src/events/SDL_touch.c
author jimtla
Fri, 30 Jul 2010 23:18:35 +0400
changeset 4676 99b4560b7aa1
parent 4674 89d5e2201b00
child 4678 f8431f66613d
permissions -rw-r--r--
Upgraded touchId/fingerId to long. Changed position variables to floats.
     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 #include <stdio.h>
    31 
    32 
    33 static int SDL_num_touch = 0;
    34 static SDL_Touch **SDL_touchPads = NULL;
    35 
    36 
    37 /* Public functions */
    38 int
    39 SDL_TouchInit(void)
    40 {
    41   return (0);
    42 }
    43 
    44 SDL_Touch *
    45 SDL_GetTouch(long id)
    46 {
    47     int index = SDL_GetTouchIndexId(id);
    48     if (index < 0 || index >= SDL_num_touch) {
    49         return NULL;
    50     }
    51     return SDL_touchPads[index];
    52 }
    53 
    54 SDL_Touch *
    55 SDL_GetTouchIndex(int index)
    56 {
    57     if (index < 0 || index >= SDL_num_touch) {
    58         return NULL;
    59     }
    60     return SDL_touchPads[index];
    61 }
    62 
    63 int
    64 SDL_GetFingerIndexId(SDL_Touch* touch,long fingerid)
    65 {
    66     int i;
    67     for(i = 0;i < touch->num_fingers;i++)
    68 	if(touch->fingers[i]->id == fingerid)
    69 	    return i;
    70     return -1;
    71 }
    72 
    73 
    74 SDL_Finger *
    75 SDL_GetFinger(SDL_Touch* touch,long id)
    76 {
    77     int index = SDL_GetFingerIndexId(touch,id);
    78     if(index < 0 || index >= touch->num_fingers)
    79 	return NULL;
    80     return touch->fingers[index];
    81 }
    82 
    83 
    84 int
    85 SDL_GetTouchIndexId(long id)
    86 {
    87     int index;
    88     SDL_Touch *touch;
    89 
    90     for (index = 0; index < SDL_num_touch; ++index) {
    91         touch = SDL_touchPads[index];
    92         if (touch->id == id) {
    93             return index;
    94         }
    95     }
    96     return -1;
    97 }
    98 
    99 int
   100 SDL_AddTouch(const SDL_Touch * touch, char *name)
   101 {
   102     SDL_Touch **touchPads;
   103     int index,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_touchPads[index] = *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     //Do I want this here? Probably
   143     SDL_GestureAddTouch(SDL_touchPads[index]);
   144 
   145     return index;
   146 }
   147 
   148 void
   149 SDL_DelTouch(long id)
   150 {
   151     int index = SDL_GetTouchIndexId(id);
   152     SDL_Touch *touch = SDL_GetTouch(id);
   153 
   154     if (!touch) {
   155         return;
   156     }
   157 
   158     
   159     SDL_free(touch->name);
   160  
   161     if (touch->FreeTouch) {
   162         touch->FreeTouch(touch);
   163     }
   164     SDL_free(touch);
   165 
   166     SDL_num_touch--;
   167     SDL_touchPads[index] = SDL_touchPads[SDL_num_touch];
   168 }
   169 
   170 void
   171 SDL_TouchQuit(void)
   172 {
   173     int i;
   174 
   175     for (i = SDL_num_touch-1; i > 0 ; --i) {
   176         SDL_DelTouch(i);
   177     }
   178     SDL_num_touch = 0;
   179 
   180     if (SDL_touchPads) {
   181         SDL_free(SDL_touchPads);
   182         SDL_touchPads = NULL;
   183     }
   184 }
   185 
   186 int
   187 SDL_GetNumTouch(void)
   188 {
   189     return SDL_num_touch;
   190 }
   191 SDL_Window *
   192 SDL_GetTouchFocusWindow(long id)
   193 {
   194     SDL_Touch *touch = SDL_GetTouch(id);
   195 
   196     if (!touch) {
   197         return 0;
   198     }
   199     return touch->focus;
   200 }
   201 
   202 void
   203 SDL_SetTouchFocus(long id, SDL_Window * window)
   204 {
   205     int index = SDL_GetTouchIndexId(id);
   206     SDL_Touch *touch = SDL_GetTouch(id);
   207     int i;
   208     SDL_bool focus;
   209 
   210     if (!touch || (touch->focus == window)) {
   211         return;
   212     }
   213 
   214     /* See if the current window has lost focus */
   215     if (touch->focus) {
   216         focus = SDL_FALSE;
   217         for (i = 0; i < SDL_num_touch; ++i) {
   218             SDL_Touch *check;
   219             if (i != index) {
   220                 check = SDL_touchPads[i];
   221                 if (check && check->focus == touch->focus) {
   222                     focus = SDL_TRUE;
   223                     break;
   224                 }
   225             }
   226         }
   227         if (!focus) {
   228             SDL_SendWindowEvent(touch->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
   229         }
   230     }
   231 
   232     touch->focus = window;
   233 
   234     if (touch->focus) {
   235         focus = SDL_FALSE;
   236         for (i = 0; i < SDL_num_touch; ++i) {
   237             SDL_Touch *check;
   238             if (i != index) {
   239                 check = SDL_touchPads[i];
   240                 if (check && check->focus == touch->focus) {
   241                     focus = SDL_TRUE;
   242                     break;
   243                 }
   244             }
   245         }
   246         if (!focus) {
   247             SDL_SendWindowEvent(touch->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
   248         }
   249     }
   250 }
   251 
   252 int 
   253 SDL_AddFinger(SDL_Touch* touch,SDL_Finger finger)
   254 {
   255     int index;
   256     SDL_Finger **fingers;
   257     //printf("Adding Finger...\n");
   258     if (SDL_GetFingerIndexId(touch,finger.id) != -1) {
   259         SDL_SetError("Finger ID already in use");
   260 	}
   261 
   262     /* Add the touch to the list of touch */
   263     if(touch->num_fingers  >= touch->max_fingers){
   264 		//printf("Making room for it!\n");
   265 		fingers = (SDL_Finger **) SDL_realloc(touch->fingers,
   266   						   (touch->num_fingers + 1) * sizeof(SDL_Finger *));
   267 		touch->max_fingers = touch->num_fingers+1;
   268 		if (!fingers) {
   269 			SDL_OutOfMemory();
   270 			return -1;
   271 		} else {
   272 			touch->max_fingers = touch->num_fingers+1;
   273 			touch->fingers = fingers;
   274 		}
   275 	}
   276 
   277     index = touch->num_fingers;
   278     //printf("Max_Fingers: %i Index: %i\n",touch->max_fingers,index);
   279 
   280     touch->fingers[index] = (SDL_Finger *) SDL_malloc(sizeof(SDL_Finger));
   281     if (!touch->fingers[index]) {
   282         SDL_OutOfMemory();
   283         return -1;
   284     }
   285     *(touch->fingers[index]) = finger;
   286     touch->num_fingers++;
   287 
   288     return index;
   289 }
   290 
   291 int
   292 SDL_DelFinger(SDL_Touch* touch,long fingerid)
   293 {
   294     int index = SDL_GetFingerIndexId(touch,fingerid);
   295     SDL_Finger* finger = SDL_GetFinger(touch,fingerid);
   296 
   297     if (!finger) {
   298         return -1;
   299     }
   300  
   301 
   302     SDL_free(finger);
   303     touch->num_fingers--;
   304     touch->fingers[index] = touch->fingers[touch->num_fingers];
   305     return 0;
   306 }
   307 
   308 
   309 int
   310 SDL_SendFingerDown(long id, long fingerid, SDL_bool down, float x, float y, float pressure)
   311 {
   312     int posted;
   313     SDL_Touch* touch = SDL_GetTouch(id);
   314 
   315     if(!touch) {
   316       return SDL_TouchNotFoundError(id);
   317     }
   318 
   319     if(down) {
   320 	SDL_Finger *finger = SDL_GetFinger(touch,fingerid);
   321 	if(finger == NULL) {
   322 	    SDL_Finger nf;
   323 	    nf.id = fingerid;
   324 	    nf.x = x;
   325 	    nf.y = y;
   326 	    nf.pressure = pressure;
   327 	    nf.xdelta = 0;
   328 	    nf.ydelta = 0;
   329 	    nf.last_x = x;
   330 	    nf.last_y = y;
   331 	    nf.last_pressure = pressure;
   332 	    nf.down = SDL_FALSE;
   333 	    SDL_AddFinger(touch,nf);
   334 	    finger = &nf;
   335 	}
   336 	else if(finger->down) return 0;
   337 	if(x < 0 || y < 0) return 0; //should defer if only a partial input
   338 	posted = 0;
   339 	if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
   340 	    SDL_Event event;
   341 	    event.tfinger.type = SDL_FINGERDOWN;
   342 	    event.tfinger.touchId = id;
   343 	    event.tfinger.x = x;
   344 	    event.tfinger.y = y;
   345 	    event.tfinger.state = touch->buttonstate;
   346 	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
   347 	    event.tfinger.fingerId = fingerid;
   348 	    posted = (SDL_PushEvent(&event) > 0);
   349 	}
   350 	if(posted) finger->down = SDL_TRUE;
   351 	return posted;
   352     }
   353     else {
   354 	if(SDL_DelFinger(touch,fingerid) < 0) return 0;
   355 	posted = 0;
   356 	if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
   357 	    SDL_Event event;
   358 	    event.tfinger.type = SDL_FINGERUP;
   359 	    event.tfinger.touchId =  id;
   360 	    event.tfinger.state = touch->buttonstate;
   361 	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
   362 	    event.tfinger.fingerId = fingerid;
   363 	    posted = (SDL_PushEvent(&event) > 0);
   364 	}
   365 	return posted;
   366     }
   367 }
   368 
   369 int
   370 SDL_SendTouchMotion(long id, long fingerid, int relative, 
   371 		    float x, float y, float pressure)
   372 {
   373     int index = SDL_GetTouchIndexId(id);
   374     SDL_Touch *touch = SDL_GetTouch(id);
   375     SDL_Finger *finger = SDL_GetFinger(touch,fingerid);
   376     int posted;
   377     float xrel;
   378     float yrel;
   379     float x_max = 0, y_max = 0;
   380     
   381     if (!touch) {
   382       return SDL_TouchNotFoundError(id);
   383     }
   384     if(touch->flush_motion) {
   385 	return 0;
   386     }
   387     
   388     if(finger == NULL || !finger->down) {
   389 	return SDL_SendFingerDown(id,fingerid,SDL_TRUE,x,y,pressure);	
   390     } else {
   391 	/* the relative motion is calculated regarding the last position */
   392 	if (relative) {
   393 	    xrel = x;
   394 	    yrel = y;
   395 	    x = (finger->last_x + x);
   396 	    y = (finger->last_y + y);
   397 	} else {
   398 	    if(x < 0) x = finger->last_x; /*If movement is only in one axis,*/
   399 	    if(y < 0) y = finger->last_y; /*The other is marked as -1*/
   400 	    if(pressure < 0) pressure = finger->last_pressure;
   401 	    xrel = x - finger->last_x;
   402 	    yrel = y - finger->last_y;
   403 	}
   404 	
   405 	/* Drop events that don't change state */
   406 	if (!xrel && !yrel) {
   407 #if 0
   408 	    printf("Touch event didn't change state - dropped!\n");
   409 #endif
   410 	    return 0;
   411 	}
   412 	
   413 	/* Update internal touch coordinates */
   414 	
   415 	finger->x = x;
   416 	finger->y = y;
   417 	
   418 	/*Should scale to window? Normalize? Maintain Aspect?*/
   419 	//SDL_GetWindowSize(touch->focus, &x_max, &y_max);
   420 	
   421 	/* make sure that the pointers find themselves inside the windows */
   422 	/* only check if touch->xmax is set ! */
   423 	/*
   424 	  if (x_max && touch->x > x_max) {
   425 	  touch->x = x_max;
   426 	  } else if (touch->x < 0) {
   427 	  touch->x = 0;
   428 	  }
   429 	  
   430 	  if (y_max && touch->y > y_max) {
   431 	  touch->y = y_max;
   432 	  } else if (touch->y < 0) {
   433 	  touch->y = 0;
   434 	  }
   435 	*/
   436 	finger->xdelta = xrel;
   437 	finger->ydelta = yrel;
   438 	finger->pressure = pressure;
   439 	
   440 	
   441 	
   442 	/* Post the event, if desired */
   443 	posted = 0;
   444 	if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
   445 	    SDL_Event event;
   446 	    event.tfinger.type = SDL_FINGERMOTION;
   447 	    event.tfinger.touchId = id;
   448 	    event.tfinger.fingerId = fingerid;
   449 	    event.tfinger.x = x;
   450 	    event.tfinger.y = y;
   451 	    event.tfinger.pressure = pressure;
   452 	    event.tfinger.state = touch->buttonstate;
   453 	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
   454 	    posted = (SDL_PushEvent(&event) > 0);
   455 	}
   456 	finger->last_x = finger->x;
   457 	finger->last_y = finger->y;
   458 	finger->last_pressure = finger->pressure;
   459 	return posted;
   460     }
   461 }
   462 int
   463 SDL_SendTouchButton(long id, Uint8 state, Uint8 button)
   464 {
   465     SDL_Touch *touch = SDL_GetTouch(id);
   466     int posted;
   467     Uint32 type;
   468 
   469     
   470     if (!touch) {
   471       return SDL_TouchNotFoundError(id);
   472     }
   473 
   474     /* Figure out which event to perform */
   475     switch (state) {
   476     case SDL_PRESSED:
   477         if (touch->buttonstate & SDL_BUTTON(button)) {
   478             /* Ignore this event, no state change */
   479             return 0;
   480         }
   481         type = SDL_TOUCHBUTTONDOWN;
   482         touch->buttonstate |= SDL_BUTTON(button);
   483         break;
   484     case SDL_RELEASED:
   485         if (!(touch->buttonstate & SDL_BUTTON(button))) {
   486             /* Ignore this event, no state change */
   487             return 0;
   488         }
   489         type = SDL_TOUCHBUTTONUP;
   490         touch->buttonstate &= ~SDL_BUTTON(button);
   491         break;
   492     default:
   493         /* Invalid state -- bail */
   494         return 0;
   495     }
   496 
   497     /* Post the event, if desired */
   498     posted = 0;
   499     if (SDL_GetEventState(type) == SDL_ENABLE) {
   500         SDL_Event event;
   501         event.type = type;
   502         event.tbutton.touchId = touch->id;
   503         event.tbutton.state = state;
   504         event.tbutton.button = button;
   505         event.tbutton.windowID = touch->focus ? touch->focus->id : 0;
   506         posted = (SDL_PushEvent(&event) > 0);
   507     }
   508     return posted;
   509 }
   510 
   511 char *
   512 SDL_GetTouchName(long id)
   513 {
   514     SDL_Touch *touch = SDL_GetTouch(id);
   515     if (!touch) {
   516         return NULL;
   517     }
   518     return touch->name;
   519 }
   520 
   521 int SDL_TouchNotFoundError(long id) {
   522   printf("ERROR: Cannot send touch on non-existent device with id: %li make sure SDL_AddTouch has been called\n",id);
   523   printf("ERROR: There are %i touches installed with Id's:\n",SDL_num_touch);
   524   int i;
   525   for(i=0;i < SDL_num_touch;i++) {
   526     printf("ERROR: %li\n",SDL_touchPads[i]->id);
   527   }
   528   return 0;
   529 }
   530 /* vi: set ts=4 sw=4 expandtab: */