src/events/SDL_touch.c
author Andreas Schiffler <aschiffler@ferzkopp.net>
Mon, 23 Aug 2010 23:44:28 -0700
changeset 4865 fff50e86c891
parent 4689 f9ab8df6d45a
child 4868 d6adaafcfb10
permissions -rw-r--r--
Update VS2010 project to add new files; update new files so code builds on Win32/Win64
     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(SDL_TouchID 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,SDL_FingerID 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,SDL_FingerID 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(SDL_TouchID 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     SDL_touchPads[index]->xres = (1<<(16-1));
   143     SDL_touchPads[index]->yres = (1<<(16-1));
   144     //Do I want this here? Probably
   145     SDL_GestureAddTouch(SDL_touchPads[index]);
   146 
   147     return index;
   148 }
   149 
   150 void
   151 SDL_DelTouch(SDL_TouchID id)
   152 {
   153     int index = SDL_GetTouchIndexId(id);
   154     SDL_Touch *touch = SDL_GetTouch(id);
   155 
   156     if (!touch) {
   157         return;
   158     }
   159 
   160     
   161     SDL_free(touch->name);
   162  
   163     if (touch->FreeTouch) {
   164         touch->FreeTouch(touch);
   165     }
   166     SDL_free(touch);
   167 
   168     SDL_num_touch--;
   169     SDL_touchPads[index] = SDL_touchPads[SDL_num_touch];
   170 }
   171 
   172 void
   173 SDL_TouchQuit(void)
   174 {
   175     int i;
   176 
   177     for (i = SDL_num_touch-1; i > 0 ; --i) {
   178         SDL_DelTouch(i);
   179     }
   180     SDL_num_touch = 0;
   181 
   182     if (SDL_touchPads) {
   183         SDL_free(SDL_touchPads);
   184         SDL_touchPads = NULL;
   185     }
   186 }
   187 
   188 int
   189 SDL_GetNumTouch(void)
   190 {
   191     return SDL_num_touch;
   192 }
   193 SDL_Window *
   194 SDL_GetTouchFocusWindow(SDL_TouchID id)
   195 {
   196     SDL_Touch *touch = SDL_GetTouch(id);
   197 
   198     if (!touch) {
   199         return 0;
   200     }
   201     return touch->focus;
   202 }
   203 
   204 void
   205 SDL_SetTouchFocus(SDL_TouchID id, SDL_Window * window)
   206 {
   207     int index = SDL_GetTouchIndexId(id);
   208     SDL_Touch *touch = SDL_GetTouch(id);
   209     int i;
   210     SDL_bool focus;
   211 
   212     if (!touch || (touch->focus == window)) {
   213         return;
   214     }
   215 
   216     /* See if the current window has lost focus */
   217     if (touch->focus) {
   218         focus = SDL_FALSE;
   219         for (i = 0; i < SDL_num_touch; ++i) {
   220             SDL_Touch *check;
   221             if (i != index) {
   222                 check = SDL_touchPads[i];
   223                 if (check && check->focus == touch->focus) {
   224                     focus = SDL_TRUE;
   225                     break;
   226                 }
   227             }
   228         }
   229         if (!focus) {
   230             SDL_SendWindowEvent(touch->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
   231         }
   232     }
   233 
   234     touch->focus = window;
   235 
   236     if (touch->focus) {
   237         focus = SDL_FALSE;
   238         for (i = 0; i < SDL_num_touch; ++i) {
   239             SDL_Touch *check;
   240             if (i != index) {
   241                 check = SDL_touchPads[i];
   242                 if (check && check->focus == touch->focus) {
   243                     focus = SDL_TRUE;
   244                     break;
   245                 }
   246             }
   247         }
   248         if (!focus) {
   249             SDL_SendWindowEvent(touch->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
   250         }
   251     }
   252 }
   253 
   254 int 
   255 SDL_AddFinger(SDL_Touch* touch,SDL_Finger *finger)
   256 {
   257     int index;
   258     SDL_Finger **fingers;
   259     //printf("Adding Finger...\n");
   260     if (SDL_GetFingerIndexId(touch,finger->id) != -1) {
   261         SDL_SetError("Finger ID already in use");
   262 	}
   263 
   264     /* Add the touch to the list of touch */
   265     if(touch->num_fingers  >= touch->max_fingers){
   266 		//printf("Making room for it!\n");
   267 		fingers = (SDL_Finger **) SDL_realloc(touch->fingers,
   268   						   (touch->num_fingers + 1) * sizeof(SDL_Finger *));
   269 		touch->max_fingers = touch->num_fingers+1;
   270 		if (!fingers) {
   271 			SDL_OutOfMemory();
   272 			return -1;
   273 		} else {
   274 			touch->max_fingers = touch->num_fingers+1;
   275 			touch->fingers = fingers;
   276 		}
   277 	}
   278 
   279     index = touch->num_fingers;
   280     //printf("Max_Fingers: %i Index: %i\n",touch->max_fingers,index);
   281 
   282     touch->fingers[index] = (SDL_Finger *) SDL_malloc(sizeof(SDL_Finger));
   283     if (!touch->fingers[index]) {
   284         SDL_OutOfMemory();
   285         return -1;
   286     }
   287     *(touch->fingers[index]) = *finger;
   288     touch->num_fingers++;
   289 
   290     return index;
   291 }
   292 
   293 int
   294 SDL_DelFinger(SDL_Touch* touch,SDL_FingerID fingerid)
   295 {
   296     int index = SDL_GetFingerIndexId(touch,fingerid);
   297     SDL_Finger* finger = SDL_GetFinger(touch,fingerid);
   298 
   299     if (!finger) {
   300         return -1;
   301     }
   302  
   303 
   304     SDL_free(finger);
   305     touch->num_fingers--;
   306     touch->fingers[index] = touch->fingers[touch->num_fingers];
   307     return 0;
   308 }
   309 
   310 
   311 int
   312 SDL_SendFingerDown(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, 
   313 		   float xin, float yin, float pressurein)
   314 {
   315     int posted;
   316 	Uint16 x;
   317 	Uint16 y;
   318 	Uint16 pressure;
   319 	SDL_Finger *finger;
   320 
   321     SDL_Touch* touch = SDL_GetTouch(id);
   322 
   323     if(!touch) {
   324       return SDL_TouchNotFoundError(id);
   325     }
   326 
   327     
   328     //scale to Integer coordinates
   329     x = (Uint16)((xin+touch->x_min)*(touch->xres)/(touch->native_xres));
   330     y = (Uint16)((yin+touch->y_min)*(touch->yres)/(touch->native_yres));
   331     pressure = (Uint16)((yin+touch->pressure_min)*(touch->pressureres)/(touch->native_pressureres));
   332     
   333     finger = SDL_GetFinger(touch,fingerid);
   334     if(down) {
   335 	if(finger == NULL) {
   336 	    SDL_Finger nf;
   337 	    nf.id = fingerid;
   338 	    nf.x = x;
   339 	    nf.y = y;
   340 	    nf.pressure = pressure;
   341 	    nf.xdelta = 0;
   342 	    nf.ydelta = 0;
   343 	    nf.last_x = x;
   344 	    nf.last_y = y;
   345 	    nf.last_pressure = pressure;
   346 	    nf.down = SDL_FALSE;
   347 	    if(SDL_AddFinger(touch,&nf) < 0) return 0;
   348 	    finger = SDL_GetFinger(touch,fingerid);
   349 	}
   350 	else if(finger->down) return 0;
   351 	if(xin < touch->x_min || yin < touch->y_min) return 0; //should defer if only a partial input
   352 	posted = 0;
   353 	if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
   354 	    SDL_Event event;
   355 	    event.tfinger.type = SDL_FINGERDOWN;
   356 	    event.tfinger.touchId = id;
   357 	    event.tfinger.x = x;
   358 	    event.tfinger.y = y;
   359 	    event.tfinger.pressure = pressure;
   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 	if(posted) finger->down = SDL_TRUE;
   366 	return posted;
   367     }
   368     else {
   369         if(finger == NULL) {printf("Finger not found...\n");return 0;}      
   370 	posted = 0;
   371 	if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
   372 	    SDL_Event event;
   373 	    event.tfinger.type = SDL_FINGERUP;
   374 	    event.tfinger.touchId =  id;
   375 	    event.tfinger.state = touch->buttonstate;
   376 	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
   377 	    event.tfinger.fingerId = fingerid;
   378 	    //I don't trust the coordinates passed on fingerUp
   379 	    event.tfinger.x = finger->x; 
   380 	    event.tfinger.y = finger->y;
   381 	    event.tfinger.dx = 0;
   382 	    event.tfinger.dy = 0;
   383 
   384 	    if(SDL_DelFinger(touch,fingerid) < 0) return 0;
   385 	    posted = (SDL_PushEvent(&event) > 0);
   386 	}	
   387 	return posted;
   388     }
   389 }
   390 
   391 int
   392 SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, int relative, 
   393 		    float xin, float yin, float pressurein)
   394 {
   395     int index = SDL_GetTouchIndexId(id);
   396     SDL_Touch *touch = SDL_GetTouch(id);
   397     SDL_Finger *finger = SDL_GetFinger(touch,fingerid);
   398     int posted;
   399     Sint16 xrel, yrel;
   400     float x_max = 0, y_max = 0;
   401 	Uint16 x;
   402 	Uint16 y;
   403 	Uint16 pressure;
   404     
   405     if (!touch) {
   406       return SDL_TouchNotFoundError(id);
   407     }
   408 
   409     //scale to Integer coordinates
   410     x = (Uint16)((xin+touch->x_min)*(touch->xres)/(touch->native_xres));
   411     y = (Uint16)((yin+touch->y_min)*(touch->yres)/(touch->native_yres));
   412     pressure = (Uint16)((yin+touch->pressure_min)*(touch->pressureres)/(touch->native_pressureres));
   413     if(touch->flush_motion) {
   414 	return 0;
   415     }
   416     
   417     if(finger == NULL || !finger->down) {
   418 	return SDL_SendFingerDown(id,fingerid,SDL_TRUE,xin,yin,pressurein);	
   419     } else {
   420 	/* the relative motion is calculated regarding the last position */
   421 	if (relative) {
   422 	    xrel = x;
   423 	    yrel = y;
   424 	    x = (finger->last_x + x);
   425 	    y = (finger->last_y + y);
   426 	} else {
   427 	    if(xin < touch->x_min) x = finger->last_x; /*If movement is only in one axis,*/
   428 	    if(yin < touch->y_min) y = finger->last_y; /*The other is marked as -1*/
   429 	    if(pressurein < touch->pressure_min) pressure = finger->last_pressure;
   430 	    xrel = x - finger->last_x;
   431 	    yrel = y - finger->last_y;
   432 	    //printf("xrel,yrel (%i,%i)\n",(int)xrel,(int)yrel);
   433 	}
   434 	
   435 	/* Drop events that don't change state */
   436 	if (!xrel && !yrel) {
   437 #if 0
   438 	    printf("Touch event didn't change state - dropped!\n");
   439 #endif
   440 	    return 0;
   441 	}
   442 	
   443 	/* Update internal touch coordinates */
   444 	
   445 	finger->x = x;
   446 	finger->y = y;
   447 	
   448 	/*Should scale to window? Normalize? Maintain Aspect?*/
   449 	//SDL_GetWindowSize(touch->focus, &x_max, &y_max);
   450 	
   451 	/* make sure that the pointers find themselves inside the windows */
   452 	/* only check if touch->xmax is set ! */
   453 	/*
   454 	  if (x_max && touch->x > x_max) {
   455 	  touch->x = x_max;
   456 	  } else if (touch->x < 0) {
   457 	  touch->x = 0;
   458 	  }
   459 	  
   460 	  if (y_max && touch->y > y_max) {
   461 	  touch->y = y_max;
   462 	  } else if (touch->y < 0) {
   463 	  touch->y = 0;
   464 	  }
   465 	*/
   466 	finger->xdelta = xrel;
   467 	finger->ydelta = yrel;
   468 	finger->pressure = pressure;
   469 	
   470 	
   471 	
   472 	/* Post the event, if desired */
   473 	posted = 0;
   474 	if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
   475 	    SDL_Event event;
   476 	    event.tfinger.type = SDL_FINGERMOTION;
   477 	    event.tfinger.touchId = id;
   478 	    event.tfinger.fingerId = fingerid;
   479 	    event.tfinger.x = x;
   480 	    event.tfinger.y = y;
   481 	    event.tfinger.dx = xrel;
   482 	    event.tfinger.dy = yrel;	    
   483 		
   484 	    event.tfinger.pressure = pressure;
   485 	    event.tfinger.state = touch->buttonstate;
   486 	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
   487 	    posted = (SDL_PushEvent(&event) > 0);
   488 	}
   489 	finger->last_x = finger->x;
   490 	finger->last_y = finger->y;
   491 	finger->last_pressure = finger->pressure;
   492 	return posted;
   493     }
   494 }
   495 int
   496 SDL_SendTouchButton(SDL_TouchID id, Uint8 state, Uint8 button)
   497 {
   498     SDL_Touch *touch = SDL_GetTouch(id);
   499     int posted;
   500     Uint32 type;
   501 
   502     
   503     if (!touch) {
   504       return SDL_TouchNotFoundError(id);
   505     }
   506 
   507     /* Figure out which event to perform */
   508     switch (state) {
   509     case SDL_PRESSED:
   510         if (touch->buttonstate & SDL_BUTTON(button)) {
   511             /* Ignore this event, no state change */
   512             return 0;
   513         }
   514         type = SDL_TOUCHBUTTONDOWN;
   515         touch->buttonstate |= SDL_BUTTON(button);
   516         break;
   517     case SDL_RELEASED:
   518         if (!(touch->buttonstate & SDL_BUTTON(button))) {
   519             /* Ignore this event, no state change */
   520             return 0;
   521         }
   522         type = SDL_TOUCHBUTTONUP;
   523         touch->buttonstate &= ~SDL_BUTTON(button);
   524         break;
   525     default:
   526         /* Invalid state -- bail */
   527         return 0;
   528     }
   529 
   530     /* Post the event, if desired */
   531     posted = 0;
   532     if (SDL_GetEventState(type) == SDL_ENABLE) {
   533         SDL_Event event;
   534         event.type = type;
   535         event.tbutton.touchId = touch->id;
   536         event.tbutton.state = state;
   537         event.tbutton.button = button;
   538         event.tbutton.windowID = touch->focus ? touch->focus->id : 0;
   539         posted = (SDL_PushEvent(&event) > 0);
   540     }
   541     return posted;
   542 }
   543 
   544 char *
   545 SDL_GetTouchName(SDL_TouchID id)
   546 {
   547     SDL_Touch *touch = SDL_GetTouch(id);
   548     if (!touch) {
   549         return NULL;
   550     }
   551     return touch->name;
   552 }
   553 
   554 int SDL_TouchNotFoundError(SDL_TouchID id) {
   555   int i;
   556   printf("ERROR: Cannot send touch on non-existent device with id: %li make sure SDL_AddTouch has been called\n",id);
   557   printf("ERROR: There are %i touches installed with Id's:\n",SDL_num_touch);
   558   for(i=0;i < SDL_num_touch;i++) {
   559     printf("ERROR: %li\n",SDL_touchPads[i]->id);
   560   }
   561   return 0;
   562 }
   563 /* vi: set ts=4 sw=4 expandtab: */