1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 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
SDL_TouchInit(void)36 SDL_TouchInit(void)
37 {
38 return (0);
39 }
40
41 int
SDL_GetNumTouchDevices(void)42 SDL_GetNumTouchDevices(void)
43 {
44 return SDL_num_touch;
45 }
46
47 SDL_TouchID
SDL_GetTouchDevice(int index)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
SDL_GetTouchIndex(SDL_TouchID id)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 *
SDL_GetTouch(SDL_TouchID id)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
SDL_GetFingerIndex(const SDL_Touch * touch,SDL_FingerID fingerid)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 *
SDL_GetFinger(const SDL_Touch * touch,SDL_FingerID id)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
SDL_GetNumTouchFingers(SDL_TouchID touchID)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 *
SDL_GetTouchFinger(SDL_TouchID touchID,int index)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
SDL_AddTouch(SDL_TouchID touchID,const char * name)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 /* Added touch to list */
156 ++SDL_num_touch;
157
158 /* we're setting the touch properties */
159 SDL_touchDevices[index]->id = touchID;
160 SDL_touchDevices[index]->num_fingers = 0;
161 SDL_touchDevices[index]->max_fingers = 0;
162 SDL_touchDevices[index]->fingers = NULL;
163
164 /* Record this touch device for gestures */
165 /* We could do this on the fly in the gesture code if we wanted */
166 SDL_GestureAddTouch(touchID);
167
168 return index;
169 }
170
171 static int
SDL_AddFinger(SDL_Touch * touch,SDL_FingerID fingerid,float x,float y,float pressure)172 SDL_AddFinger(SDL_Touch *touch, SDL_FingerID fingerid, float x, float y, float pressure)
173 {
174 SDL_Finger *finger;
175
176 if (touch->num_fingers == touch->max_fingers) {
177 SDL_Finger **new_fingers;
178 new_fingers = (SDL_Finger **)SDL_realloc(touch->fingers, (touch->max_fingers+1)*sizeof(*touch->fingers));
179 if (!new_fingers) {
180 return SDL_OutOfMemory();
181 }
182 touch->fingers = new_fingers;
183 touch->fingers[touch->max_fingers] = (SDL_Finger *)SDL_malloc(sizeof(*finger));
184 if (!touch->fingers[touch->max_fingers]) {
185 return SDL_OutOfMemory();
186 }
187 touch->max_fingers++;
188 }
189
190 finger = touch->fingers[touch->num_fingers++];
191 finger->id = fingerid;
192 finger->x = x;
193 finger->y = y;
194 finger->pressure = pressure;
195 return 0;
196 }
197
198 static int
SDL_DelFinger(SDL_Touch * touch,SDL_FingerID fingerid)199 SDL_DelFinger(SDL_Touch* touch, SDL_FingerID fingerid)
200 {
201 SDL_Finger *temp;
202
203 int index = SDL_GetFingerIndex(touch, fingerid);
204 if (index < 0) {
205 return -1;
206 }
207
208 touch->num_fingers--;
209 temp = touch->fingers[index];
210 touch->fingers[index] = touch->fingers[touch->num_fingers];
211 touch->fingers[touch->num_fingers] = temp;
212 return 0;
213 }
214
215 int
SDL_SendTouch(SDL_TouchID id,SDL_FingerID fingerid,SDL_bool down,float x,float y,float pressure)216 SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid,
217 SDL_bool down, float x, float y, float pressure)
218 {
219 int posted;
220 SDL_Finger *finger;
221
222 SDL_Touch* touch = SDL_GetTouch(id);
223 if (!touch) {
224 return -1;
225 }
226
227 finger = SDL_GetFinger(touch, fingerid);
228 if (down) {
229 if (finger) {
230 /* This finger is already down */
231 return 0;
232 }
233
234 if (SDL_AddFinger(touch, fingerid, x, y, pressure) < 0) {
235 return 0;
236 }
237
238 posted = 0;
239 if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
240 SDL_Event event;
241 event.tfinger.type = SDL_FINGERDOWN;
242 event.tfinger.touchId = id;
243 event.tfinger.fingerId = fingerid;
244 event.tfinger.x = x;
245 event.tfinger.y = y;
246 event.tfinger.dx = 0;
247 event.tfinger.dy = 0;
248 event.tfinger.pressure = pressure;
249 posted = (SDL_PushEvent(&event) > 0);
250 }
251 } else {
252 if (!finger) {
253 /* This finger is already up */
254 return 0;
255 }
256
257 posted = 0;
258 if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
259 SDL_Event event;
260 event.tfinger.type = SDL_FINGERUP;
261 event.tfinger.touchId = id;
262 event.tfinger.fingerId = fingerid;
263 /* I don't trust the coordinates passed on fingerUp */
264 event.tfinger.x = finger->x;
265 event.tfinger.y = finger->y;
266 event.tfinger.dx = 0;
267 event.tfinger.dy = 0;
268 event.tfinger.pressure = pressure;
269 posted = (SDL_PushEvent(&event) > 0);
270 }
271
272 SDL_DelFinger(touch, fingerid);
273 }
274 return posted;
275 }
276
277 int
SDL_SendTouchMotion(SDL_TouchID id,SDL_FingerID fingerid,float x,float y,float pressure)278 SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid,
279 float x, float y, float pressure)
280 {
281 SDL_Touch *touch;
282 SDL_Finger *finger;
283 int posted;
284 float xrel, yrel, prel;
285
286 touch = SDL_GetTouch(id);
287 if (!touch) {
288 return -1;
289 }
290
291 finger = SDL_GetFinger(touch,fingerid);
292 if (!finger) {
293 return SDL_SendTouch(id, fingerid, SDL_TRUE, x, y, pressure);
294 }
295
296 xrel = x - finger->x;
297 yrel = y - finger->y;
298 prel = pressure - finger->pressure;
299
300 /* Drop events that don't change state */
301 if (!xrel && !yrel && !prel) {
302 #if 0
303 printf("Touch event didn't change state - dropped!\n");
304 #endif
305 return 0;
306 }
307
308 /* Update internal touch coordinates */
309 finger->x = x;
310 finger->y = y;
311 finger->pressure = pressure;
312
313 /* Post the event, if desired */
314 posted = 0;
315 if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
316 SDL_Event event;
317 event.tfinger.type = SDL_FINGERMOTION;
318 event.tfinger.touchId = id;
319 event.tfinger.fingerId = fingerid;
320 event.tfinger.x = x;
321 event.tfinger.y = y;
322 event.tfinger.dx = xrel;
323 event.tfinger.dy = yrel;
324 event.tfinger.pressure = pressure;
325 posted = (SDL_PushEvent(&event) > 0);
326 }
327 return posted;
328 }
329
330 void
SDL_DelTouch(SDL_TouchID id)331 SDL_DelTouch(SDL_TouchID id)
332 {
333 int i;
334 int index = SDL_GetTouchIndex(id);
335 SDL_Touch *touch = SDL_GetTouch(id);
336
337 if (!touch) {
338 return;
339 }
340
341 for (i = 0; i < touch->max_fingers; ++i) {
342 SDL_free(touch->fingers[i]);
343 }
344 SDL_free(touch->fingers);
345 SDL_free(touch);
346
347 SDL_num_touch--;
348 SDL_touchDevices[index] = SDL_touchDevices[SDL_num_touch];
349 }
350
351 void
SDL_TouchQuit(void)352 SDL_TouchQuit(void)
353 {
354 int i;
355
356 for (i = SDL_num_touch; i--; ) {
357 SDL_DelTouch(SDL_touchDevices[i]->id);
358 }
359 SDL_assert(SDL_num_touch == 0);
360
361 SDL_free(SDL_touchDevices);
362 SDL_touchDevices = NULL;
363 }
364
365 /* vi: set ts=4 sw=4 expandtab: */
366