src/events/SDL_touch.c
author Sam Lantinga
Sat, 06 Oct 2012 12:16:32 -0700
changeset 6566 dd7e57847ea9
parent 6299 3809b2eee787
child 6810 b5609445aa4c
permissions -rw-r--r--
Add flags to the vidmode debug output
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* General touch handling code for SDL */
    24 
    25 #include "SDL_events.h"
    26 #include "SDL_events_c.h"
    27 #include "../video/SDL_sysvideo.h"
    28 
    29 #include <stdio.h>
    30 
    31 
    32 static int SDL_num_touch = 0;
    33 static SDL_Touch **SDL_touchPads = NULL;
    34 
    35 
    36 /* Public functions */
    37 int
    38 SDL_TouchInit(void)
    39 {
    40   return (0);
    41 }
    42 
    43 SDL_Touch *
    44 SDL_GetTouch(SDL_TouchID id)
    45 {
    46     int index = SDL_GetTouchIndexId(id);
    47     if (index < 0 || index >= SDL_num_touch) {
    48         return NULL;
    49     }
    50     return SDL_touchPads[index];
    51 }
    52 
    53 SDL_Touch *
    54 SDL_GetTouchIndex(int index)
    55 {
    56     if (index < 0 || index >= SDL_num_touch) {
    57         return NULL;
    58     }
    59     return SDL_touchPads[index];
    60 }
    61 
    62 static int
    63 SDL_GetFingerIndexId(SDL_Touch* touch,SDL_FingerID fingerid)
    64 {
    65     int i;
    66     for(i = 0;i < touch->num_fingers;i++)
    67         if(touch->fingers[i]->id == fingerid)
    68             return i;
    69     return -1;
    70 }
    71 
    72 
    73 SDL_Finger *
    74 SDL_GetFinger(SDL_Touch* touch,SDL_FingerID id)
    75 {
    76     int index = SDL_GetFingerIndexId(touch,id);
    77     if(index < 0 || index >= touch->num_fingers)
    78         return NULL;
    79     return touch->fingers[index];
    80 }
    81 
    82 
    83 int
    84 SDL_GetTouchIndexId(SDL_TouchID id)
    85 {
    86     int index;
    87     SDL_Touch *touch;
    88 
    89     for (index = 0; index < SDL_num_touch; ++index) {
    90         touch = SDL_touchPads[index];
    91         if (touch->id == id) {
    92             return index;
    93         }
    94     }
    95     return -1;
    96 }
    97 
    98 int
    99 SDL_AddTouch(const SDL_Touch * touch, char *name)
   100 {
   101     SDL_Touch **touchPads;
   102     int index;
   103     size_t length;
   104 
   105     if (SDL_GetTouchIndexId(touch->id) != -1) {
   106         SDL_SetError("Touch ID already in use");
   107     }
   108 
   109     /* Add the touch to the list of touch */
   110     touchPads = (SDL_Touch **) SDL_realloc(SDL_touchPads,
   111                                       (SDL_num_touch + 1) * sizeof(*touch));
   112     if (!touchPads) {
   113         SDL_OutOfMemory();
   114         return -1;
   115     }
   116 
   117     SDL_touchPads = touchPads;
   118     index = SDL_num_touch++;
   119 
   120     SDL_touchPads[index] = (SDL_Touch *) SDL_malloc(sizeof(*SDL_touchPads[index]));
   121     if (!SDL_touchPads[index]) {
   122         SDL_OutOfMemory();
   123         return -1;
   124     }
   125     SDL_memcpy(SDL_touchPads[index], touch, sizeof(*touch));
   126 
   127     /* we're setting the touch properties */
   128     length = 0;
   129     length = SDL_strlen(name);
   130     SDL_touchPads[index]->focus = 0;
   131     SDL_touchPads[index]->name = SDL_malloc((length + 2) * sizeof(char));
   132     SDL_strlcpy(SDL_touchPads[index]->name, name, length + 1);   
   133 
   134     SDL_touchPads[index]->num_fingers = 0;
   135     SDL_touchPads[index]->max_fingers = 1;
   136     SDL_touchPads[index]->fingers = (SDL_Finger **) SDL_malloc(sizeof(SDL_Finger*));
   137     SDL_touchPads[index]->fingers[0] = NULL;
   138     SDL_touchPads[index]->buttonstate = 0;
   139     SDL_touchPads[index]->relative_mode = SDL_FALSE;
   140     SDL_touchPads[index]->flush_motion = SDL_FALSE;
   141     
   142     SDL_touchPads[index]->xres = (1<<(16-1));
   143     SDL_touchPads[index]->yres = (1<<(16-1));
   144     SDL_touchPads[index]->pressureres = (1<<(16-1));
   145     //Do I want this here? Probably
   146     SDL_GestureAddTouch(SDL_touchPads[index]);
   147 
   148     return index;
   149 }
   150 
   151 void
   152 SDL_DelTouch(SDL_TouchID id)
   153 {
   154     int index = SDL_GetTouchIndexId(id);
   155     SDL_Touch *touch = SDL_GetTouch(id);
   156 
   157     if (!touch) {
   158         return;
   159     }
   160 
   161     
   162     SDL_free(touch->name);
   163  
   164     if (touch->FreeTouch) {
   165         touch->FreeTouch(touch);
   166     }
   167     SDL_free(touch);
   168 
   169     SDL_num_touch--;
   170     SDL_touchPads[index] = SDL_touchPads[SDL_num_touch];
   171 }
   172 
   173 void
   174 SDL_TouchQuit(void)
   175 {
   176     int i;
   177 
   178     for (i = SDL_num_touch-1; i > 0 ; --i) {
   179         SDL_DelTouch(i);
   180     }
   181     SDL_num_touch = 0;
   182 
   183     if (SDL_touchPads) {
   184         SDL_free(SDL_touchPads);
   185         SDL_touchPads = NULL;
   186     }
   187 }
   188 
   189 int
   190 SDL_GetNumTouch(void)
   191 {
   192     return SDL_num_touch;
   193 }
   194 
   195 SDL_Window *
   196 SDL_GetTouchFocusWindow(SDL_TouchID id)
   197 {
   198     SDL_Touch *touch = SDL_GetTouch(id);
   199 
   200     if (!touch) {
   201         return 0;
   202     }
   203     return touch->focus;
   204 }
   205 
   206 void
   207 SDL_SetTouchFocus(SDL_TouchID id, SDL_Window * window)
   208 {
   209     int index = SDL_GetTouchIndexId(id);
   210     SDL_Touch *touch = SDL_GetTouch(id);
   211     int i;
   212     SDL_bool focus;
   213 
   214     if (!touch || (touch->focus == window)) {
   215         return;
   216     }
   217 
   218     /* See if the current window has lost focus */
   219     if (touch->focus) {
   220         focus = SDL_FALSE;
   221         for (i = 0; i < SDL_num_touch; ++i) {
   222             SDL_Touch *check;
   223             if (i != index) {
   224                 check = SDL_touchPads[i];
   225                 if (check && check->focus == touch->focus) {
   226                     focus = SDL_TRUE;
   227                     break;
   228                 }
   229             }
   230         }
   231         if (!focus) {
   232             SDL_SendWindowEvent(touch->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
   233         }
   234     }
   235 
   236     touch->focus = window;
   237 
   238     if (touch->focus) {
   239         focus = SDL_FALSE;
   240         for (i = 0; i < SDL_num_touch; ++i) {
   241             SDL_Touch *check;
   242             if (i != index) {
   243                 check = SDL_touchPads[i];
   244                 if (check && check->focus == touch->focus) {
   245                     focus = SDL_TRUE;
   246                     break;
   247                 }
   248             }
   249         }
   250         if (!focus) {
   251             SDL_SendWindowEvent(touch->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
   252         }
   253     }
   254 }
   255 
   256 int 
   257 SDL_AddFinger(SDL_Touch* touch,SDL_Finger *finger)
   258 {
   259     int index;
   260     SDL_Finger **fingers;
   261     //printf("Adding Finger...\n");
   262     if (SDL_GetFingerIndexId(touch,finger->id) != -1) {
   263         SDL_SetError("Finger ID already in use");
   264         }
   265 
   266     /* Add the touch to the list of touch */
   267     if(touch->num_fingers  >= touch->max_fingers){
   268                 //printf("Making room for it!\n");
   269                 fingers = (SDL_Finger **) SDL_realloc(touch->fingers,
   270                                                      (touch->num_fingers + 1) * sizeof(SDL_Finger *));
   271                 touch->max_fingers = touch->num_fingers+1;
   272                 if (!fingers) {
   273                         SDL_OutOfMemory();
   274                         return -1;
   275                 } else {
   276                         touch->max_fingers = touch->num_fingers+1;
   277                         touch->fingers = fingers;
   278                 }
   279         }
   280 
   281     index = touch->num_fingers;
   282     //printf("Max_Fingers: %i Index: %i\n",touch->max_fingers,index);
   283 
   284     touch->fingers[index] = (SDL_Finger *) SDL_malloc(sizeof(SDL_Finger));
   285     if (!touch->fingers[index]) {
   286         SDL_OutOfMemory();
   287         return -1;
   288     }
   289     *(touch->fingers[index]) = *finger;
   290     touch->num_fingers++;
   291 
   292     return index;
   293 }
   294 
   295 int
   296 SDL_DelFinger(SDL_Touch* touch,SDL_FingerID fingerid)
   297 {
   298     int index = SDL_GetFingerIndexId(touch,fingerid);
   299     SDL_Finger* finger = SDL_GetFinger(touch,fingerid);
   300 
   301     if (!finger) {
   302         return -1;
   303     }
   304  
   305 
   306     SDL_free(finger);
   307     touch->num_fingers--;
   308     touch->fingers[index] = touch->fingers[touch->num_fingers];
   309     return 0;
   310 }
   311 
   312 
   313 int
   314 SDL_SendFingerDown(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, 
   315                    float xin, float yin, float pressurein)
   316 {
   317     int posted;
   318         Uint16 x;
   319         Uint16 y;
   320         Uint16 pressure;
   321         SDL_Finger *finger;
   322 
   323     SDL_Touch* touch = SDL_GetTouch(id);
   324 
   325     if(!touch) {
   326       return SDL_TouchNotFoundError(id);
   327     }
   328 
   329     
   330     //scale to Integer coordinates
   331     x = (Uint16)((xin+touch->x_min)*(touch->xres)/(touch->native_xres));
   332     y = (Uint16)((yin+touch->y_min)*(touch->yres)/(touch->native_yres));
   333     pressure = (Uint16)((pressurein+touch->pressure_min)*(touch->pressureres)/(touch->native_pressureres));
   334     
   335     finger = SDL_GetFinger(touch,fingerid);
   336     if(down) {
   337         if(finger == NULL) {
   338             SDL_Finger nf;
   339             nf.id = fingerid;
   340             nf.x = x;
   341             nf.y = y;
   342             nf.pressure = pressure;
   343             nf.xdelta = 0;
   344             nf.ydelta = 0;
   345             nf.last_x = x;
   346             nf.last_y = y;
   347             nf.last_pressure = pressure;
   348             nf.down = SDL_FALSE;
   349             if(SDL_AddFinger(touch,&nf) < 0) return 0;
   350             finger = SDL_GetFinger(touch,fingerid);
   351         }
   352         else if(finger->down) return 0;
   353         if(xin < touch->x_min || yin < touch->y_min) return 0; //should defer if only a partial input
   354         posted = 0;
   355         if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
   356             SDL_Event event;
   357             event.tfinger.type = SDL_FINGERDOWN;
   358             event.tfinger.touchId = id;
   359             event.tfinger.x = x;
   360             event.tfinger.y = y;
   361             event.tfinger.dx = 0;
   362             event.tfinger.dy = 0;
   363             event.tfinger.pressure = pressure;
   364             event.tfinger.state = touch->buttonstate;
   365             event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
   366             event.tfinger.fingerId = fingerid;
   367             posted = (SDL_PushEvent(&event) > 0);
   368         }
   369         if(posted) finger->down = SDL_TRUE;
   370         return posted;
   371     }
   372     else {
   373         if(finger == NULL) {
   374             SDL_SetError("Finger not found.");
   375             return 0;
   376         }      
   377         posted = 0;
   378         if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
   379             SDL_Event event;
   380             event.tfinger.type = SDL_FINGERUP;
   381             event.tfinger.touchId =  id;
   382             event.tfinger.state = touch->buttonstate;
   383             event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
   384             event.tfinger.fingerId = fingerid;
   385             //I don't trust the coordinates passed on fingerUp
   386             event.tfinger.x = finger->x; 
   387             event.tfinger.y = finger->y;
   388             event.tfinger.dx = 0;
   389             event.tfinger.dy = 0;
   390             event.tfinger.pressure = pressure;
   391 
   392             if(SDL_DelFinger(touch,fingerid) < 0) return 0;
   393             posted = (SDL_PushEvent(&event) > 0);
   394         }        
   395         return posted;
   396     }
   397 }
   398 
   399 int
   400 SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, int relative, 
   401                     float xin, float yin, float pressurein)
   402 {
   403     SDL_Touch *touch;
   404     SDL_Finger *finger;
   405     int posted;
   406     Sint16 xrel, yrel;
   407     Uint16 x;
   408     Uint16 y;
   409     Uint16 pressure;
   410     
   411     touch = SDL_GetTouch(id);
   412     if (!touch) {
   413       return SDL_TouchNotFoundError(id);
   414     }
   415 
   416     //scale to Integer coordinates
   417     x = (Uint16)((xin+touch->x_min)*(touch->xres)/(touch->native_xres));
   418     y = (Uint16)((yin+touch->y_min)*(touch->yres)/(touch->native_yres));
   419     pressure = (Uint16)((pressurein+touch->pressure_min)*(touch->pressureres)/(touch->native_pressureres));
   420     if(touch->flush_motion) {
   421         return 0;
   422     }
   423     
   424     finger = SDL_GetFinger(touch,fingerid);
   425     if(finger == NULL || !finger->down) {
   426         return SDL_SendFingerDown(id,fingerid,SDL_TRUE,xin,yin,pressurein);        
   427     } else {
   428         /* the relative motion is calculated regarding the last position */
   429         if (relative) {
   430             xrel = x;
   431             yrel = y;
   432             x = (finger->last_x + x);
   433             y = (finger->last_y + y);
   434         } else {
   435             if(xin < touch->x_min) x = finger->last_x; /*If movement is only in one axis,*/
   436             if(yin < touch->y_min) y = finger->last_y; /*The other is marked as -1*/
   437             if(pressurein < touch->pressure_min) pressure = finger->last_pressure;
   438             xrel = x - finger->last_x;
   439             yrel = y - finger->last_y;
   440             //printf("xrel,yrel (%i,%i)\n",(int)xrel,(int)yrel);
   441         }
   442         
   443         /* Drop events that don't change state */
   444         if (!xrel && !yrel) {
   445 #if 0
   446             printf("Touch event didn't change state - dropped!\n");
   447 #endif
   448             return 0;
   449         }
   450         
   451         /* Update internal touch coordinates */
   452         
   453         finger->x = x;
   454         finger->y = y;
   455         
   456         /*Should scale to window? Normalize? Maintain Aspect?*/
   457         //SDL_GetWindowSize(touch->focus, &x_max, &y_max);
   458         
   459         /* make sure that the pointers find themselves inside the windows */
   460         /* only check if touch->xmax is set ! */
   461         /*
   462           if (x_max && touch->x > x_max) {
   463           touch->x = x_max;
   464           } else if (touch->x < 0) {
   465           touch->x = 0;
   466           }
   467           
   468           if (y_max && touch->y > y_max) {
   469           touch->y = y_max;
   470           } else if (touch->y < 0) {
   471           touch->y = 0;
   472           }
   473         */
   474         finger->xdelta = xrel;
   475         finger->ydelta = yrel;
   476         finger->pressure = pressure;
   477         
   478         
   479         
   480         /* Post the event, if desired */
   481         posted = 0;
   482         if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
   483             SDL_Event event;
   484             event.tfinger.type = SDL_FINGERMOTION;
   485             event.tfinger.touchId = id;
   486             event.tfinger.fingerId = fingerid;
   487             event.tfinger.x = x;
   488             event.tfinger.y = y;
   489             event.tfinger.dx = xrel;
   490             event.tfinger.dy = yrel;            
   491                 
   492             event.tfinger.pressure = pressure;
   493             event.tfinger.state = touch->buttonstate;
   494             event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
   495             posted = (SDL_PushEvent(&event) > 0);
   496         }
   497         finger->last_x = finger->x;
   498         finger->last_y = finger->y;
   499         finger->last_pressure = finger->pressure;
   500         return posted;
   501     }
   502 }
   503 
   504 int
   505 SDL_SendTouchButton(SDL_TouchID id, Uint8 state, Uint8 button)
   506 {
   507     SDL_Touch *touch;
   508     int posted;
   509     Uint32 type;
   510 
   511     
   512     touch = SDL_GetTouch(id);
   513     if (!touch) {
   514       return SDL_TouchNotFoundError(id);
   515     }
   516 
   517     /* Figure out which event to perform */
   518     switch (state) {
   519     case SDL_PRESSED:
   520         if (touch->buttonstate & SDL_BUTTON(button)) {
   521             /* Ignore this event, no state change */
   522             return 0;
   523         }
   524         type = SDL_TOUCHBUTTONDOWN;
   525         touch->buttonstate |= SDL_BUTTON(button);
   526         break;
   527     case SDL_RELEASED:
   528         if (!(touch->buttonstate & SDL_BUTTON(button))) {
   529             /* Ignore this event, no state change */
   530             return 0;
   531         }
   532         type = SDL_TOUCHBUTTONUP;
   533         touch->buttonstate &= ~SDL_BUTTON(button);
   534         break;
   535     default:
   536         /* Invalid state -- bail */
   537         return 0;
   538     }
   539 
   540     /* Post the event, if desired */
   541     posted = 0;
   542     if (SDL_GetEventState(type) == SDL_ENABLE) {
   543         SDL_Event event;
   544         event.type = type;
   545         event.tbutton.touchId = touch->id;
   546         event.tbutton.state = state;
   547         event.tbutton.button = button;
   548         event.tbutton.windowID = touch->focus ? touch->focus->id : 0;
   549         posted = (SDL_PushEvent(&event) > 0);
   550     }
   551     return posted;
   552 }
   553 
   554 char *
   555 SDL_GetTouchName(SDL_TouchID id)
   556 {
   557     SDL_Touch *touch = SDL_GetTouch(id);
   558     if (!touch) {
   559         return NULL;
   560     }
   561     return touch->name;
   562 }
   563 
   564 int SDL_TouchNotFoundError(SDL_TouchID id) {
   565   //int i;
   566   SDL_SetError("ERROR: Cannot send touch on non-existent device with id: %li make sure SDL_AddTouch has been called\n",id);
   567 #if 0
   568   printf("ERROR: There are %i touches installed with Id's:\n",SDL_num_touch);
   569   for(i=0;i < SDL_num_touch;i++) {
   570     printf("ERROR: %li\n",SDL_touchPads[i]->id);
   571   }
   572 #endif
   573   return 0;
   574 }
   575 /* vi: set ts=4 sw=4 expandtab: */