sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_touch.c (13629B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 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_events.h"
     26 #include "SDL_events_c.h"
     27 #include "../video/SDL_sysvideo.h"
     28 
     29 
     30 static int SDL_num_touch = 0;
     31 static SDL_Touch **SDL_touchDevices = NULL;
     32 
     33 /* for mapping touch events to mice */
     34 
     35 #define SYNTHESIZE_TOUCH_TO_MOUSE 1
     36 
     37 #if SYNTHESIZE_TOUCH_TO_MOUSE
     38 static SDL_bool finger_touching = SDL_FALSE;
     39 static SDL_FingerID track_fingerid;
     40 static SDL_TouchID  track_touchid;
     41 #endif
     42 
     43 /* Public functions */
     44 int
     45 SDL_TouchInit(void)
     46 {
     47     return (0);
     48 }
     49 
     50 int
     51 SDL_GetNumTouchDevices(void)
     52 {
     53     return SDL_num_touch;
     54 }
     55 
     56 SDL_TouchID
     57 SDL_GetTouchDevice(int index)
     58 {
     59     if (index < 0 || index >= SDL_num_touch) {
     60         SDL_SetError("Unknown touch device index %d", index);
     61         return 0;
     62     }
     63     return SDL_touchDevices[index]->id;
     64 }
     65 
     66 static int
     67 SDL_GetTouchIndex(SDL_TouchID id)
     68 {
     69     int index;
     70     SDL_Touch *touch;
     71 
     72     for (index = 0; index < SDL_num_touch; ++index) {
     73         touch = SDL_touchDevices[index];
     74         if (touch->id == id) {
     75             return index;
     76         }
     77     }
     78     return -1;
     79 }
     80 
     81 SDL_Touch *
     82 SDL_GetTouch(SDL_TouchID id)
     83 {
     84     int index = SDL_GetTouchIndex(id);
     85     if (index < 0 || index >= SDL_num_touch) {
     86         if (SDL_GetVideoDevice()->ResetTouch != NULL) {
     87             SDL_SetError("Unknown touch id %d, resetting", (int) id);
     88             (SDL_GetVideoDevice()->ResetTouch)(SDL_GetVideoDevice());
     89         } else {
     90             SDL_SetError("Unknown touch device id %d, cannot reset", (int) id);
     91         }
     92         return NULL;
     93     }
     94     return SDL_touchDevices[index];
     95 }
     96 
     97 SDL_TouchDeviceType
     98 SDL_GetTouchDeviceType(SDL_TouchID id)
     99 {
    100     SDL_Touch *touch = SDL_GetTouch(id);
    101     if (touch) {
    102         return touch->type;
    103     }
    104     return SDL_TOUCH_DEVICE_INVALID;
    105 }
    106 
    107 static int
    108 SDL_GetFingerIndex(const SDL_Touch * touch, SDL_FingerID fingerid)
    109 {
    110     int index;
    111     for (index = 0; index < touch->num_fingers; ++index) {
    112         if (touch->fingers[index]->id == fingerid) {
    113             return index;
    114         }
    115     }
    116     return -1;
    117 }
    118 
    119 static SDL_Finger *
    120 SDL_GetFinger(const SDL_Touch * touch, SDL_FingerID id)
    121 {
    122     int index = SDL_GetFingerIndex(touch, id);
    123     if (index < 0 || index >= touch->num_fingers) {
    124         return NULL;
    125     }
    126     return touch->fingers[index];
    127 }
    128 
    129 int
    130 SDL_GetNumTouchFingers(SDL_TouchID touchID)
    131 {
    132     SDL_Touch *touch = SDL_GetTouch(touchID);
    133     if (touch) {
    134         return touch->num_fingers;
    135     }
    136     return 0;
    137 }
    138 
    139 SDL_Finger *
    140 SDL_GetTouchFinger(SDL_TouchID touchID, int index)
    141 {
    142     SDL_Touch *touch = SDL_GetTouch(touchID);
    143     if (!touch) {
    144         return NULL;
    145     }
    146     if (index < 0 || index >= touch->num_fingers) {
    147         SDL_SetError("Unknown touch finger");
    148         return NULL;
    149     }
    150     return touch->fingers[index];
    151 }
    152 
    153 int
    154 SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
    155 {
    156     SDL_Touch **touchDevices;
    157     int index;
    158 
    159     index = SDL_GetTouchIndex(touchID);
    160     if (index >= 0) {
    161         return index;
    162     }
    163 
    164     /* Add the touch to the list of touch */
    165     touchDevices = (SDL_Touch **) SDL_realloc(SDL_touchDevices,
    166                                       (SDL_num_touch + 1) * sizeof(*touchDevices));
    167     if (!touchDevices) {
    168         return SDL_OutOfMemory();
    169     }
    170 
    171     SDL_touchDevices = touchDevices;
    172     index = SDL_num_touch;
    173 
    174     SDL_touchDevices[index] = (SDL_Touch *) SDL_malloc(sizeof(*SDL_touchDevices[index]));
    175     if (!SDL_touchDevices[index]) {
    176         return SDL_OutOfMemory();
    177     }
    178 
    179     /* Added touch to list */
    180     ++SDL_num_touch;
    181 
    182     /* we're setting the touch properties */
    183     SDL_touchDevices[index]->id = touchID;
    184     SDL_touchDevices[index]->type = type;
    185     SDL_touchDevices[index]->num_fingers = 0;
    186     SDL_touchDevices[index]->max_fingers = 0;
    187     SDL_touchDevices[index]->fingers = NULL;
    188 
    189     /* Record this touch device for gestures */
    190     /* We could do this on the fly in the gesture code if we wanted */
    191     SDL_GestureAddTouch(touchID);
    192 
    193     return index;
    194 }
    195 
    196 static int
    197 SDL_AddFinger(SDL_Touch *touch, SDL_FingerID fingerid, float x, float y, float pressure)
    198 {
    199     SDL_Finger *finger;
    200 
    201     if (touch->num_fingers == touch->max_fingers) {
    202         SDL_Finger **new_fingers;
    203         new_fingers = (SDL_Finger **)SDL_realloc(touch->fingers, (touch->max_fingers+1)*sizeof(*touch->fingers));
    204         if (!new_fingers) {
    205             return SDL_OutOfMemory();
    206         }
    207         touch->fingers = new_fingers;
    208         touch->fingers[touch->max_fingers] = (SDL_Finger *)SDL_malloc(sizeof(*finger));
    209         if (!touch->fingers[touch->max_fingers]) {
    210             return SDL_OutOfMemory();
    211         }
    212         touch->max_fingers++;
    213     }
    214 
    215     finger = touch->fingers[touch->num_fingers++];
    216     finger->id = fingerid;
    217     finger->x = x;
    218     finger->y = y;
    219     finger->pressure = pressure;
    220     return 0;
    221 }
    222 
    223 static int
    224 SDL_DelFinger(SDL_Touch* touch, SDL_FingerID fingerid)
    225 {
    226     SDL_Finger *temp;
    227 
    228     int index = SDL_GetFingerIndex(touch, fingerid);
    229     if (index < 0) {
    230         return -1;
    231     }
    232 
    233     touch->num_fingers--;
    234     temp = touch->fingers[index];
    235     touch->fingers[index] = touch->fingers[touch->num_fingers];
    236     touch->fingers[touch->num_fingers] = temp;
    237     return 0;
    238 }
    239 
    240 int
    241 SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window,
    242               SDL_bool down, float x, float y, float pressure)
    243 {
    244     int posted;
    245     SDL_Finger *finger;
    246     SDL_Mouse *mouse;
    247 
    248     SDL_Touch* touch = SDL_GetTouch(id);
    249     if (!touch) {
    250         return -1;
    251     }
    252 
    253     mouse = SDL_GetMouse();
    254 
    255 #if SYNTHESIZE_TOUCH_TO_MOUSE
    256     /* SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events */
    257     {
    258         if (mouse->touch_mouse_events) {
    259             /* FIXME: maybe we should only restrict to a few SDL_TouchDeviceType */
    260             if (id != SDL_MOUSE_TOUCHID) {
    261                 if (window) {
    262                     if (down) {
    263                         if (finger_touching == SDL_FALSE) {
    264                             int pos_x = (int)(x * (float)window->w);
    265                             int pos_y = (int)(y * (float)window->h);
    266                             if (pos_x < 0) pos_x = 0;
    267                             if (pos_x > window->w - 1) pos_x = window->w - 1;
    268                             if (pos_y < 0) pos_y = 0;
    269                             if (pos_y > window->h - 1) pos_y = window->h - 1;
    270                             SDL_SendMouseMotion(window, SDL_TOUCH_MOUSEID, 0, pos_x, pos_y);
    271                             SDL_SendMouseButton(window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
    272                         }
    273                     } else {
    274                         if (finger_touching == SDL_TRUE && track_touchid == id && track_fingerid == fingerid) {
    275                             SDL_SendMouseButton(window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
    276                         }
    277                     }
    278                 }
    279                 if (down) {
    280                     if (finger_touching == SDL_FALSE) {
    281                         finger_touching = SDL_TRUE;
    282                         track_touchid = id;
    283                         track_fingerid = fingerid;
    284                     }
    285                 } else {
    286                     if (finger_touching == SDL_TRUE && track_touchid == id && track_fingerid == fingerid) {
    287                         finger_touching = SDL_FALSE;
    288                     }
    289                 }
    290             }
    291         }
    292     }
    293 #endif
    294 
    295     /* SDL_HINT_MOUSE_TOUCH_EVENTS: if not set, discard synthetic touch events coming from platform layer */
    296     if (mouse->mouse_touch_events == 0) {
    297         if (id == SDL_MOUSE_TOUCHID) {
    298             return 0;
    299         }
    300     }
    301 
    302     finger = SDL_GetFinger(touch, fingerid);
    303     if (down) {
    304         if (finger) {
    305             /* This finger is already down */
    306             return 0;
    307         }
    308 
    309         if (SDL_AddFinger(touch, fingerid, x, y, pressure) < 0) {
    310             return 0;
    311         }
    312 
    313         posted = 0;
    314         if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
    315             SDL_Event event;
    316             event.tfinger.type = SDL_FINGERDOWN;
    317             event.tfinger.touchId = id;
    318             event.tfinger.fingerId = fingerid;
    319             event.tfinger.x = x;
    320             event.tfinger.y = y;
    321             event.tfinger.dx = 0;
    322             event.tfinger.dy = 0;
    323             event.tfinger.pressure = pressure;
    324             event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0;
    325             posted = (SDL_PushEvent(&event) > 0);
    326         }
    327     } else {
    328         if (!finger) {
    329             /* This finger is already up */
    330             return 0;
    331         }
    332 
    333         posted = 0;
    334         if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
    335             SDL_Event event;
    336             event.tfinger.type = SDL_FINGERUP;
    337             event.tfinger.touchId = id;
    338             event.tfinger.fingerId = fingerid;
    339             /* I don't trust the coordinates passed on fingerUp */
    340             event.tfinger.x = finger->x;
    341             event.tfinger.y = finger->y;
    342             event.tfinger.dx = 0;
    343             event.tfinger.dy = 0;
    344             event.tfinger.pressure = pressure;
    345             event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0;
    346             posted = (SDL_PushEvent(&event) > 0);
    347         }
    348 
    349         SDL_DelFinger(touch, fingerid);
    350     }
    351     return posted;
    352 }
    353 
    354 int
    355 SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window,
    356                     float x, float y, float pressure)
    357 {
    358     SDL_Touch *touch;
    359     SDL_Finger *finger;
    360     SDL_Mouse *mouse;
    361     int posted;
    362     float xrel, yrel, prel;
    363 
    364     touch = SDL_GetTouch(id);
    365     if (!touch) {
    366         return -1;
    367     }
    368 
    369     mouse = SDL_GetMouse();
    370 
    371 #if SYNTHESIZE_TOUCH_TO_MOUSE
    372     /* SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events */
    373     {
    374         if (mouse->touch_mouse_events) {
    375             if (id != SDL_MOUSE_TOUCHID) {
    376                 if (window) {
    377                     if (finger_touching == SDL_TRUE && track_touchid == id && track_fingerid == fingerid) {
    378                         int pos_x = (int)(x * (float)window->w);
    379                         int pos_y = (int)(y * (float)window->h);
    380                         if (pos_x < 0) pos_x = 0;
    381                         if (pos_x > window->w - 1) pos_x = window->w - 1;
    382                         if (pos_y < 0) pos_y = 0;
    383                         if (pos_y > window->h - 1) pos_y = window->h - 1;
    384                         SDL_SendMouseMotion(window, SDL_TOUCH_MOUSEID, 0, pos_x, pos_y);
    385                     }
    386                 }
    387             }
    388         }
    389     }
    390 #endif
    391 
    392     /* SDL_HINT_MOUSE_TOUCH_EVENTS: if not set, discard synthetic touch events coming from platform layer */
    393     if (mouse->mouse_touch_events == 0) {
    394         if (id == SDL_MOUSE_TOUCHID) {
    395             return 0;
    396         }
    397     }
    398 
    399     finger = SDL_GetFinger(touch,fingerid);
    400     if (!finger) {
    401         return SDL_SendTouch(id, fingerid, window, SDL_TRUE, x, y, pressure);
    402     }
    403 
    404     xrel = x - finger->x;
    405     yrel = y - finger->y;
    406     prel = pressure - finger->pressure;
    407 
    408     /* Drop events that don't change state */
    409     if (xrel == 0.0f && yrel == 0.0f && prel == 0.0f) {
    410 #if 0
    411         printf("Touch event didn't change state - dropped!\n");
    412 #endif
    413         return 0;
    414     }
    415 
    416     /* Update internal touch coordinates */
    417     finger->x = x;
    418     finger->y = y;
    419     finger->pressure = pressure;
    420 
    421     /* Post the event, if desired */
    422     posted = 0;
    423     if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
    424         SDL_Event event;
    425         event.tfinger.type = SDL_FINGERMOTION;
    426         event.tfinger.touchId = id;
    427         event.tfinger.fingerId = fingerid;
    428         event.tfinger.x = x;
    429         event.tfinger.y = y;
    430         event.tfinger.dx = xrel;
    431         event.tfinger.dy = yrel;
    432         event.tfinger.pressure = pressure;
    433         event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0;
    434         posted = (SDL_PushEvent(&event) > 0);
    435     }
    436     return posted;
    437 }
    438 
    439 void
    440 SDL_DelTouch(SDL_TouchID id)
    441 {
    442     int i;
    443     int index = SDL_GetTouchIndex(id);
    444     SDL_Touch *touch = SDL_GetTouch(id);
    445 
    446     if (!touch) {
    447         return;
    448     }
    449 
    450     for (i = 0; i < touch->max_fingers; ++i) {
    451         SDL_free(touch->fingers[i]);
    452     }
    453     SDL_free(touch->fingers);
    454     SDL_free(touch);
    455 
    456     SDL_num_touch--;
    457     SDL_touchDevices[index] = SDL_touchDevices[SDL_num_touch];
    458 
    459     /* Delete this touch device for gestures */
    460     SDL_GestureDelTouch(id);
    461 }
    462 
    463 void
    464 SDL_TouchQuit(void)
    465 {
    466     int i;
    467 
    468     for (i = SDL_num_touch; i--; ) {
    469         SDL_DelTouch(SDL_touchDevices[i]->id);
    470     }
    471     SDL_assert(SDL_num_touch == 0);
    472 
    473     SDL_free(SDL_touchDevices);
    474     SDL_touchDevices = NULL;
    475     SDL_GestureQuit();
    476 }
    477 
    478 /* vi: set ts=4 sw=4 expandtab: */