1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Android family device touch input driver.
12 *
13 * By Thomas Fjellstrom.
14 *
15 * Based on the iOS touch input driver by Michał Cichoń.
16 *
17 * See readme.txt for copyright information.
18 */
19
20 #include "allegro5/allegro.h"
21 #include "allegro5/internal/aintern_android.h"
22 #include "allegro5/internal/aintern_display.h"
23 #include "allegro5/internal/aintern_touch_input.h"
24
25 ALLEGRO_DEBUG_CHANNEL("android")
26
27
28 /* forward declaration */
29 static void android_touch_input_handle_cancel(int id, double timestamp,
30 float x, float y, bool primary, ALLEGRO_DISPLAY *disp);
31
32
33 static ALLEGRO_TOUCH_INPUT_STATE touch_input_state;
34 static ALLEGRO_MOUSE_STATE mouse_state;
35 static ALLEGRO_TOUCH_INPUT touch_input;
36 static bool installed = false;
37
38
reset_touch_input_state(void)39 static void reset_touch_input_state(void)
40 {
41 int i;
42
43 for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; i++) {
44 touch_input_state.touches[i].id = -1;
45 }
46 }
47
48
generate_touch_input_event(unsigned int type,double timestamp,int id,float x,float y,float dx,float dy,bool primary,ALLEGRO_DISPLAY * disp)49 static void generate_touch_input_event(unsigned int type, double timestamp,
50 int id, float x, float y, float dx, float dy, bool primary,
51 ALLEGRO_DISPLAY *disp)
52 {
53 ALLEGRO_EVENT event;
54
55 bool want_touch_event = _al_event_source_needs_to_generate_event(&touch_input.es);
56 bool want_mouse_emulation_event;
57
58 if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_5_0_x) {
59 want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && al_is_mouse_installed();
60 }
61 else {
62 want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && primary && al_is_mouse_installed();
63 }
64
65 if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_NONE)
66 want_mouse_emulation_event = false;
67 else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_INCLUSIVE)
68 want_touch_event = al_is_mouse_installed() ? (want_touch_event && !primary) : want_touch_event;
69 else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_EXCLUSIVE)
70 want_touch_event = al_is_mouse_installed() ? false : want_touch_event;
71
72
73 if (!want_touch_event && !want_mouse_emulation_event)
74 return;
75
76 if (want_touch_event) {
77
78 event.touch.type = type;
79 event.touch.display = (ALLEGRO_DISPLAY*)disp;
80 event.touch.timestamp = timestamp;
81 event.touch.id = id;
82 event.touch.x = x;
83 event.touch.y = y;
84 event.touch.dx = dx;
85 event.touch.dy = dy;
86 event.touch.primary = primary;
87
88 _al_event_source_lock(&touch_input.es);
89 _al_event_source_emit_event(&touch_input.es, &event);
90 _al_event_source_unlock(&touch_input.es);
91 }
92
93 if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_NONE) {
94 mouse_state.x = (int)x;
95 mouse_state.y = (int)y;
96 if (type == ALLEGRO_EVENT_TOUCH_BEGIN)
97 mouse_state.buttons++;
98 else if (type == ALLEGRO_EVENT_TOUCH_END)
99 mouse_state.buttons--;
100
101 mouse_state.pressure = mouse_state.buttons ? 1.0 : 0.0; /* TODO */
102
103 _al_event_source_lock(&touch_input.mouse_emulation_es);
104 if (want_mouse_emulation_event) {
105
106 switch (type) {
107 case ALLEGRO_EVENT_TOUCH_BEGIN: type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN; break;
108 case ALLEGRO_EVENT_TOUCH_CANCEL:
109 case ALLEGRO_EVENT_TOUCH_END: type = ALLEGRO_EVENT_MOUSE_BUTTON_UP; break;
110 case ALLEGRO_EVENT_TOUCH_MOVE: type = ALLEGRO_EVENT_MOUSE_AXES; break;
111 }
112
113 event.mouse.type = type;
114 event.mouse.timestamp = timestamp;
115 event.mouse.display = (ALLEGRO_DISPLAY*)disp;
116 event.mouse.x = (int)x;
117 event.mouse.y = (int)y;
118 event.mouse.dx = (int)dx;
119 event.mouse.dy = (int)dy;
120 event.mouse.dz = 0;
121 event.mouse.dw = 0;
122 if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) {
123 event.mouse.button = 1;
124 }
125 else {
126 event.mouse.button = id;
127 }
128 event.mouse.pressure = mouse_state.pressure;
129
130 if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) {
131 al_set_mouse_xy(event.mouse.display, event.mouse.x, event.mouse.y);
132 }
133
134 _al_event_source_emit_event(&touch_input.mouse_emulation_es, &event);
135 }
136 _al_event_source_unlock(&touch_input.mouse_emulation_es);
137 }
138 }
139
140
init_touch_input(void)141 static bool init_touch_input(void)
142 {
143 if (installed)
144 return false;
145
146 reset_touch_input_state();
147 memset(&mouse_state, 0, sizeof(mouse_state));
148
149 _al_event_source_init(&touch_input.es);
150 _al_event_source_init(&touch_input.mouse_emulation_es);
151 touch_input.mouse_emulation_mode = ALLEGRO_MOUSE_EMULATION_TRANSPARENT;
152
153 installed = true;
154
155 return true;
156 }
157
158
exit_touch_input(void)159 static void exit_touch_input(void)
160 {
161 if (!installed)
162 return;
163
164 reset_touch_input_state();
165 memset(&mouse_state, 0, sizeof(mouse_state));
166
167 _al_event_source_free(&touch_input.es);
168 _al_event_source_free(&touch_input.mouse_emulation_es);
169
170 installed = false;
171 }
172
173
get_touch_input(void)174 static ALLEGRO_TOUCH_INPUT* get_touch_input(void)
175 {
176 return &touch_input;
177 }
178
179
get_touch_input_state(ALLEGRO_TOUCH_INPUT_STATE * ret_state)180 static void get_touch_input_state(ALLEGRO_TOUCH_INPUT_STATE *ret_state)
181 {
182 _al_event_source_lock(&touch_input.es);
183 *ret_state = touch_input_state;
184 _al_event_source_unlock(&touch_input.es);
185 }
186
187
set_mouse_emulation_mode(int mode)188 static void set_mouse_emulation_mode(int mode)
189 {
190 if (touch_input.mouse_emulation_mode != mode) {
191
192 int i;
193
194 for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) {
195
196 ALLEGRO_TOUCH_STATE* touch = touch_input_state.touches + i;
197
198 if (touch->id > 0) {
199 android_touch_input_handle_cancel(touch->id, al_get_time(),
200 touch->x, touch->y, touch->primary, touch->display);
201 }
202 }
203
204 touch_input.mouse_emulation_mode = mode;
205 }
206 }
207
208
find_free_touch_state(void)209 static ALLEGRO_TOUCH_STATE* find_free_touch_state(void)
210 {
211 int i;
212
213 for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i)
214 if (touch_input_state.touches[i].id < 0)
215 return touch_input_state.touches + i;
216
217 return NULL;
218 }
219
220
find_touch_state_with_id(int id)221 static ALLEGRO_TOUCH_STATE* find_touch_state_with_id(int id)
222 {
223 int i;
224
225 for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i)
226 if (touch_input_state.touches[i].id == id)
227 return touch_input_state.touches + i;
228
229 return NULL;
230 }
231
232
android_touch_input_handle_begin(int id,double timestamp,float x,float y,bool primary,ALLEGRO_DISPLAY * disp)233 static void android_touch_input_handle_begin(int id, double timestamp,
234 float x, float y, bool primary, ALLEGRO_DISPLAY *disp)
235 {
236 ALLEGRO_TOUCH_STATE* state = find_free_touch_state();
237 (void)primary;
238
239 if (NULL == state)
240 return;
241
242 _al_event_source_lock(&touch_input.es);
243 state->id = id;
244 state->x = x;
245 state->y = y;
246 state->dx = 0.0f;
247 state->dy = 0.0f;
248 state->primary = primary;
249 state->display = disp;
250 _al_event_source_unlock(&touch_input.es);
251
252 generate_touch_input_event(ALLEGRO_EVENT_TOUCH_BEGIN, timestamp,
253 state->id, state->x, state->y, state->dx, state->dy, state->primary,
254 disp);
255 }
256
257
android_touch_input_handle_end(int id,double timestamp,float x,float y,bool primary,ALLEGRO_DISPLAY * disp)258 static void android_touch_input_handle_end(int id, double timestamp,
259 float x, float y, bool primary, ALLEGRO_DISPLAY *disp)
260 {
261 ALLEGRO_TOUCH_STATE* state = find_touch_state_with_id(id);
262 (void)primary;
263
264 if (NULL == state)
265 return;
266
267 _al_event_source_lock(&touch_input.es);
268 state->dx = x - state->x;
269 state->dy = y - state->y;
270 state->x = x;
271 state->y = y;
272 _al_event_source_unlock(&touch_input.es);
273
274 generate_touch_input_event(ALLEGRO_EVENT_TOUCH_END, timestamp,
275 state->id, state->x, state->y, state->dx, state->dy, state->primary,
276 disp);
277
278 _al_event_source_lock(&touch_input.es);
279 state->id = -1;
280 _al_event_source_unlock(&touch_input.es);
281 }
282
283
android_touch_input_handle_move(int id,double timestamp,float x,float y,bool primary,ALLEGRO_DISPLAY * disp)284 static void android_touch_input_handle_move(int id, double timestamp,
285 float x, float y, bool primary, ALLEGRO_DISPLAY *disp)
286 {
287 ALLEGRO_TOUCH_STATE* state = find_touch_state_with_id(id);
288 (void)primary;
289
290 if (NULL == state)
291 return;
292
293 _al_event_source_lock(&touch_input.es);
294 state->dx = x - state->x;
295 state->dy = y - state->y;
296 state->x = x;
297 state->y = y;
298 _al_event_source_unlock(&touch_input.es);
299
300 generate_touch_input_event(ALLEGRO_EVENT_TOUCH_MOVE, timestamp,
301 state->id, state->x, state->y, state->dx, state->dy, state->primary,
302 disp);
303 }
304
305
android_touch_input_handle_cancel(int id,double timestamp,float x,float y,bool primary,ALLEGRO_DISPLAY * disp)306 static void android_touch_input_handle_cancel(int id, double timestamp,
307 float x, float y, bool primary, ALLEGRO_DISPLAY *disp)
308 {
309 ALLEGRO_TOUCH_STATE* state = find_touch_state_with_id(id);
310 (void)primary;
311
312 if (NULL == state)
313 return;
314
315 _al_event_source_lock(&touch_input.es);
316 state->dx = x - state->x;
317 state->dy = y - state->y;
318 state->x = x;
319 state->y = y;
320 _al_event_source_unlock(&touch_input.es);
321
322 generate_touch_input_event(ALLEGRO_EVENT_TOUCH_CANCEL, timestamp,
323 state->id, state->x, state->y, state->dx, state->dy, state->primary, disp);
324
325 _al_event_source_lock(&touch_input.es);
326 state->id = -1;
327 _al_event_source_unlock(&touch_input.es);
328 }
329
330
331 JNI_FUNC(void, TouchListener, nativeOnTouch, (JNIEnv *env, jobject obj,
332 jint id, jint action, jfloat x, jfloat y, jboolean primary))
333 {
334 (void)env;
335 (void)obj;
336
337 ALLEGRO_SYSTEM *system = al_get_system_driver();
338 ASSERT(system != NULL);
339
340 ALLEGRO_DISPLAY **dptr = _al_vector_ref(&system->displays, 0);
341 ALLEGRO_DISPLAY *display = *dptr;
342 ASSERT(display != NULL);
343
344 switch (action) {
345 case ALLEGRO_EVENT_TOUCH_BEGIN:
346 android_touch_input_handle_begin(id, al_get_time(), x, y, primary,
347 display);
348 break;
349
350 case ALLEGRO_EVENT_TOUCH_END:
351 android_touch_input_handle_end(id, al_get_time(), x, y, primary,
352 display);
353 break;
354
355 case ALLEGRO_EVENT_TOUCH_MOVE:
356 android_touch_input_handle_move(id, al_get_time(), x, y, primary,
357 display);
358 break;
359
360 case ALLEGRO_EVENT_TOUCH_CANCEL:
361 android_touch_input_handle_cancel(id, al_get_time(), x, y,
362 primary, display);
363 break;
364
365 default:
366 ALLEGRO_ERROR("unknown touch action: %i", action);
367 break;
368 }
369 }
370
371
372 /* the driver vtable */
373 #define TOUCH_INPUT_ANDROID AL_ID('A','T','I','D')
374
375 static ALLEGRO_TOUCH_INPUT_DRIVER touch_input_driver =
376 {
377 TOUCH_INPUT_ANDROID,
378 init_touch_input,
379 exit_touch_input,
380 get_touch_input,
381 get_touch_input_state,
382 set_mouse_emulation_mode,
383 NULL
384 };
385
386
_al_get_android_touch_input_driver(void)387 ALLEGRO_TOUCH_INPUT_DRIVER *_al_get_android_touch_input_driver(void)
388 {
389 return &touch_input_driver;
390 }
391
392
_al_android_mouse_get_state(ALLEGRO_MOUSE_STATE * ret_state)393 void _al_android_mouse_get_state(ALLEGRO_MOUSE_STATE *ret_state)
394 {
395 _al_event_source_lock(&touch_input.es);
396 *ret_state = mouse_state;
397 _al_event_source_unlock(&touch_input.es);
398 }
399
400
401 /* vim: set sts=3 sw=3 et: */
402