src/events/SDL_touch.c
author Ryan C. Gordon
Mon, 05 Jan 2015 01:41:42 -0500
changeset 9306 817656bd36ec
parent 8149 681eb46b8ac4
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Clang static analysis builds should use C runtime directly.

This is a little macro magic to use malloc() directly instead of SDL_malloc(),
etc, so static analysis tests that know about the C runtime can function
properly, and understand that we are dealing with heap allocations, etc.

This changed our static analysis report from 5 outstanding bugs to 30.

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