src/events/SDL_touch.c
author Jim Grandpre <jim.tla@gmail.com>
Mon, 31 May 2010 00:24:37 -0400
changeset 4645 0375d020e7e3
parent 4644 fb500b3e1717
child 4646 eea1bf53effa
permissions -rw-r--r--
Auto-detects Wacom touch devices.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* General touch handling code for SDL */
    25 
    26 #include "SDL_events.h"
    27 #include "SDL_events_c.h"
    28 #include "../video/SDL_sysvideo.h"
    29 
    30 
    31 static int SDL_num_touch = 0;
    32 static SDL_Touch **SDL_touchPads = NULL;
    33 
    34 
    35 /* Public functions */
    36 int
    37 SDL_TouchInit(void)
    38 {
    39     
    40     return (0);
    41 }
    42 
    43 SDL_Touch *
    44 SDL_GetTouch(int 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 int
    63 SDL_GetFingerIndexId(SDL_Touch* touch,int 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,int 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(int 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 selected_touch;
   103     int index;
   104     size_t length;
   105 
   106     if (SDL_GetTouchIndexId(touch->id) != -1) {
   107         SDL_SetError("Touch ID already in use");
   108     }
   109 
   110     /* Add the touch to the list of touch */
   111     touchPads = (SDL_Touch **) SDL_realloc(SDL_touchPads,
   112                                       (SDL_num_touch + 1) * sizeof(*touch));
   113     if (!touchPads) {
   114         SDL_OutOfMemory();
   115         return -1;
   116     }
   117 
   118     SDL_touchPads = touchPads;
   119     index = SDL_num_touch++;
   120 
   121     SDL_touchPads[index] = (SDL_Touch *) SDL_malloc(sizeof(*SDL_touchPads[index]));
   122     if (!SDL_touchPads[index]) {
   123         SDL_OutOfMemory();
   124         return -1;
   125     }
   126     *SDL_touchPads[index] = *touch;
   127 
   128     /* we're setting the touch properties */
   129     length = 0;
   130     length = SDL_strlen(name);
   131     SDL_touchPads[index]->focus = 0;
   132     SDL_touchPads[index]->name = SDL_malloc((length + 2) * sizeof(char));
   133     SDL_strlcpy(SDL_touchPads[index]->name, name, length + 1);   
   134 
   135     SDL_touchPads[index]->num_fingers = 0;
   136     SDL_touchPads[index]->max_fingers = 0;
   137     SDL_touchPads[index]->fingers = NULL;
   138     
   139     SDL_touchPads[index]->buttonstate = 0;
   140     SDL_touchPads[index]->relative_mode = SDL_FALSE;
   141     SDL_touchPads[index]->flush_motion = SDL_FALSE;
   142     
   143     return index;
   144 }
   145 
   146 void
   147 SDL_DelTouch(int id)
   148 {
   149     int index = SDL_GetTouchIndexId(id);
   150     SDL_Touch *touch = SDL_GetTouch(id);
   151 
   152     if (!touch) {
   153         return;
   154     }
   155 
   156     
   157     SDL_free(touch->name);
   158  
   159     if (touch->FreeTouch) {
   160         touch->FreeTouch(touch);
   161     }
   162     SDL_free(touch);
   163 
   164     SDL_num_touch--;
   165     SDL_touchPads[index] = SDL_touchPads[SDL_num_touch];
   166 }
   167 
   168 void
   169 SDL_TouchQuit(void)
   170 {
   171     int i;
   172 
   173     for (i = SDL_num_touch-1; i > 0 ; --i) {
   174         SDL_DelTouch(i);
   175     }
   176     SDL_num_touch = 0;
   177 
   178     if (SDL_touchPads) {
   179         SDL_free(SDL_touchPads);
   180         SDL_touchPads = NULL;
   181     }
   182 }
   183 
   184 int
   185 SDL_GetNumTouch(void)
   186 {
   187     return SDL_num_touch;
   188 }
   189 SDL_Window *
   190 SDL_GetTouchFocusWindow(int id)
   191 {
   192     SDL_Touch *touch = SDL_GetTouch(id);
   193 
   194     if (!touch) {
   195         return 0;
   196     }
   197     return touch->focus;
   198 }
   199 
   200 void
   201 SDL_SetTouchFocus(int id, SDL_Window * window)
   202 {
   203     int index = SDL_GetTouchIndexId(id);
   204     SDL_Touch *touch = SDL_GetTouch(id);
   205     int i;
   206     SDL_bool focus;
   207 
   208     if (!touch || (touch->focus == window)) {
   209         return;
   210     }
   211 
   212     /* See if the current window has lost focus */
   213     if (touch->focus) {
   214         focus = SDL_FALSE;
   215         for (i = 0; i < SDL_num_touch; ++i) {
   216             SDL_Touch *check;
   217             if (i != index) {
   218                 check = SDL_touchPads[i];
   219                 if (check && check->focus == touch->focus) {
   220                     focus = SDL_TRUE;
   221                     break;
   222                 }
   223             }
   224         }
   225         if (!focus) {
   226             SDL_SendWindowEvent(touch->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
   227         }
   228     }
   229 
   230     touch->focus = window;
   231 
   232     if (touch->focus) {
   233         focus = SDL_FALSE;
   234         for (i = 0; i < SDL_num_touch; ++i) {
   235             SDL_Touch *check;
   236             if (i != index) {
   237                 check = SDL_touchPads[i];
   238                 if (check && check->focus == touch->focus) {
   239                     focus = SDL_TRUE;
   240                     break;
   241                 }
   242             }
   243         }
   244         if (!focus) {
   245             SDL_SendWindowEvent(touch->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
   246         }
   247     }
   248 }
   249 
   250 int 
   251 SDL_AddFinger(SDL_Touch* touch,SDL_Finger* finger)
   252 {
   253     int index;
   254     SDL_Finger **fingers;
   255     size_t length;
   256     
   257     if (SDL_GetFingerIndexId(touch,finger->id) != -1) {
   258         SDL_SetError("Finger ID already in use");
   259 	}
   260 
   261     /* Add the touch to the list of touch */
   262     if(touch->num_fingers >= touch->max_fingers){
   263       if(fingers == NULL) {
   264 	touch->max_fingers = 1;
   265 	fingers = (SDL_Finger **) SDL_malloc(sizeof(finger));
   266       }
   267       else {
   268 	fingers = (SDL_Finger **) SDL_realloc(touch->fingers,
   269 				     (touch->num_fingers + 1) * sizeof(finger));
   270 	touch->max_fingers = touch->num_fingers+1;
   271       }
   272 
   273     }
   274 
   275     if (!fingers) {
   276         SDL_OutOfMemory();
   277         return -1;
   278     }
   279 
   280     touch->fingers = fingers;
   281     index = touch->num_fingers;
   282     touch->num_fingers++;
   283     touch->fingers[index] = (SDL_Finger *) SDL_malloc(sizeof(*(touch->fingers[index])));
   284     if (!touch->fingers[index]) {
   285         SDL_OutOfMemory();
   286         return -1;
   287     }
   288     *touch->fingers[index] = *finger;    
   289 
   290     return index;
   291 }
   292 
   293 int
   294 SDL_DelFinger(SDL_Touch* touch,int fingerid)
   295 {
   296     int index = SDL_GetFingerIndexId(touch,fingerid);
   297     SDL_Finger* finger = SDL_GetFinger(touch,fingerid);
   298 
   299     if (!finger) {
   300         return;
   301     }
   302  
   303 
   304     SDL_free(finger);
   305     touch->num_fingers--;
   306     touch->fingers[index] = touch->fingers[touch->num_fingers];
   307 }
   308 
   309 
   310 int
   311 SDL_SendFingerDown(int id, int fingerid, SDL_bool down, int x, int y, int pressure)
   312 {
   313     int posted;
   314     SDL_Touch* touch = SDL_GetTouch(id);
   315 
   316     if(down) {
   317 	SDL_Finger nf;
   318 	nf.id = fingerid;
   319 	nf.x = x;
   320 	nf.y = y;
   321 	nf.pressure = pressure;
   322 	nf.xdelta = 0;
   323 	nf.ydelta = 0;
   324 	nf.last_x = x;
   325 	nf.last_y = y;
   326 	SDL_AddFinger(touch,&nf);
   327 
   328 	posted = 0;
   329 	if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
   330 	    SDL_Event event;
   331 	    event.tfinger.type = SDL_FINGERDOWN;
   332 	    event.tfinger.touchId = (Uint8) id;
   333 	    event.tfinger.x = x;
   334 	    event.tfinger.y = y;
   335 	    event.tfinger.state = touch->buttonstate;
   336 	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
   337 	    event.tfinger.fingerId = fingerid;
   338 	    posted = (SDL_PushEvent(&event) > 0);
   339 	}
   340 	return posted;
   341     }
   342     else {
   343 	SDL_DelFinger(touch,fingerid);
   344 	posted = 0;
   345 	if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
   346 	    SDL_Event event;
   347 	    event.tfinger.type = SDL_FINGERUP;
   348 	    event.tfinger.touchId = (Uint8) id;
   349 	    event.tfinger.state = touch->buttonstate;
   350 	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
   351 	    event.tfinger.fingerId = fingerid;
   352 	    posted = (SDL_PushEvent(&event) > 0);
   353 	}
   354 	return posted;
   355     }
   356 }
   357 
   358 int
   359 SDL_SendTouchMotion(int id, int fingerid, int relative, 
   360 		    int x, int y, int pressure)
   361 {
   362     int index = SDL_GetTouchIndexId(id);
   363     SDL_Touch *touch = SDL_GetTouch(id);
   364     SDL_Finger *finger = SDL_GetFinger(touch,fingerid);
   365     int posted;
   366     int xrel;
   367     int yrel;
   368     int x_max = 0, y_max = 0;
   369 
   370     if (!touch || touch->flush_motion) {
   371         return 0;
   372     }
   373 
   374     if(finger == NULL)
   375 	SDL_SendFingerDown(id,fingerid,SDL_TRUE,x,y,pressure);
   376     else {
   377 	/* the relative motion is calculated regarding the last position */
   378 	if (relative) {
   379 	    xrel = x;
   380 	    yrel = y;
   381 	    x = (finger->last_x + x);
   382 	    y = (finger->last_y + y);
   383 	} else {
   384 	    if(x < 0) x = finger->last_x; /*If movement is only in one axis,*/
   385 	    if(y < 0) y = finger->last_y; /*The other is marked as -1*/
   386 	    xrel = x - finger->last_x;
   387 	    yrel = y - finger->last_y;
   388 	}
   389 	
   390 	/* Drop events that don't change state */
   391 	if (!xrel && !yrel) {
   392 #if 0
   393 	    printf("Touch event didn't change state - dropped!\n");
   394 #endif
   395 	    return 0;
   396 	}
   397 	
   398 	/* Update internal touch coordinates */
   399 	
   400 	finger->x = x;
   401 	finger->y = y;
   402 	
   403 	/*Should scale to window? Normalize? Maintain Aspect?*/
   404 	//SDL_GetWindowSize(touch->focus, &x_max, &y_max);
   405 	
   406 	/* make sure that the pointers find themselves inside the windows */
   407 	/* only check if touch->xmax is set ! */
   408 	/*
   409 	  if (x_max && touch->x > x_max) {
   410 	  touch->x = x_max;
   411 	  } else if (touch->x < 0) {
   412 	  touch->x = 0;
   413 	  }
   414 	  
   415 	  if (y_max && touch->y > y_max) {
   416 	  touch->y = y_max;
   417 	  } else if (touch->y < 0) {
   418 	  touch->y = 0;
   419 	  }
   420 	*/
   421 	finger->xdelta += xrel;
   422 	finger->ydelta += yrel;
   423 	finger->pressure = pressure;
   424 	
   425 	
   426 	
   427 	/* Post the event, if desired */
   428 	posted = 0;
   429 	if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
   430 	    SDL_Event event;
   431 	    event.tfinger.type = SDL_FINGERMOTION;
   432 	    event.tfinger.touchId = (Uint8) id;
   433 	    event.tfinger.fingerId = (Uint8) fingerid;
   434 	    event.tfinger.x = x;
   435 	    event.tfinger.y = y;
   436 	    event.tfinger.pressure = pressure;
   437 	    event.tfinger.state = touch->buttonstate;
   438 	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
   439 	    posted = (SDL_PushEvent(&event) > 0);
   440 	}
   441 	finger->last_x = finger->x;
   442 	finger->last_y = finger->y;
   443 	return posted;
   444     }
   445 }
   446 int
   447 SDL_SendTouchButton(int id, Uint8 state, Uint8 button)
   448 {
   449     SDL_Touch *touch = SDL_GetTouch(id);
   450     int posted;
   451     Uint32 type;
   452 
   453     if (!touch) {
   454         return 0;
   455     }
   456 
   457     /* Figure out which event to perform */
   458     switch (state) {
   459     case SDL_PRESSED:
   460         if (touch->buttonstate & SDL_BUTTON(button)) {
   461             /* Ignore this event, no state change */
   462             return 0;
   463         }
   464         type = SDL_TOUCHBUTTONDOWN;
   465         touch->buttonstate |= SDL_BUTTON(button);
   466         break;
   467     case SDL_RELEASED:
   468         if (!(touch->buttonstate & SDL_BUTTON(button))) {
   469             /* Ignore this event, no state change */
   470             return 0;
   471         }
   472         type = SDL_TOUCHBUTTONUP;
   473         touch->buttonstate &= ~SDL_BUTTON(button);
   474         break;
   475     default:
   476         /* Invalid state -- bail */
   477         return 0;
   478     }
   479 
   480     /* Post the event, if desired */
   481     posted = 0;
   482     if (SDL_GetEventState(type) == SDL_ENABLE) {
   483         SDL_Event event;
   484         event.type = type;
   485         event.tbutton.touchId = (Uint8) index;
   486         event.tbutton.state = state;
   487         event.tbutton.button = button;
   488         event.tbutton.windowID = touch->focus ? touch->focus->id : 0;
   489         posted = (SDL_PushEvent(&event) > 0);
   490     }
   491     return posted;
   492 }
   493 
   494 char *
   495 SDL_GetTouchName(int id)
   496 {
   497     SDL_Touch *touch = SDL_GetTouch(id);
   498     if (!touch) {
   499         return NULL;
   500     }
   501     return touch->name;
   502 }
   503 
   504 /* vi: set ts=4 sw=4 expandtab: */