src/events/SDL_touch.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 26 May 2015 06:27:46 -0700
changeset 9619 b94b6d0bff0f
parent 8149 681eb46b8ac4
child 9730 3136a8c1cf0b
permissions -rw-r--r--
Updated the copyright year to 2015
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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_internal.h"
    22 
    23 /* General touch handling code for SDL */
    24 
    25 #include "SDL_assert.h"
    26 #include "SDL_events.h"
    27 #include "SDL_events_c.h"
    28 
    29 
    30 static int SDL_num_touch = 0;
    31 static SDL_Touch **SDL_touchDevices = NULL;
    32 
    33 
    34 /* Public functions */
    35 int
    36 SDL_TouchInit(void)
    37 {
    38     return (0);
    39 }
    40 
    41 int
    42 SDL_GetNumTouchDevices(void)
    43 {
    44     return SDL_num_touch;
    45 }
    46 
    47 SDL_TouchID
    48 SDL_GetTouchDevice(int index)
    49 {
    50     if (index < 0 || index >= SDL_num_touch) {
    51         SDL_SetError("Unknown touch device");
    52         return 0;
    53     }
    54     return SDL_touchDevices[index]->id;
    55 }
    56 
    57 static int
    58 SDL_GetTouchIndex(SDL_TouchID id)
    59 {
    60     int index;
    61     SDL_Touch *touch;
    62 
    63     for (index = 0; index < SDL_num_touch; ++index) {
    64         touch = SDL_touchDevices[index];
    65         if (touch->id == id) {
    66             return index;
    67         }
    68     }
    69     return -1;
    70 }
    71 
    72 SDL_Touch *
    73 SDL_GetTouch(SDL_TouchID id)
    74 {
    75     int index = SDL_GetTouchIndex(id);
    76     if (index < 0 || index >= SDL_num_touch) {
    77         SDL_SetError("Unknown touch device");
    78         return NULL;
    79     }
    80     return SDL_touchDevices[index];
    81 }
    82 
    83 static int
    84 SDL_GetFingerIndex(const SDL_Touch * touch, SDL_FingerID fingerid)
    85 {
    86     int index;
    87     for (index = 0; index < touch->num_fingers; ++index) {
    88         if (touch->fingers[index]->id == fingerid) {
    89             return index;
    90         }
    91     }
    92     return -1;
    93 }
    94 
    95 SDL_Finger *
    96 SDL_GetFinger(const SDL_Touch * touch, SDL_FingerID id)
    97 {
    98     int index = SDL_GetFingerIndex(touch, id);
    99     if (index < 0 || index >= touch->num_fingers) {
   100         return NULL;
   101     }
   102     return touch->fingers[index];
   103 }
   104 
   105 int
   106 SDL_GetNumTouchFingers(SDL_TouchID touchID)
   107 {
   108     SDL_Touch *touch = SDL_GetTouch(touchID);
   109     if (touch) {
   110         return touch->num_fingers;
   111     }
   112     return 0;
   113 }
   114 
   115 SDL_Finger *
   116 SDL_GetTouchFinger(SDL_TouchID touchID, int index)
   117 {
   118     SDL_Touch *touch = SDL_GetTouch(touchID);
   119     if (!touch) {
   120         return NULL;
   121     }
   122     if (index < 0 || index >= touch->num_fingers) {
   123         SDL_SetError("Unknown touch finger");
   124         return NULL;
   125     }
   126     return touch->fingers[index];
   127 }
   128 
   129 int
   130 SDL_AddTouch(SDL_TouchID touchID, const char *name)
   131 {
   132     SDL_Touch **touchDevices;
   133     int index;
   134 
   135     index = SDL_GetTouchIndex(touchID);
   136     if (index >= 0) {
   137         return index;
   138     }
   139 
   140     /* Add the touch to the list of touch */
   141     touchDevices = (SDL_Touch **) SDL_realloc(SDL_touchDevices,
   142                                       (SDL_num_touch + 1) * sizeof(*touchDevices));
   143     if (!touchDevices) {
   144         return SDL_OutOfMemory();
   145     }
   146 
   147     SDL_touchDevices = touchDevices;
   148     index = SDL_num_touch++;
   149 
   150     SDL_touchDevices[index] = (SDL_Touch *) SDL_malloc(sizeof(*SDL_touchDevices[index]));
   151     if (!SDL_touchDevices[index]) {
   152         return SDL_OutOfMemory();
   153     }
   154 
   155     /* we're setting the touch properties */
   156     SDL_touchDevices[index]->id = touchID;
   157     SDL_touchDevices[index]->num_fingers = 0;
   158     SDL_touchDevices[index]->max_fingers = 0;
   159     SDL_touchDevices[index]->fingers = NULL;
   160 
   161     /* Record this touch device for gestures */
   162     /* We could do this on the fly in the gesture code if we wanted */
   163     SDL_GestureAddTouch(touchID);
   164 
   165     return index;
   166 }
   167 
   168 static int
   169 SDL_AddFinger(SDL_Touch *touch, SDL_FingerID fingerid, float x, float y, float pressure)
   170 {
   171     SDL_Finger *finger;
   172 
   173     if (touch->num_fingers == touch->max_fingers) {
   174         SDL_Finger **new_fingers;
   175         new_fingers = (SDL_Finger **)SDL_realloc(touch->fingers, (touch->max_fingers+1)*sizeof(*touch->fingers));
   176         if (!new_fingers) {
   177             return SDL_OutOfMemory();
   178         }
   179         touch->fingers = new_fingers;
   180         touch->fingers[touch->max_fingers] = (SDL_Finger *)SDL_malloc(sizeof(*finger));
   181         if (!touch->fingers[touch->max_fingers]) {
   182             return SDL_OutOfMemory();
   183         }
   184         touch->max_fingers++;
   185     }
   186 
   187     finger = touch->fingers[touch->num_fingers++];
   188     finger->id = fingerid;
   189     finger->x = x;
   190     finger->y = y;
   191     finger->pressure = pressure;
   192     return 0;
   193 }
   194 
   195 static int
   196 SDL_DelFinger(SDL_Touch* touch, SDL_FingerID fingerid)
   197 {
   198     SDL_Finger *temp;
   199 
   200     int index = SDL_GetFingerIndex(touch, fingerid);
   201     if (index < 0) {
   202         return -1;
   203     }
   204 
   205     touch->num_fingers--;
   206     temp = touch->fingers[index];
   207     touch->fingers[index] = touch->fingers[touch->num_fingers];
   208     touch->fingers[touch->num_fingers] = temp;
   209     return 0;
   210 }
   211 
   212 int
   213 SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid,
   214               SDL_bool down, float x, float y, float pressure)
   215 {
   216     int posted;
   217     SDL_Finger *finger;
   218 
   219     SDL_Touch* touch = SDL_GetTouch(id);
   220     if (!touch) {
   221         return -1;
   222     }
   223 
   224     finger = SDL_GetFinger(touch, fingerid);
   225     if (down) {
   226         if (finger) {
   227             /* This finger is already down */
   228             return 0;
   229         }
   230 
   231         if (SDL_AddFinger(touch, fingerid, x, y, pressure) < 0) {
   232             return 0;
   233         }
   234 
   235         posted = 0;
   236         if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
   237             SDL_Event event;
   238             event.tfinger.type = SDL_FINGERDOWN;
   239             event.tfinger.touchId = id;
   240             event.tfinger.fingerId = fingerid;
   241             event.tfinger.x = x;
   242             event.tfinger.y = y;
   243             event.tfinger.dx = 0;
   244             event.tfinger.dy = 0;
   245             event.tfinger.pressure = pressure;
   246             posted = (SDL_PushEvent(&event) > 0);
   247         }
   248     } else {
   249         if (!finger) {
   250             /* This finger is already up */
   251             return 0;
   252         }
   253 
   254         posted = 0;
   255         if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
   256             SDL_Event event;
   257             event.tfinger.type = SDL_FINGERUP;
   258             event.tfinger.touchId =  id;
   259             event.tfinger.fingerId = fingerid;
   260             /* I don't trust the coordinates passed on fingerUp */
   261             event.tfinger.x = finger->x;
   262             event.tfinger.y = finger->y;
   263             event.tfinger.dx = 0;
   264             event.tfinger.dy = 0;
   265             event.tfinger.pressure = pressure;
   266             posted = (SDL_PushEvent(&event) > 0);
   267         }
   268 
   269         SDL_DelFinger(touch, fingerid);
   270     }
   271     return posted;
   272 }
   273 
   274 int
   275 SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid,
   276                     float x, float y, float pressure)
   277 {
   278     SDL_Touch *touch;
   279     SDL_Finger *finger;
   280     int posted;
   281     float xrel, yrel, prel;
   282 
   283     touch = SDL_GetTouch(id);
   284     if (!touch) {
   285         return -1;
   286     }
   287 
   288     finger = SDL_GetFinger(touch,fingerid);
   289     if (!finger) {
   290         return SDL_SendTouch(id, fingerid, SDL_TRUE, x, y, pressure);
   291     }
   292 
   293     xrel = x - finger->x;
   294     yrel = y - finger->y;
   295     prel = pressure - finger->pressure;
   296 
   297     /* Drop events that don't change state */
   298     if (!xrel && !yrel && !prel) {
   299 #if 0
   300         printf("Touch event didn't change state - dropped!\n");
   301 #endif
   302         return 0;
   303     }
   304 
   305     /* Update internal touch coordinates */
   306     finger->x = x;
   307     finger->y = y;
   308     finger->pressure = pressure;
   309 
   310     /* Post the event, if desired */
   311     posted = 0;
   312     if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
   313         SDL_Event event;
   314         event.tfinger.type = SDL_FINGERMOTION;
   315         event.tfinger.touchId = id;
   316         event.tfinger.fingerId = fingerid;
   317         event.tfinger.x = x;
   318         event.tfinger.y = y;
   319         event.tfinger.dx = xrel;
   320         event.tfinger.dy = yrel;
   321         event.tfinger.pressure = pressure;
   322         posted = (SDL_PushEvent(&event) > 0);
   323     }
   324     return posted;
   325 }
   326 
   327 void
   328 SDL_DelTouch(SDL_TouchID id)
   329 {
   330     int i;
   331     int index = SDL_GetTouchIndex(id);
   332     SDL_Touch *touch = SDL_GetTouch(id);
   333 
   334     if (!touch) {
   335         return;
   336     }
   337 
   338     for (i = 0; i < touch->max_fingers; ++i) {
   339         SDL_free(touch->fingers[i]);
   340     }
   341     SDL_free(touch->fingers);
   342     SDL_free(touch);
   343 
   344     SDL_num_touch--;
   345     SDL_touchDevices[index] = SDL_touchDevices[SDL_num_touch];
   346 }
   347 
   348 void
   349 SDL_TouchQuit(void)
   350 {
   351     int i;
   352 
   353     for (i = SDL_num_touch; i--; ) {
   354         SDL_DelTouch(SDL_touchDevices[i]->id);
   355     }
   356     SDL_assert(SDL_num_touch == 0);
   357 
   358     SDL_free(SDL_touchDevices);
   359     SDL_touchDevices = NULL;
   360 }
   361 
   362 /* vi: set ts=4 sw=4 expandtab: */