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