src/events/SDL_touch.c
author Alex Szpakowski <slime73@gmail.com>
Sat, 10 Nov 2018 16:15:48 -0400
changeset 12404 eb60e952b13f
parent 11811 5d94cb6b24d3
child 12462 b57435750c5b
permissions -rw-r--r--
Add SDL_TouchDeviceType enum and SDL_GetTouchDeviceType(SDL_TouchID id).

Touch device types include SDL_TOUCH_DEVICE_DIRECT (a touch screen with window-relative coordinates for touches), SDL_TOUCH_DEVICE_INDIRECT_ABSOLUTE (a trackpad-style device with absolute device coordinates), and SDL_TOUCH_DEVICE_INDIRECT_RELATIVE (a trackpad-style device with screen cursor-relative coordinates).

Phone screens are an example of a direct device type. Mac trackpads are the indirect-absolute touch device type. The Apple TV remote is an indirect-relative touch device type.
jim@4640
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@11811
     3
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
jim@4640
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
jim@4640
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
jim@4640
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
jim@4640
    20
*/
icculus@8093
    21
#include "../SDL_internal.h"
jim@4640
    22
jim@4640
    23
/* General touch handling code for SDL */
jim@4640
    24
slouken@6951
    25
#include "SDL_assert.h"
jim@4640
    26
#include "SDL_events.h"
jim@4640
    27
#include "SDL_events_c.h"
slouken@10880
    28
#include "../video/SDL_sysvideo.h"
jimtla@4648
    29
jim@4640
    30
jim@4640
    31
static int SDL_num_touch = 0;
slouken@6951
    32
static SDL_Touch **SDL_touchDevices = NULL;
jim@4640
    33
jim@4640
    34
jim@4640
    35
/* Public functions */
jim@4640
    36
int
jim@4640
    37
SDL_TouchInit(void)
jim@4640
    38
{
slouken@6951
    39
    return (0);
jim@4640
    40
}
jim@4642
    41
slouken@6951
    42
int
philipp@7170
    43
SDL_GetNumTouchDevices(void)
jim@4640
    44
{
slouken@6951
    45
    return SDL_num_touch;
jim@4640
    46
}
jim@4640
    47
slouken@6951
    48
SDL_TouchID
slouken@6951
    49
SDL_GetTouchDevice(int index)
jim@4641
    50
{
jim@4642
    51
    if (index < 0 || index >= SDL_num_touch) {
slouken@10880
    52
        SDL_SetError("Unknown touch device index %d", index);
slouken@6951
    53
        return 0;
jim@4642
    54
    }
slouken@6951
    55
    return SDL_touchDevices[index]->id;
jim@4641
    56
}
jim@4641
    57
slouken@6044
    58
static int
slouken@6951
    59
SDL_GetTouchIndex(SDL_TouchID id)
jim@4640
    60
{
jim@4640
    61
    int index;
jim@4640
    62
    SDL_Touch *touch;
jim@4640
    63
jim@4640
    64
    for (index = 0; index < SDL_num_touch; ++index) {
slouken@6951
    65
        touch = SDL_touchDevices[index];
jim@4640
    66
        if (touch->id == id) {
jim@4640
    67
            return index;
jim@4640
    68
        }
jim@4640
    69
    }
jim@4640
    70
    return -1;
jim@4640
    71
}
jim@4640
    72
slouken@6951
    73
SDL_Touch *
slouken@6951
    74
SDL_GetTouch(SDL_TouchID id)
slouken@6951
    75
{
slouken@6951
    76
    int index = SDL_GetTouchIndex(id);
slouken@6951
    77
    if (index < 0 || index >= SDL_num_touch) {
slouken@10880
    78
        if (SDL_GetVideoDevice()->ResetTouch != NULL) {
slouken@10880
    79
            SDL_SetError("Unknown touch id %d, resetting", (int) id);
slouken@10880
    80
            (SDL_GetVideoDevice()->ResetTouch)(SDL_GetVideoDevice());
slouken@10880
    81
        } else {
slouken@10880
    82
            SDL_SetError("Unknown touch device id %d, cannot reset", (int) id);
slouken@10880
    83
        }
slouken@6951
    84
        return NULL;
slouken@6951
    85
    }
slouken@6951
    86
    return SDL_touchDevices[index];
slouken@6951
    87
}
slouken@6951
    88
slime73@12404
    89
SDL_TouchDeviceType
slime73@12404
    90
SDL_GetTouchDeviceType(SDL_TouchID id)
slime73@12404
    91
{
slime73@12404
    92
    SDL_Touch *touch = SDL_GetTouch(id);
slime73@12404
    93
    if (touch) {
slime73@12404
    94
        return touch->type;
slime73@12404
    95
    }
slime73@12404
    96
    return SDL_TOUCH_DEVICE_INVALID;
slime73@12404
    97
}
slime73@12404
    98
slouken@6951
    99
static int
slouken@6951
   100
SDL_GetFingerIndex(const SDL_Touch * touch, SDL_FingerID fingerid)
slouken@6951
   101
{
slouken@6951
   102
    int index;
slouken@6951
   103
    for (index = 0; index < touch->num_fingers; ++index) {
slouken@6951
   104
        if (touch->fingers[index]->id == fingerid) {
slouken@6951
   105
            return index;
slouken@6951
   106
        }
slouken@6951
   107
    }
slouken@6951
   108
    return -1;
slouken@6951
   109
}
slouken@6951
   110
slouken@10609
   111
static SDL_Finger *
slouken@6951
   112
SDL_GetFinger(const SDL_Touch * touch, SDL_FingerID id)
slouken@6951
   113
{
slouken@6951
   114
    int index = SDL_GetFingerIndex(touch, id);
slouken@6951
   115
    if (index < 0 || index >= touch->num_fingers) {
slouken@6951
   116
        return NULL;
slouken@6951
   117
    }
slouken@6951
   118
    return touch->fingers[index];
slouken@6951
   119
}
slouken@6951
   120
jim@4640
   121
int
slouken@6951
   122
SDL_GetNumTouchFingers(SDL_TouchID touchID)
jim@4640
   123
{
slouken@6951
   124
    SDL_Touch *touch = SDL_GetTouch(touchID);
slouken@6951
   125
    if (touch) {
slouken@6951
   126
        return touch->num_fingers;
slouken@6951
   127
    }
slouken@6951
   128
    return 0;
slouken@6951
   129
}
slouken@6951
   130
slouken@6951
   131
SDL_Finger *
slouken@6951
   132
SDL_GetTouchFinger(SDL_TouchID touchID, int index)
slouken@6951
   133
{
slouken@6951
   134
    SDL_Touch *touch = SDL_GetTouch(touchID);
slouken@6951
   135
    if (!touch) {
slouken@6951
   136
        return NULL;
slouken@6951
   137
    }
slouken@6951
   138
    if (index < 0 || index >= touch->num_fingers) {
slouken@6951
   139
        SDL_SetError("Unknown touch finger");
slouken@6951
   140
        return NULL;
slouken@6951
   141
    }
slouken@6951
   142
    return touch->fingers[index];
slouken@6951
   143
}
slouken@6951
   144
slouken@6951
   145
int
slime73@12404
   146
SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
slouken@6951
   147
{
slouken@6951
   148
    SDL_Touch **touchDevices;
slouken@5076
   149
    int index;
jim@4640
   150
slouken@6951
   151
    index = SDL_GetTouchIndex(touchID);
slouken@6951
   152
    if (index >= 0) {
slouken@6951
   153
        return index;
jim@4640
   154
    }
jim@4640
   155
jim@4640
   156
    /* Add the touch to the list of touch */
slouken@6951
   157
    touchDevices = (SDL_Touch **) SDL_realloc(SDL_touchDevices,
slouken@6951
   158
                                      (SDL_num_touch + 1) * sizeof(*touchDevices));
slouken@6951
   159
    if (!touchDevices) {
icculus@7037
   160
        return SDL_OutOfMemory();
jim@4640
   161
    }
jim@4640
   162
slouken@6951
   163
    SDL_touchDevices = touchDevices;
philipp@9730
   164
    index = SDL_num_touch;
jim@4640
   165
slouken@6951
   166
    SDL_touchDevices[index] = (SDL_Touch *) SDL_malloc(sizeof(*SDL_touchDevices[index]));
slouken@6951
   167
    if (!SDL_touchDevices[index]) {
icculus@7037
   168
        return SDL_OutOfMemory();
jim@4640
   169
    }
jim@4640
   170
philipp@9730
   171
    /* Added touch to list */
philipp@9730
   172
    ++SDL_num_touch;
philipp@9730
   173
jim@4640
   174
    /* we're setting the touch properties */
slouken@6951
   175
    SDL_touchDevices[index]->id = touchID;
slime73@12404
   176
    SDL_touchDevices[index]->type = type;
slouken@6951
   177
    SDL_touchDevices[index]->num_fingers = 0;
slouken@6951
   178
    SDL_touchDevices[index]->max_fingers = 0;
slouken@6951
   179
    SDL_touchDevices[index]->fingers = NULL;
jim@4642
   180
slouken@6951
   181
    /* Record this touch device for gestures */
slouken@6951
   182
    /* We could do this on the fly in the gesture code if we wanted */
slouken@6951
   183
    SDL_GestureAddTouch(touchID);
jim@4657
   184
jim@4640
   185
    return index;
jim@4640
   186
}
jim@4640
   187
slouken@7191
   188
static int
slouken@6951
   189
SDL_AddFinger(SDL_Touch *touch, SDL_FingerID fingerid, float x, float y, float pressure)
slouken@6951
   190
{
slouken@6951
   191
    SDL_Finger *finger;
slouken@6951
   192
slouken@6951
   193
    if (touch->num_fingers == touch->max_fingers) {
slouken@6951
   194
        SDL_Finger **new_fingers;
slouken@6951
   195
        new_fingers = (SDL_Finger **)SDL_realloc(touch->fingers, (touch->max_fingers+1)*sizeof(*touch->fingers));
slouken@6951
   196
        if (!new_fingers) {
icculus@7037
   197
            return SDL_OutOfMemory();
slouken@6951
   198
        }
slouken@6951
   199
        touch->fingers = new_fingers;
slouken@6951
   200
        touch->fingers[touch->max_fingers] = (SDL_Finger *)SDL_malloc(sizeof(*finger));
slouken@6951
   201
        if (!touch->fingers[touch->max_fingers]) {
icculus@7037
   202
            return SDL_OutOfMemory();
slouken@6951
   203
        }
slouken@6951
   204
        touch->max_fingers++;
slouken@6951
   205
    }
slouken@6951
   206
slouken@6951
   207
    finger = touch->fingers[touch->num_fingers++];
slouken@6951
   208
    finger->id = fingerid;
slouken@6951
   209
    finger->x = x;
slouken@6951
   210
    finger->y = y;
slouken@6951
   211
    finger->pressure = pressure;
slouken@6951
   212
    return 0;
slouken@6951
   213
}
slouken@6951
   214
slouken@6951
   215
static int
slouken@6951
   216
SDL_DelFinger(SDL_Touch* touch, SDL_FingerID fingerid)
slouken@6951
   217
{
slouken@6951
   218
    SDL_Finger *temp;
slouken@6951
   219
slouken@6951
   220
    int index = SDL_GetFingerIndex(touch, fingerid);
slouken@6951
   221
    if (index < 0) {
slouken@6951
   222
        return -1;
slouken@6951
   223
    }
slouken@6951
   224
slouken@6951
   225
    touch->num_fingers--;
slouken@6951
   226
    temp = touch->fingers[index];
slouken@6951
   227
    touch->fingers[index] = touch->fingers[touch->num_fingers];
slouken@6951
   228
    touch->fingers[touch->num_fingers] = temp;
slouken@6951
   229
    return 0;
slouken@6951
   230
}
slouken@6951
   231
slouken@6951
   232
int
slouken@6951
   233
SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid,
slouken@6951
   234
              SDL_bool down, float x, float y, float pressure)
slouken@6951
   235
{
slouken@6951
   236
    int posted;
slouken@6951
   237
    SDL_Finger *finger;
slouken@6951
   238
slouken@6951
   239
    SDL_Touch* touch = SDL_GetTouch(id);
slouken@6951
   240
    if (!touch) {
slouken@6951
   241
        return -1;
slouken@6951
   242
    }
slouken@6951
   243
slouken@6951
   244
    finger = SDL_GetFinger(touch, fingerid);
slouken@6951
   245
    if (down) {
slouken@6951
   246
        if (finger) {
slouken@6951
   247
            /* This finger is already down */
slouken@6951
   248
            return 0;
slouken@6951
   249
        }
slouken@6951
   250
slouken@6951
   251
        if (SDL_AddFinger(touch, fingerid, x, y, pressure) < 0) {
slouken@6951
   252
            return 0;
slouken@6951
   253
        }
slouken@6951
   254
slouken@6951
   255
        posted = 0;
slouken@6951
   256
        if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
slouken@6951
   257
            SDL_Event event;
slouken@6951
   258
            event.tfinger.type = SDL_FINGERDOWN;
slouken@6951
   259
            event.tfinger.touchId = id;
slouken@6951
   260
            event.tfinger.fingerId = fingerid;
slouken@6951
   261
            event.tfinger.x = x;
slouken@6951
   262
            event.tfinger.y = y;
slouken@6951
   263
            event.tfinger.dx = 0;
slouken@6951
   264
            event.tfinger.dy = 0;
slouken@6951
   265
            event.tfinger.pressure = pressure;
slouken@6951
   266
            posted = (SDL_PushEvent(&event) > 0);
slouken@6951
   267
        }
slouken@6951
   268
    } else {
slouken@6951
   269
        if (!finger) {
slouken@6951
   270
            /* This finger is already up */
slouken@6951
   271
            return 0;
slouken@6951
   272
        }
slouken@6951
   273
slouken@6951
   274
        posted = 0;
slouken@6951
   275
        if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
slouken@6951
   276
            SDL_Event event;
slouken@6951
   277
            event.tfinger.type = SDL_FINGERUP;
slouken@6951
   278
            event.tfinger.touchId =  id;
slouken@6951
   279
            event.tfinger.fingerId = fingerid;
slouken@6951
   280
            /* I don't trust the coordinates passed on fingerUp */
slouken@7191
   281
            event.tfinger.x = finger->x;
slouken@6951
   282
            event.tfinger.y = finger->y;
slouken@6951
   283
            event.tfinger.dx = 0;
slouken@6951
   284
            event.tfinger.dy = 0;
slouken@6951
   285
            event.tfinger.pressure = pressure;
slouken@6951
   286
            posted = (SDL_PushEvent(&event) > 0);
slouken@6951
   287
        }
slouken@6951
   288
slouken@6951
   289
        SDL_DelFinger(touch, fingerid);
slouken@6951
   290
    }
slouken@6951
   291
    return posted;
slouken@6951
   292
}
slouken@6951
   293
slouken@6951
   294
int
slouken@6951
   295
SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid,
slouken@6951
   296
                    float x, float y, float pressure)
slouken@6951
   297
{
slouken@6951
   298
    SDL_Touch *touch;
slouken@6951
   299
    SDL_Finger *finger;
slouken@6951
   300
    int posted;
slouken@6951
   301
    float xrel, yrel, prel;
slouken@6951
   302
slouken@6951
   303
    touch = SDL_GetTouch(id);
slouken@6951
   304
    if (!touch) {
slouken@6951
   305
        return -1;
slouken@6951
   306
    }
slouken@6951
   307
slouken@6951
   308
    finger = SDL_GetFinger(touch,fingerid);
slouken@6951
   309
    if (!finger) {
slouken@7191
   310
        return SDL_SendTouch(id, fingerid, SDL_TRUE, x, y, pressure);
slouken@6951
   311
    }
slouken@6951
   312
slouken@6951
   313
    xrel = x - finger->x;
slouken@6951
   314
    yrel = y - finger->y;
slouken@6951
   315
    prel = pressure - finger->pressure;
slouken@6951
   316
slouken@6951
   317
    /* Drop events that don't change state */
slouken@6951
   318
    if (!xrel && !yrel && !prel) {
slouken@6951
   319
#if 0
slouken@6951
   320
        printf("Touch event didn't change state - dropped!\n");
slouken@6951
   321
#endif
slouken@6951
   322
        return 0;
slouken@6951
   323
    }
slouken@6951
   324
slouken@6951
   325
    /* Update internal touch coordinates */
slouken@6951
   326
    finger->x = x;
slouken@6951
   327
    finger->y = y;
slouken@6951
   328
    finger->pressure = pressure;
slouken@7191
   329
slouken@6951
   330
    /* Post the event, if desired */
slouken@6951
   331
    posted = 0;
slouken@6951
   332
    if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
slouken@6951
   333
        SDL_Event event;
slouken@6951
   334
        event.tfinger.type = SDL_FINGERMOTION;
slouken@6951
   335
        event.tfinger.touchId = id;
slouken@6951
   336
        event.tfinger.fingerId = fingerid;
slouken@6951
   337
        event.tfinger.x = x;
slouken@6951
   338
        event.tfinger.y = y;
slouken@6951
   339
        event.tfinger.dx = xrel;
slouken@7191
   340
        event.tfinger.dy = yrel;
slouken@6951
   341
        event.tfinger.pressure = pressure;
slouken@6951
   342
        posted = (SDL_PushEvent(&event) > 0);
slouken@6951
   343
    }
slouken@6951
   344
    return posted;
slouken@6951
   345
}
slouken@6951
   346
jim@4640
   347
void
jimtla@4678
   348
SDL_DelTouch(SDL_TouchID id)
jim@4640
   349
{
slouken@6951
   350
    int i;
slouken@6951
   351
    int index = SDL_GetTouchIndex(id);
jim@4641
   352
    SDL_Touch *touch = SDL_GetTouch(id);
jim@4640
   353
jim@4640
   354
    if (!touch) {
jim@4640
   355
        return;
jim@4640
   356
    }
jim@4640
   357
slouken@6951
   358
    for (i = 0; i < touch->max_fingers; ++i) {
slouken@6951
   359
        SDL_free(touch->fingers[i]);
jim@4640
   360
    }
slouken@6951
   361
    SDL_free(touch->fingers);
jim@4640
   362
    SDL_free(touch);
jim@4640
   363
jim@4641
   364
    SDL_num_touch--;
slouken@6951
   365
    SDL_touchDevices[index] = SDL_touchDevices[SDL_num_touch];
slouken@11290
   366
slouken@11290
   367
    /* Delete this touch device for gestures */
slouken@11290
   368
    SDL_GestureDelTouch(id);
jim@4640
   369
}
jim@4640
   370
jim@4640
   371
void
jim@4640
   372
SDL_TouchQuit(void)
jim@4640
   373
{
jim@4640
   374
    int i;
jim@4640
   375
slouken@6951
   376
    for (i = SDL_num_touch; i--; ) {
slouken@6951
   377
        SDL_DelTouch(SDL_touchDevices[i]->id);
jim@4640
   378
    }
slouken@6951
   379
    SDL_assert(SDL_num_touch == 0);
jim@4640
   380
slouken@7719
   381
    SDL_free(SDL_touchDevices);
slouken@7719
   382
    SDL_touchDevices = NULL;
slouken@11290
   383
    SDL_GestureQuit();
jim@4640
   384
}
jim@4640
   385
jim@4640
   386
/* vi: set ts=4 sw=4 expandtab: */