1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
3 * Copyright (C) 2011-2017 - Daniel De Matteis
4 * Copyright (C) 2012-2015 - Michael Lelli
5 * Copyright (C) 2013-2014 - Steven Crowe
6 *
7 * RetroArch is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Found-
9 * ation, either version 3 of the License, or (at your option) any later version.
10 *
11 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along with RetroArch.
16 * If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <unistd.h>
20 #include <dlfcn.h>
21
22 #include <android/keycodes.h>
23
24 #include <dynamic/dylib.h>
25 #include <retro_inline.h>
26 #include <string/stdstring.h>
27
28 #ifdef HAVE_CONFIG_H
29 #include "../../config.h"
30 #endif
31
32 #include "../../config.def.h"
33
34 #ifdef HAVE_MENU
35 #include "../../menu/menu_driver.h"
36 #endif
37
38
39 #include "../../command.h"
40 #include "../../frontend/drivers/platform_unix.h"
41 #include "../drivers_keyboard/keyboard_event_android.h"
42 #include "../../tasks/tasks_internal.h"
43 #include "../../performance_counters.h"
44
45 #include "../../configuration.h"
46 #include "../../retroarch.h"
47
48 #define MAX_TOUCH 16
49 #define MAX_NUM_KEYBOARDS 3
50 #define DEFAULT_ASENSOR_EVENT_RATE 60
51
52 /* If using an SDK lower than 14 then add missing mouse button codes */
53 #if __ANDROID_API__ < 14
54 enum {
55 AMOTION_EVENT_BUTTON_PRIMARY = 1 << 0,
56 AMOTION_EVENT_BUTTON_SECONDARY = 1 << 1,
57 AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2,
58 AMOTION_EVENT_BUTTON_BACK = 1 << 3,
59 AMOTION_EVENT_BUTTON_FORWARD = 1 << 4,
60 AMOTION_EVENT_AXIS_VSCROLL = 9,
61 AMOTION_EVENT_ACTION_HOVER_MOVE = 7,
62 AINPUT_SOURCE_STYLUS = 0x00004000
63 };
64 #endif
65
66 /* If using an SDK lower than 24 then add missing relative axis codes */
67 #ifndef AMOTION_EVENT_AXIS_RELATIVE_X
68 #define AMOTION_EVENT_AXIS_RELATIVE_X 27
69 #endif
70
71 #ifndef AMOTION_EVENT_AXIS_RELATIVE_Y
72 #define AMOTION_EVENT_AXIS_RELATIVE_Y 28
73 #endif
74
75 /* Use this to enable/disable using the touch screen as mouse */
76 #define ENABLE_TOUCH_SCREEN_MOUSE 1
77
78 #define AKEYCODE_ASSIST 219
79
80 #define LAST_KEYCODE AKEYCODE_ASSIST
81
82 #define MAX_KEYS ((LAST_KEYCODE + 7) / 8)
83
84 /* First ports are used to keep track of gamepad states.
85 * Last port is used for keyboard state */
86 static uint8_t android_key_state[DEFAULT_MAX_PADS + 1][MAX_KEYS];
87
88 #define ANDROID_KEYBOARD_PORT_INPUT_PRESSED(binds, id) (BIT_GET(android_key_state[ANDROID_KEYBOARD_PORT], rarch_keysym_lut[(binds)[(id)].key]))
89
90 #define ANDROID_KEYBOARD_INPUT_PRESSED(key) (BIT_GET(android_key_state[0], (key)))
91
android_keyboard_state_get(unsigned port)92 uint8_t *android_keyboard_state_get(unsigned port)
93 {
94 return android_key_state[port];
95 }
96
android_keyboard_free(void)97 static void android_keyboard_free(void)
98 {
99 unsigned i, j;
100
101 for (i = 0; i < DEFAULT_MAX_PADS; i++)
102 for (j = 0; j < MAX_KEYS; j++)
103 android_key_state[i][j] = 0;
104 }
105
106 /* TODO/FIXME -
107 * fix game focus toggle */
108
109 typedef struct
110 {
111 float x;
112 float y;
113 float z;
114 } sensor_t;
115
116 struct input_pointer
117 {
118 int16_t x, y;
119 int16_t full_x, full_y;
120 };
121
122 static int pad_id1 = -1;
123 static int pad_id2 = -1;
124 static int kbd_id[MAX_NUM_KEYBOARDS];
125 static int kbd_num = 0;
126
127 enum
128 {
129 AXIS_X = 0,
130 AXIS_Y = 1,
131 AXIS_Z = 11,
132 AXIS_RZ = 14,
133 AXIS_HAT_X = 15,
134 AXIS_HAT_Y = 16,
135 AXIS_LTRIGGER = 17,
136 AXIS_RTRIGGER = 18,
137 AXIS_GAS = 22,
138 AXIS_BRAKE = 23
139 };
140
141 typedef struct state_device
142 {
143 int id;
144 int port;
145 char name[256];
146 } state_device_t;
147
148 typedef struct android_input
149 {
150 int64_t quick_tap_time;
151 state_device_t pad_states[MAX_USERS]; /* int alignment */
152 int mouse_x_delta, mouse_y_delta;
153 int mouse_l, mouse_r, mouse_m, mouse_wu, mouse_wd;
154 unsigned pads_connected;
155 unsigned pointer_count;
156 sensor_t accelerometer_state; /* float alignment */
157 sensor_t gyroscope_state; /* float alignment */
158 float mouse_x_prev, mouse_y_prev;
159 struct input_pointer pointer[MAX_TOUCH]; /* int16_t alignment */
160 char device_model[256];
161 } android_input_t;
162
163 static void frontend_android_get_version_sdk(int32_t *sdk);
164 static void frontend_android_get_name(char *s, size_t len);
165
166 bool (*engine_lookup_name)(char *buf,
167 int *vendorId, int *productId, size_t size, int id);
168 void (*engine_handle_dpad)(struct android_app *, AInputEvent*, int, int);
169
170 static bool android_input_set_sensor_state(void *data, unsigned port,
171 enum retro_sensor_action action, unsigned event_rate);
172
173 extern float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
174 int32_t axis, size_t pointer_idx);
175
176 static typeof(AMotionEvent_getAxisValue) *p_AMotionEvent_getAxisValue;
177
178 #define AMotionEvent_getAxisValue (*p_AMotionEvent_getAxisValue)
179
180 extern int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event);
181
182 static typeof(AMotionEvent_getButtonState) *p_AMotionEvent_getButtonState;
183
184 #define AMotionEvent_getButtonState (*p_AMotionEvent_getButtonState)
185
186 #ifdef HAVE_DYNAMIC
187 static void *libandroid_handle;
188 #endif
189
android_input_lookup_name_prekitkat(char * buf,int * vendorId,int * productId,size_t size,int id)190 static bool android_input_lookup_name_prekitkat(char *buf,
191 int *vendorId, int *productId, size_t size, int id)
192 {
193 jobject name = NULL;
194 jmethodID getName = NULL;
195 jobject device = NULL;
196 jmethodID method = NULL;
197 jclass class = 0;
198 const char *str = NULL;
199 JNIEnv *env = (JNIEnv*)jni_thread_getenv();
200
201 if (!env)
202 return false;
203
204 FIND_CLASS(env, class, "android/view/InputDevice");
205 if (!class)
206 return false;
207
208 GET_STATIC_METHOD_ID(env, method, class, "getDevice",
209 "(I)Landroid/view/InputDevice;");
210 if (!method)
211 return false;
212
213 CALL_OBJ_STATIC_METHOD_PARAM(env, device, class, method, (jint)id);
214 if (!device)
215 return false;
216
217 GET_METHOD_ID(env, getName, class, "getName", "()Ljava/lang/String;");
218 if (!getName)
219 return false;
220
221 CALL_OBJ_METHOD(env, name, device, getName);
222 if (!name)
223 return false;
224
225 buf[0] = '\0';
226
227 str = (*env)->GetStringUTFChars(env, name, 0);
228 if (str)
229 strlcpy(buf, str, size);
230 (*env)->ReleaseStringUTFChars(env, name, str);
231
232 return true;
233 }
234
android_input_lookup_name(char * buf,int * vendorId,int * productId,size_t size,int id)235 static bool android_input_lookup_name(char *buf,
236 int *vendorId, int *productId, size_t size, int id)
237 {
238 jmethodID getVendorId = NULL;
239 jmethodID getProductId = NULL;
240 jmethodID getName = NULL;
241 jobject device = NULL;
242 jobject name = NULL;
243 jmethodID method = NULL;
244 jclass class = NULL;
245 const char *str = NULL;
246 JNIEnv *env = (JNIEnv*)jni_thread_getenv();
247
248 if (!env)
249 return false;
250
251 FIND_CLASS(env, class, "android/view/InputDevice");
252 if (!class)
253 return false;
254
255 GET_STATIC_METHOD_ID(env, method, class, "getDevice",
256 "(I)Landroid/view/InputDevice;");
257 if (!method)
258 return false;
259
260 CALL_OBJ_STATIC_METHOD_PARAM(env, device, class, method, (jint)id);
261 if (!device)
262 return false;
263
264 GET_METHOD_ID(env, getName, class, "getName", "()Ljava/lang/String;");
265 if (!getName)
266 return false;
267
268 CALL_OBJ_METHOD(env, name, device, getName);
269 if (!name)
270 return false;
271
272 buf[0] = '\0';
273
274 str = (*env)->GetStringUTFChars(env, name, 0);
275 if (str)
276 strlcpy(buf, str, size);
277 (*env)->ReleaseStringUTFChars(env, name, str);
278
279 GET_METHOD_ID(env, getVendorId, class, "getVendorId", "()I");
280 if (!getVendorId)
281 return false;
282
283 CALL_INT_METHOD(env, *vendorId, device, getVendorId);
284
285 GET_METHOD_ID(env, getProductId, class, "getProductId", "()I");
286 if (!getProductId)
287 return false;
288
289 *productId = 0;
290 CALL_INT_METHOD(env, *productId, device, getProductId);
291
292 return true;
293 }
294
android_input_poll_main_cmd(void)295 static void android_input_poll_main_cmd(void)
296 {
297 int8_t cmd;
298 struct android_app *android_app = (struct android_app*)g_android;
299
300 if (read(android_app->msgread, &cmd, sizeof(cmd)) != sizeof(cmd))
301 cmd = -1;
302
303 switch (cmd)
304 {
305 case APP_CMD_REINIT_DONE:
306 slock_lock(android_app->mutex);
307
308 android_app->reinitRequested = 0;
309
310 scond_broadcast(android_app->cond);
311 slock_unlock(android_app->mutex);
312 break;
313
314 case APP_CMD_INPUT_CHANGED:
315 slock_lock(android_app->mutex);
316
317 if (android_app->inputQueue)
318 AInputQueue_detachLooper(android_app->inputQueue);
319
320 android_app->inputQueue = android_app->pendingInputQueue;
321
322 if (android_app->inputQueue)
323 AInputQueue_attachLooper(android_app->inputQueue,
324 android_app->looper, LOOPER_ID_INPUT, NULL,
325 NULL);
326
327 scond_broadcast(android_app->cond);
328 slock_unlock(android_app->mutex);
329
330 break;
331
332 case APP_CMD_INIT_WINDOW:
333 slock_lock(android_app->mutex);
334 android_app->window = android_app->pendingWindow;
335 android_app->reinitRequested = 1;
336 scond_broadcast(android_app->cond);
337 slock_unlock(android_app->mutex);
338
339 break;
340
341 case APP_CMD_SAVE_STATE:
342 slock_lock(android_app->mutex);
343 android_app->stateSaved = 1;
344 scond_broadcast(android_app->cond);
345 slock_unlock(android_app->mutex);
346 break;
347
348 case APP_CMD_RESUME:
349 case APP_CMD_START:
350 case APP_CMD_PAUSE:
351 case APP_CMD_STOP:
352 slock_lock(android_app->mutex);
353 android_app->activityState = cmd;
354 scond_broadcast(android_app->cond);
355 slock_unlock(android_app->mutex);
356 break;
357
358 case APP_CMD_CONFIG_CHANGED:
359 AConfiguration_fromAssetManager(android_app->config,
360 android_app->activity->assetManager);
361 break;
362 case APP_CMD_TERM_WINDOW:
363 slock_lock(android_app->mutex);
364
365 /* The window is being hidden or closed, clean it up. */
366 /* terminate display/EGL context here */
367
368 android_app->window = NULL;
369 scond_broadcast(android_app->cond);
370 slock_unlock(android_app->mutex);
371 break;
372
373 case APP_CMD_GAINED_FOCUS:
374 {
375 bool boolean = false;
376 bool enable_accelerometer = (android_app->sensor_state_mask &
377 (UINT64_C(1) << RETRO_SENSOR_ACCELEROMETER_ENABLE)) &&
378 !android_app->accelerometerSensor;
379 bool enable_gyroscope = (android_app->sensor_state_mask &
380 (UINT64_C(1) << RETRO_SENSOR_GYROSCOPE_ENABLE)) &&
381 !android_app->gyroscopeSensor;
382
383 rarch_ctl(RARCH_CTL_SET_PAUSED, &boolean);
384 rarch_ctl(RARCH_CTL_SET_IDLE, &boolean);
385 video_driver_unset_stub_frame();
386
387 if (enable_accelerometer)
388 input_sensor_set_state(0,
389 RETRO_SENSOR_ACCELEROMETER_ENABLE,
390 android_app->accelerometer_event_rate);
391
392 if (enable_gyroscope)
393 input_sensor_set_state(0,
394 RETRO_SENSOR_GYROSCOPE_ENABLE,
395 android_app->gyroscope_event_rate);
396 }
397 slock_lock(android_app->mutex);
398 android_app->unfocused = false;
399 scond_broadcast(android_app->cond);
400 slock_unlock(android_app->mutex);
401 break;
402 case APP_CMD_LOST_FOCUS:
403 {
404 bool boolean = true;
405 bool disable_accelerometer = (android_app->sensor_state_mask &
406 (UINT64_C(1) << RETRO_SENSOR_ACCELEROMETER_ENABLE)) &&
407 android_app->accelerometerSensor;
408 bool disable_gyroscope = (android_app->sensor_state_mask &
409 (UINT64_C(1) << RETRO_SENSOR_GYROSCOPE_ENABLE)) &&
410 android_app->gyroscopeSensor;
411
412 rarch_ctl(RARCH_CTL_SET_PAUSED, &boolean);
413 rarch_ctl(RARCH_CTL_SET_IDLE, &boolean);
414 video_driver_set_stub_frame();
415
416 /* Avoid draining battery while app is not being used. */
417 if (disable_accelerometer)
418 input_sensor_set_state(0,
419 RETRO_SENSOR_ACCELEROMETER_DISABLE,
420 android_app->accelerometer_event_rate);
421
422 if (disable_gyroscope)
423 input_sensor_set_state(0,
424 RETRO_SENSOR_GYROSCOPE_DISABLE,
425 android_app->gyroscope_event_rate);
426 }
427 slock_lock(android_app->mutex);
428 android_app->unfocused = true;
429 scond_broadcast(android_app->cond);
430 slock_unlock(android_app->mutex);
431 break;
432
433 case APP_CMD_DESTROY:
434 android_app->destroyRequested = 1;
435 break;
436 case APP_CMD_VIBRATE_KEYPRESS:
437 {
438 JNIEnv *env = (JNIEnv*)jni_thread_getenv();
439
440 if (env && g_android && g_android->doVibrate)
441 {
442 CALL_VOID_METHOD_PARAM(env, g_android->activity->clazz,
443 g_android->doVibrate, (jint)-1, (jint)RETRO_RUMBLE_STRONG, (jint)255, (jint)1);
444 }
445 break;
446 }
447 }
448 }
449
engine_handle_dpad_default(struct android_app * android,AInputEvent * event,int port,int source)450 static void engine_handle_dpad_default(struct android_app *android,
451 AInputEvent *event, int port, int source)
452 {
453 size_t motion_ptr = AMotionEvent_getAction(event) >>
454 AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
455 float x = AMotionEvent_getX(event, motion_ptr);
456 float y = AMotionEvent_getY(event, motion_ptr);
457
458 android->analog_state[port][0] = (int16_t)(x * 32767.0f);
459 android->analog_state[port][1] = (int16_t)(y * 32767.0f);
460 }
461
462 #ifdef HAVE_DYNAMIC
engine_handle_dpad_getaxisvalue(struct android_app * android,AInputEvent * event,int port,int source)463 static void engine_handle_dpad_getaxisvalue(struct android_app *android,
464 AInputEvent *event, int port, int source)
465 {
466 size_t motion_ptr = AMotionEvent_getAction(event) >>
467 AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
468 float x = AMotionEvent_getAxisValue(event, AXIS_X, motion_ptr);
469 float y = AMotionEvent_getAxisValue(event, AXIS_Y, motion_ptr);
470 float z = AMotionEvent_getAxisValue(event, AXIS_Z, motion_ptr);
471 float rz = AMotionEvent_getAxisValue(event, AXIS_RZ, motion_ptr);
472 float hatx = AMotionEvent_getAxisValue(event, AXIS_HAT_X, motion_ptr);
473 float haty = AMotionEvent_getAxisValue(event, AXIS_HAT_Y, motion_ptr);
474 float ltrig = AMotionEvent_getAxisValue(event, AXIS_LTRIGGER, motion_ptr);
475 float rtrig = AMotionEvent_getAxisValue(event, AXIS_RTRIGGER, motion_ptr);
476 float brake = AMotionEvent_getAxisValue(event, AXIS_BRAKE, motion_ptr);
477 float gas = AMotionEvent_getAxisValue(event, AXIS_GAS, motion_ptr);
478
479 android->hat_state[port][0] = (int)hatx;
480 android->hat_state[port][1] = (int)haty;
481
482 /* XXX: this could be a loop instead, but do we really want to
483 * loop through every axis? */
484 android->analog_state[port][0] = (int16_t)(x * 32767.0f);
485 android->analog_state[port][1] = (int16_t)(y * 32767.0f);
486 android->analog_state[port][2] = (int16_t)(z * 32767.0f);
487 android->analog_state[port][3] = (int16_t)(rz * 32767.0f);
488 #if 0
489 android->analog_state[port][4] = (int16_t)(hatx * 32767.0f);
490 android->analog_state[port][5] = (int16_t)(haty * 32767.0f);
491 #endif
492 android->analog_state[port][6] = (int16_t)(ltrig * 32767.0f);
493 android->analog_state[port][7] = (int16_t)(rtrig * 32767.0f);
494 android->analog_state[port][8] = (int16_t)(brake * 32767.0f);
495 android->analog_state[port][9] = (int16_t)(gas * 32767.0f);
496 }
497 #endif
498
android_input_init_handle(void)499 static bool android_input_init_handle(void)
500 {
501 #ifdef HAVE_DYNAMIC
502 if (libandroid_handle != NULL) /* already initialized */
503 return true;
504 #if defined (ANDROID_AARCH64) || defined(ANDROID_X64)
505 if ((libandroid_handle = dlopen("/system/lib64/libandroid.so",
506 RTLD_LOCAL | RTLD_LAZY)) == 0)
507 return false;
508 #else
509 if ((libandroid_handle = dlopen("/system/lib/libandroid.so",
510 RTLD_LOCAL | RTLD_LAZY)) == 0)
511 return false;
512 #endif
513
514 if ((p_AMotionEvent_getAxisValue = dlsym(RTLD_DEFAULT,
515 "AMotionEvent_getAxisValue")))
516 engine_handle_dpad = engine_handle_dpad_getaxisvalue;
517
518 p_AMotionEvent_getButtonState = dlsym(RTLD_DEFAULT,
519 "AMotionEvent_getButtonState");
520 #endif
521
522 pad_id1 = -1;
523 pad_id2 = -1;
524
525 return true;
526 }
527
android_input_init(const char * joypad_driver)528 static void *android_input_init(const char *joypad_driver)
529 {
530 int32_t sdk;
531 struct android_app *android_app = (struct android_app*)g_android;
532 android_input_t *android = (android_input_t*)
533 calloc(1, sizeof(*android));
534
535 if (!android)
536 return NULL;
537
538 android->pads_connected = 0;
539 android->quick_tap_time = 0;
540
541 input_keymaps_init_keyboard_lut(rarch_key_map_android);
542
543 frontend_android_get_version_sdk(&sdk);
544
545 if (sdk >= 19)
546 engine_lookup_name = android_input_lookup_name;
547 else
548 engine_lookup_name = android_input_lookup_name_prekitkat;
549
550 engine_handle_dpad = engine_handle_dpad_default;
551
552 if (!android_input_init_handle())
553 {
554 RARCH_WARN("Unable to open libandroid.so\n");
555 }
556
557 frontend_android_get_name(android->device_model,
558 sizeof(android->device_model));
559
560 android_app->input_alive = true;
561
562 return android;
563 }
564
android_check_quick_tap(android_input_t * android)565 static int android_check_quick_tap(android_input_t *android)
566 {
567 /* Check if the touch screen has been been quick tapped
568 * and then not touched again for 200ms
569 * If so then return true and deactivate quick tap timer */
570 retro_time_t now = cpu_features_get_time_usec();
571 if (android->quick_tap_time &&
572 (now / 1000 - android->quick_tap_time / 1000000) >= 200)
573 {
574 android->quick_tap_time = 0;
575 return 1;
576 }
577
578 return 0;
579 }
580
android_mouse_calculate_deltas(android_input_t * android,AInputEvent * event,size_t motion_ptr)581 static INLINE void android_mouse_calculate_deltas(android_input_t *android,
582 AInputEvent *event,size_t motion_ptr)
583 {
584 /* Adjust mouse speed based on ratio
585 * between core resolution and system resolution */
586 float x = 0, y = 0;
587 float x_scale = 1;
588 float y_scale = 1;
589 struct retro_system_av_info *av_info = video_viewport_get_system_av_info();
590
591 if (av_info)
592 {
593 video_viewport_t *custom_vp = video_viewport_get_custom();
594 const struct retro_game_geometry *geom = (const struct retro_game_geometry*)&av_info->geometry;
595 x_scale = 2 * (float)geom->base_width / (float)custom_vp->width;
596 y_scale = 2 * (float)geom->base_height / (float)custom_vp->height;
597 }
598
599 /* This axis is only available on Android Nougat and on
600 * Android devices with NVIDIA extensions */
601 if (p_AMotionEvent_getAxisValue)
602 {
603 x = AMotionEvent_getAxisValue(event,AMOTION_EVENT_AXIS_RELATIVE_X,
604 motion_ptr);
605 y = AMotionEvent_getAxisValue(event,AMOTION_EVENT_AXIS_RELATIVE_Y,
606 motion_ptr);
607 }
608
609 /* If AXIS_RELATIVE had 0 values it might be because we're not
610 * running Android Nougat or on a device
611 * with NVIDIA extension, so re-calculate deltas based on
612 * AXIS_X and AXIS_Y. This has limitations
613 * compared to AXIS_RELATIVE because once the Android mouse cursor
614 * hits the edge of the screen it is
615 * not possible to move the in-game mouse any further in that direction.
616 */
617 if (!x && !y)
618 {
619 x = (AMotionEvent_getX(event, motion_ptr) - android->mouse_x_prev);
620 y = (AMotionEvent_getY(event, motion_ptr) - android->mouse_y_prev);
621 android->mouse_x_prev = AMotionEvent_getX(event, motion_ptr);
622 android->mouse_y_prev = AMotionEvent_getY(event, motion_ptr);
623 }
624
625 android->mouse_x_delta = ceil(x) * x_scale;
626 android->mouse_y_delta = ceil(y) * y_scale;
627 }
628
android_input_poll_event_type_motion(android_input_t * android,AInputEvent * event,int port,int source,bool vibrate_on_keypress)629 static INLINE void android_input_poll_event_type_motion(
630 android_input_t *android, AInputEvent *event,
631 int port, int source, bool vibrate_on_keypress)
632 {
633 int btn;
634 int getaction = AMotionEvent_getAction(event);
635 int action = getaction & AMOTION_EVENT_ACTION_MASK;
636 size_t motion_ptr = getaction >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
637 bool keyup = (
638 action == AMOTION_EVENT_ACTION_UP ||
639 action == AMOTION_EVENT_ACTION_CANCEL ||
640 action == AMOTION_EVENT_ACTION_POINTER_UP) ||
641 (source == AINPUT_SOURCE_MOUSE &&
642 action != AMOTION_EVENT_ACTION_DOWN);
643
644 /* If source is mouse then calculate button state
645 * and mouse deltas and don't process as touchscreen event */
646 if (source == AINPUT_SOURCE_MOUSE)
647 {
648 /* getButtonState requires API level 14 */
649 if (p_AMotionEvent_getButtonState)
650 {
651 btn = (int)AMotionEvent_getButtonState(event);
652
653 android->mouse_l = (btn & AMOTION_EVENT_BUTTON_PRIMARY);
654 android->mouse_r = (btn & AMOTION_EVENT_BUTTON_SECONDARY);
655 android->mouse_m = (btn & AMOTION_EVENT_BUTTON_TERTIARY);
656
657 btn = (int)AMotionEvent_getAxisValue(event,
658 AMOTION_EVENT_AXIS_VSCROLL, motion_ptr);
659
660 if (btn > 0)
661 android->mouse_wu = btn;
662 else if (btn < 0)
663 android->mouse_wd = btn;
664 }
665 else
666 {
667 /* If getButtonState is not available
668 * then treat all MotionEvent.ACTION_DOWN as left button presses */
669 if (action == AMOTION_EVENT_ACTION_DOWN)
670 android->mouse_l = 1;
671 if (action == AMOTION_EVENT_ACTION_UP)
672 android->mouse_l = 0;
673 }
674
675 android_mouse_calculate_deltas(android,event,motion_ptr);
676
677 return;
678 }
679
680 if (keyup && motion_ptr < MAX_TOUCH)
681 {
682 if (action == AMOTION_EVENT_ACTION_UP && ENABLE_TOUCH_SCREEN_MOUSE)
683 {
684 /* If touchscreen was pressed for less than 200ms
685 * then register time stamp of a quick tap */
686 if ((AMotionEvent_getEventTime(event)-AMotionEvent_getDownTime(event))/1000000 < 200)
687 android->quick_tap_time = AMotionEvent_getEventTime(event);
688 android->mouse_l = 0;
689 }
690
691 memmove(android->pointer + motion_ptr,
692 android->pointer + motion_ptr + 1,
693 (MAX_TOUCH - motion_ptr - 1) * sizeof(struct input_pointer));
694 if (android->pointer_count > 0)
695 android->pointer_count--;
696 }
697 else
698 {
699 int pointer_max = MIN(
700 AMotionEvent_getPointerCount(event), MAX_TOUCH);
701
702 if (vibrate_on_keypress && action != AMOTION_EVENT_ACTION_MOVE)
703 android_app_write_cmd(g_android, APP_CMD_VIBRATE_KEYPRESS);
704
705 if (action == AMOTION_EVENT_ACTION_DOWN && ENABLE_TOUCH_SCREEN_MOUSE)
706 {
707 /* When touch screen is pressed, set mouse
708 * previous position to current position
709 * before starting to calculate mouse movement deltas. */
710 android->mouse_x_prev = AMotionEvent_getX(event, motion_ptr);
711 android->mouse_y_prev = AMotionEvent_getY(event, motion_ptr);
712
713 /* If another touch happened within 200ms after a quick tap
714 * then cancel the quick tap and register left mouse button
715 * as being held down */
716 if ((AMotionEvent_getEventTime(event) - android->quick_tap_time)/1000000 < 200)
717 {
718 android->quick_tap_time = 0;
719 android->mouse_l = 1;
720 }
721 }
722
723 if (( action == AMOTION_EVENT_ACTION_MOVE
724 || action == AMOTION_EVENT_ACTION_HOVER_MOVE)
725 && ENABLE_TOUCH_SCREEN_MOUSE)
726 android_mouse_calculate_deltas(android,event,motion_ptr);
727
728 for (motion_ptr = 0; motion_ptr < pointer_max; motion_ptr++)
729 {
730 struct video_viewport vp;
731 float x = AMotionEvent_getX(event, motion_ptr);
732 float y = AMotionEvent_getY(event, motion_ptr);
733
734 vp.x = 0;
735 vp.y = 0;
736 vp.width = 0;
737 vp.height = 0;
738 vp.full_width = 0;
739 vp.full_height = 0;
740
741 video_driver_translate_coord_viewport_wrap(
742 &vp,
743 x, y,
744 &android->pointer[motion_ptr].x,
745 &android->pointer[motion_ptr].y,
746 &android->pointer[motion_ptr].full_x,
747 &android->pointer[motion_ptr].full_y);
748
749 android->pointer_count = MAX(
750 android->pointer_count,
751 motion_ptr + 1);
752 }
753 }
754
755 /* If more than one pointer detected
756 * then count it as a mouse right click */
757 if (ENABLE_TOUCH_SCREEN_MOUSE)
758 android->mouse_r = (android->pointer_count == 2);
759 }
760
android_is_keyboard_id(int id)761 static bool android_is_keyboard_id(int id)
762 {
763 unsigned i;
764 for (i = 0; i < (unsigned)kbd_num; i++)
765 if (id == kbd_id[i])
766 return true;
767
768 return false;
769 }
770
android_input_poll_event_type_keyboard(AInputEvent * event,int keycode,int * handled)771 static INLINE void android_input_poll_event_type_keyboard(
772 AInputEvent *event, int keycode, int *handled)
773 {
774 int keydown = (AKeyEvent_getAction(event)
775 == AKEY_EVENT_ACTION_DOWN);
776 unsigned keyboardcode = input_keymaps_translate_keysym_to_rk(keycode);
777 /* Set keyboard modifier based on shift,ctrl and alt state */
778 uint16_t mod = 0;
779 int meta = AKeyEvent_getMetaState(event);
780
781 if (meta & AMETA_ALT_ON)
782 mod |= RETROKMOD_ALT;
783 if (meta & AMETA_CTRL_ON)
784 mod |= RETROKMOD_CTRL;
785 if (meta & AMETA_SHIFT_ON)
786 mod |= RETROKMOD_SHIFT;
787
788 input_keyboard_event(keydown, keyboardcode,
789 keyboardcode, mod, RETRO_DEVICE_KEYBOARD);
790
791 if ((keycode == AKEYCODE_VOLUME_UP || keycode == AKEYCODE_VOLUME_DOWN))
792 *handled = 0;
793 }
794
android_input_poll_event_type_key(struct android_app * android_app,AInputEvent * event,int port,int keycode,int source,int type_event,int * handled)795 static INLINE void android_input_poll_event_type_key(
796 struct android_app *android_app,
797 AInputEvent *event, int port, int keycode, int source,
798 int type_event, int *handled)
799 {
800 uint8_t *buf = android_key_state[port];
801 int action = AKeyEvent_getAction(event);
802
803 /* some controllers send both the up and down events at once
804 * when the button is released for "special" buttons, like menu buttons
805 * work around that by only using down events for meta keys (which get
806 * cleared every poll anyway)
807 */
808 switch (action)
809 {
810 case AKEY_EVENT_ACTION_UP:
811 BIT_CLEAR(buf, keycode);
812 break;
813 case AKEY_EVENT_ACTION_DOWN:
814 BIT_SET(buf, keycode);
815 break;
816 }
817
818 if ((keycode == AKEYCODE_VOLUME_UP || keycode == AKEYCODE_VOLUME_DOWN))
819 *handled = 0;
820 }
821
android_input_get_id_port(android_input_t * android,int id,int source)822 static int android_input_get_id_port(android_input_t *android, int id,
823 int source)
824 {
825 unsigned i;
826 int ret = -1;
827 if (source & (AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE |
828 AINPUT_SOURCE_TOUCHPAD))
829 ret = 0; /* touch overlay is always user 1 */
830
831 for (i = 0; i < android->pads_connected; i++)
832 {
833 if (android->pad_states[i].id == id)
834 {
835 ret = i;
836 break;
837 }
838 }
839
840 return ret;
841 }
842
843 #ifdef HAVE_DYNAMIC
844 /* Returns the index inside android->pad_state */
android_input_get_id_index_from_name(android_input_t * android,const char * name)845 static int android_input_get_id_index_from_name(android_input_t *android,
846 const char *name)
847 {
848 int i;
849 for (i = 0; i < android->pads_connected; i++)
850 {
851 if (string_is_equal(name, android->pad_states[i].name))
852 return i;
853 }
854
855 return -1;
856 }
857 #endif
858
handle_hotplug(android_input_t * android,struct android_app * android_app,int * port,int id,int source)859 static void handle_hotplug(android_input_t *android,
860 struct android_app *android_app, int *port, int id,
861 int source)
862 {
863 char device_name[256];
864 char name_buf[256];
865 int vendorId = 0;
866 int productId = 0;
867 const char *device_model = android->device_model;
868
869 device_name[0] = name_buf[0] = '\0';
870
871 if (!engine_lookup_name(device_name, &vendorId,
872 &productId, sizeof(device_name), id))
873 return;
874
875 /* FIXME - per-device hacks for NVidia Shield, Xperia Play and
876 * similar devices
877 *
878 * These hacks depend on autoconf, but can work with user
879 * created autoconfs properly
880 */
881
882 /* NVIDIA Shield Console
883 * This is the most complicated example, the built-in controller
884 * has an extra button that can't be used and a remote.
885 *
886 * We map the remote for navigation and overwrite whenever a
887 * real controller is connected.
888 * Also group the NVIDIA button on the controller with the
889 * main controller inputs so it's usable. It's mapped to
890 * menu by default
891 *
892 * The NVIDIA button is identified as "Virtual" device when first
893 * pressed. CEC remote input is also identified as "Virtual" device.
894 * If a virtual device is detected before a controller then it will
895 * be assigned to port 0 as "SHIELD Virtual Controller". When a real
896 * controller is detected it will overwrite the virtual controller
897 * and be grouped with the NVIDIA button of the virtual device.
898 *
899 */
900 if (strstr(device_model, "SHIELD Android TV") && (
901 strstr(device_name, "Virtual") ||
902 strstr(device_name, "NVIDIA Corporation NVIDIA Controller v01.0")))
903 {
904 /* only use the hack if the device is one of the built-in devices */
905 RARCH_LOG("Special Device Detected: %s\n", device_model);
906 {
907 #if 0
908 RARCH_LOG("- Pads Mapped: %d\n- Device Name: %s\n- IDS: %d, %d, %d",
909 android->pads_connected, device_name, id, pad_id1, pad_id2);
910 #endif
911 /* Remove the remote or virtual controller device if it is mapped */
912 if (strstr(android->pad_states[0].name,"SHIELD Remote") ||
913 strstr(android->pad_states[0].name,"SHIELD Virtual Controller"))
914 {
915 pad_id1 = -1;
916 pad_id2 = -1;
917 android->pads_connected = 0;
918 *port = 0;
919 strlcpy(name_buf, device_name, sizeof(name_buf));
920 }
921
922 /* if the actual controller has not been mapped yet,
923 * then configure Virtual device for now */
924 if (strstr(device_name, "Virtual") && android->pads_connected==0)
925 strlcpy (name_buf, "SHIELD Virtual Controller", sizeof(name_buf));
926 else
927 strlcpy (name_buf, "NVIDIA SHIELD Controller", sizeof(name_buf));
928
929 /* apply the hack only for the first controller
930 * store the id for later use
931 */
932 if (strstr(device_name, "NVIDIA Corporation NVIDIA Controller v01.0")
933 && android->pads_connected==0)
934 pad_id1 = id;
935 else if (strstr(device_name, "Virtual") && pad_id1 != -1)
936 {
937 id = pad_id1;
938 return;
939 }
940 }
941 }
942
943 else if (strstr(device_model, "SHIELD") && (
944 strstr(device_name, "Virtual") || strstr(device_name, "gpio") ||
945 strstr(device_name, "NVIDIA Corporation NVIDIA Controller v01.01") ||
946 strstr(device_name, "NVIDIA Corporation NVIDIA Controller v01.02")))
947 {
948 /* only use the hack if the device is one of the built-in devices */
949 RARCH_LOG("Special Device Detected: %s\n", device_model);
950 {
951 if ( pad_id1 < 0 )
952 pad_id1 = id;
953 else
954 pad_id2 = id;
955
956 if ( pad_id2 > 0)
957 return;
958 strlcpy (name_buf, "NVIDIA SHIELD Portable", sizeof(name_buf));
959 }
960 }
961
962 else if (strstr(device_model, "SHIELD") && (
963 strstr(device_name, "Virtual") || strstr(device_name, "gpio") ||
964 strstr(device_name, "NVIDIA Corporation NVIDIA Controller v01.03")))
965 {
966 /* only use the hack if the device is one of the built-in devices */
967 RARCH_LOG("Special Device Detected: %s\n", device_model);
968 {
969 if (strstr(device_name, "NVIDIA Corporation NVIDIA Controller v01.03")
970 && android->pads_connected==0)
971 pad_id1 = id;
972 else if (strstr(device_name, "Virtual") || strstr(device_name, "gpio"))
973 {
974 id = pad_id1;
975 return;
976 }
977 strlcpy (name_buf, "NVIDIA SHIELD Gamepad", sizeof(name_buf));
978 }
979 }
980
981 /* Other ATV Devices
982 * Add other common ATV devices that will follow the Android
983 * Gaempad convention as "Android Gamepad"
984 */
985 /* to-do: add DS4 on Bravia ATV */
986 else if (strstr(device_name, "NVIDIA"))
987 strlcpy (name_buf, "Android Gamepad", sizeof(name_buf));
988
989 /* GPD XD
990 * This is a simple hack, basically groups the "back"
991 * button with the rest of the gamepad
992 */
993 else if (strstr(device_model, "XD") && (
994 strstr(device_name, "Virtual") || strstr(device_name, "rk29-keypad") ||
995 strstr(device_name,"Playstation3") || strstr(device_name,"XBOX")))
996 {
997 /* only use the hack if the device is one of the built-in devices */
998 RARCH_LOG("Special Device Detected: %s\n", device_model);
999 {
1000 if ( pad_id1 < 0 )
1001 pad_id1 = id;
1002 else
1003 pad_id2 = id;
1004
1005 if ( pad_id2 > 0)
1006 return;
1007
1008 strlcpy (name_buf, "GPD XD", sizeof(name_buf));
1009 *port = 0;
1010 }
1011 }
1012
1013 /* XPERIA Play
1014 * This device is composed of two hid devices
1015 * We make it look like one device
1016 */
1017 else if(
1018 (
1019 string_starts_with_size(device_model, "R800", STRLEN_CONST("R800")) ||
1020 strstr(device_model, "Xperia Play") ||
1021 strstr(device_model, "Play") ||
1022 strstr(device_model, "SO-01D")
1023 ) && (
1024 strstr(device_name, "keypad-game-zeus") ||
1025 strstr(device_name, "keypad-zeus") ||
1026 strstr(device_name, "Android Gamepad")
1027 )
1028 )
1029 {
1030 /* only use the hack if the device is one of the built-in devices */
1031 RARCH_LOG("Special Device Detected: %s\n", device_model);
1032 {
1033 if ( pad_id1 < 0 )
1034 pad_id1 = id;
1035 else
1036 pad_id2 = id;
1037
1038 if ( pad_id2 > 0)
1039 return;
1040
1041 strlcpy (name_buf, "XPERIA Play", sizeof(name_buf));
1042 *port = 0;
1043 }
1044 }
1045
1046 /* ARCHOS Gamepad
1047 * This device is composed of two hid devices
1048 * We make it look like one device
1049 */
1050 else if (strstr(device_model, "ARCHOS GAMEPAD") && (
1051 strstr(device_name, "joy_key") || strstr(device_name, "joystick")))
1052 {
1053 /* only use the hack if the device is one of the built-in devices */
1054 RARCH_LOG("ARCHOS GAMEPAD Detected: %s\n", device_model);
1055 {
1056 if ( pad_id1 < 0 )
1057 pad_id1 = id;
1058 else
1059 pad_id2 = id;
1060
1061 if ( pad_id2 > 0)
1062 return;
1063
1064 strlcpy (name_buf, "ARCHOS GamePad", sizeof(name_buf));
1065 *port = 0;
1066 }
1067 }
1068
1069 /* Amazon Fire TV & Fire stick */
1070 else if (
1071 string_starts_with_size(device_model, "AFT", STRLEN_CONST("AFT")) &&
1072 (
1073 strstr(device_model, "AFTB") ||
1074 strstr(device_model, "AFTT") ||
1075 strstr(device_model, "AFTS") ||
1076 strstr(device_model, "AFTM") ||
1077 strstr(device_model, "AFTRS")
1078 )
1079 )
1080 {
1081 RARCH_LOG("Special Device Detected: %s\n", device_model);
1082 {
1083 /* always map remote to port #0 */
1084 if (strstr(device_name, "Amazon Fire TV Remote"))
1085 {
1086 android->pads_connected = 0;
1087 *port = 0;
1088 strlcpy(name_buf, device_name, sizeof(name_buf));
1089 }
1090 /* remove the remote when a gamepad enters */
1091 else if (strstr(android->pad_states[0].name,"Amazon Fire TV Remote"))
1092 {
1093 android->pads_connected = 0;
1094 *port = 0;
1095 strlcpy(name_buf, device_name, sizeof(name_buf));
1096 }
1097 else
1098 strlcpy(name_buf, device_name, sizeof(name_buf));
1099 }
1100 }
1101
1102 /* Other uncommon devices
1103 * These are mostly remote control type devices, bind them always to port 0
1104 * And overwrite the binding whenever a controller button is pressed
1105 */
1106 else if (strstr(device_name, "Amazon Fire TV Remote")
1107 || strstr(device_name, "Nexus Remote")
1108 || strstr(device_name, "SHIELD Remote"))
1109 {
1110 android->pads_connected = 0;
1111 *port = 0;
1112 strlcpy(name_buf, device_name, sizeof(name_buf));
1113 }
1114
1115 else if (strstr(device_name, "iControlPad-"))
1116 strlcpy(name_buf, "iControlPad HID Joystick profile", sizeof(name_buf));
1117
1118 else if (strstr(device_name, "TTT THT Arcade console 2P USB Play"))
1119 {
1120 if (*port == 0)
1121 strlcpy(name_buf, "TTT THT Arcade (User 1)", sizeof(name_buf));
1122 else if (*port == 1)
1123 strlcpy(name_buf, "TTT THT Arcade (User 2)", sizeof(name_buf));
1124 }
1125 else if (strstr(device_name, "MOGA"))
1126 strlcpy(name_buf, "Moga IME", sizeof(name_buf));
1127
1128 /* If device is keyboard only and didn't match any of the devices above
1129 * then assume it is a keyboard, register the id, and return unless the
1130 * maximum number of keyboards are already registered. */
1131 else if (source == AINPUT_SOURCE_KEYBOARD && kbd_num < MAX_NUM_KEYBOARDS)
1132 {
1133 kbd_id[kbd_num] = id;
1134 kbd_num++;
1135 return;
1136 }
1137
1138 /* if device was not keyboard only, yet did not match any of the devices
1139 * then try to autoconfigure as gamepad based on device_name. */
1140 else if (!string_is_empty(device_name))
1141 strlcpy(name_buf, device_name, sizeof(name_buf));
1142
1143 if (strstr(android_app->current_ime, "net.obsidianx.android.mogaime"))
1144 strlcpy(name_buf, android_app->current_ime, sizeof(name_buf));
1145 else if (strstr(android_app->current_ime, "com.ccpcreations.android.WiiUseAndroid"))
1146 strlcpy(name_buf, android_app->current_ime, sizeof(name_buf));
1147 else if (strstr(android_app->current_ime, "com.hexad.bluezime"))
1148 strlcpy(name_buf, android_app->current_ime, sizeof(name_buf));
1149
1150 if (*port < 0)
1151 *port = android->pads_connected;
1152
1153 input_autoconfigure_connect(
1154 name_buf,
1155 NULL,
1156 android_joypad.ident,
1157 *port,
1158 vendorId,
1159 productId);
1160
1161 android->pad_states[android->pads_connected].id =
1162 g_android->id[android->pads_connected] = id;
1163 android->pad_states[android->pads_connected].port = *port;
1164
1165 strlcpy(android->pad_states[*port].name, name_buf,
1166 sizeof(android->pad_states[*port].name));
1167
1168 android->pads_connected++;
1169 }
1170
android_input_get_id(AInputEvent * event)1171 static int android_input_get_id(AInputEvent *event)
1172 {
1173 int id = AInputEvent_getDeviceId(event);
1174
1175 if (id == pad_id2)
1176 id = pad_id1;
1177
1178 return id;
1179 }
1180
android_input_poll_input(android_input_t * android,bool vibrate_on_keypress)1181 static void android_input_poll_input(android_input_t *android,
1182 bool vibrate_on_keypress)
1183 {
1184 AInputEvent *event = NULL;
1185 struct android_app *android_app = (struct android_app*)g_android;
1186
1187 /* Read all pending events. */
1188 while (AInputQueue_hasEvents(android_app->inputQueue))
1189 {
1190 while (AInputQueue_getEvent(android_app->inputQueue, &event) >= 0)
1191 {
1192 int32_t handled = 1;
1193 int predispatched = AInputQueue_preDispatchEvent(
1194 android_app->inputQueue, event);
1195 int source = AInputEvent_getSource(event);
1196 int type_event = AInputEvent_getType(event);
1197 int id = android_input_get_id(event);
1198 int port = android_input_get_id_port(android, id, source);
1199
1200 if (port < 0 && !android_is_keyboard_id(id))
1201 handle_hotplug(android, android_app,
1202 &port, id, source);
1203
1204 switch (type_event)
1205 {
1206 case AINPUT_EVENT_TYPE_MOTION:
1207 /* Only handle events from a touchscreen or mouse */
1208 if ((source & (AINPUT_SOURCE_TOUCHSCREEN
1209 | AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE)))
1210 android_input_poll_event_type_motion(android, event,
1211 port, source, vibrate_on_keypress);
1212 else
1213 engine_handle_dpad(android_app, event, port, source);
1214 break;
1215 case AINPUT_EVENT_TYPE_KEY:
1216 {
1217 int keycode = AKeyEvent_getKeyCode(event);
1218
1219 if (android_is_keyboard_id(id))
1220 {
1221 if (!predispatched)
1222 {
1223 android_input_poll_event_type_keyboard(
1224 event, keycode, &handled);
1225 android_input_poll_event_type_key(
1226 android_app, event, ANDROID_KEYBOARD_PORT,
1227 keycode, source, type_event, &handled);
1228 }
1229 }
1230 else
1231 android_input_poll_event_type_key(android_app,
1232 event, port, keycode, source, type_event, &handled);
1233 }
1234 break;
1235 }
1236
1237 if (!predispatched)
1238 AInputQueue_finishEvent(android_app->inputQueue, event,
1239 handled);
1240 }
1241 }
1242 }
1243
android_input_poll_user(android_input_t * android)1244 static void android_input_poll_user(android_input_t *android)
1245 {
1246 struct android_app *android_app = (struct android_app*)g_android;
1247 bool poll_accelerometer = false;
1248 bool poll_gyroscope = false;
1249
1250 if (!android_app->sensorEventQueue)
1251 return;
1252
1253 poll_accelerometer = (android_app->sensor_state_mask &
1254 (UINT64_C(1) << RETRO_SENSOR_ACCELEROMETER_ENABLE)) &&
1255 android_app->accelerometerSensor;
1256
1257 poll_gyroscope = (android_app->sensor_state_mask &
1258 (UINT64_C(1) << RETRO_SENSOR_GYROSCOPE_ENABLE)) &&
1259 android_app->gyroscopeSensor;
1260
1261 if (poll_accelerometer || poll_gyroscope)
1262 {
1263 ASensorEvent event;
1264 while (ASensorEventQueue_getEvents(
1265 android_app->sensorEventQueue, &event, 1) > 0)
1266 {
1267 switch (event.type)
1268 {
1269 case ASENSOR_TYPE_ACCELEROMETER:
1270 android->accelerometer_state.x = event.acceleration.x;
1271 android->accelerometer_state.y = event.acceleration.y;
1272 android->accelerometer_state.z = event.acceleration.z;
1273 break;
1274 case ASENSOR_TYPE_GYROSCOPE:
1275 /* ASensorEvent struct is mysterious - have to
1276 * read the raw 'data' field to get rate of
1277 * rotation... */
1278 android->gyroscope_state.x = event.data[0];
1279 android->gyroscope_state.y = event.data[1];
1280 android->gyroscope_state.z = event.data[2];
1281 break;
1282 default:
1283 break;
1284 }
1285 }
1286 }
1287 }
1288
1289 /* Handle all events. If our activity is in pause state,
1290 * block until we're unpaused.
1291 */
android_input_poll(void * data)1292 static void android_input_poll(void *data)
1293 {
1294 int ident;
1295 struct android_app *android_app = (struct android_app*)g_android;
1296 android_input_t *android = (android_input_t*)data;
1297 settings_t *settings = config_get_ptr();
1298
1299 while ((ident =
1300 ALooper_pollAll((input_config_binds[0][RARCH_PAUSE_TOGGLE].valid
1301 && input_key_pressed(RARCH_PAUSE_TOGGLE,
1302 ANDROID_KEYBOARD_PORT_INPUT_PRESSED(input_config_binds[0],
1303 RARCH_PAUSE_TOGGLE)))
1304 ? -1 : settings->uints.input_block_timeout,
1305 NULL, NULL, NULL)) >= 0)
1306 {
1307 bool vibrate_on_keypress = settings
1308 ? settings->bools.vibrate_on_keypress
1309 : false;
1310
1311 switch (ident)
1312 {
1313 case LOOPER_ID_INPUT:
1314 android_input_poll_input(android,
1315 vibrate_on_keypress);
1316 break;
1317 case LOOPER_ID_USER:
1318 android_input_poll_user(android);
1319 break;
1320 case LOOPER_ID_MAIN:
1321 android_input_poll_main_cmd();
1322 break;
1323 }
1324
1325 if (android_app->destroyRequested != 0)
1326 {
1327 rarch_ctl(RARCH_CTL_SET_SHUTDOWN, NULL);
1328 return;
1329 }
1330
1331 if (android_app->reinitRequested != 0)
1332 {
1333 if (rarch_ctl(RARCH_CTL_IS_PAUSED, NULL))
1334 command_event(CMD_EVENT_REINIT, NULL);
1335 android_app_write_cmd(android_app, APP_CMD_REINIT_DONE);
1336 return;
1337 }
1338 }
1339 }
1340
android_run_events(void * data)1341 bool android_run_events(void *data)
1342 {
1343 struct android_app *android_app = (struct android_app*)g_android;
1344
1345 if (ALooper_pollOnce(-1, NULL, NULL, NULL) == LOOPER_ID_MAIN)
1346 android_input_poll_main_cmd();
1347
1348 /* Check if we are exiting. */
1349 if (android_app->destroyRequested != 0)
1350 {
1351 rarch_ctl(RARCH_CTL_SET_SHUTDOWN, NULL);
1352 return false;
1353 }
1354
1355 if (android_app->reinitRequested != 0)
1356 {
1357 if (rarch_ctl(RARCH_CTL_IS_PAUSED, NULL))
1358 command_event(CMD_EVENT_REINIT, NULL);
1359 android_app_write_cmd(android_app, APP_CMD_REINIT_DONE);
1360 }
1361
1362 return true;
1363 }
1364
android_input_state(void * data,const input_device_driver_t * joypad,const input_device_driver_t * sec_joypad,rarch_joypad_info_t * joypad_info,const struct retro_keybind ** binds,bool keyboard_mapping_blocked,unsigned port,unsigned device,unsigned idx,unsigned id)1365 static int16_t android_input_state(
1366 void *data,
1367 const input_device_driver_t *joypad,
1368 const input_device_driver_t *sec_joypad,
1369 rarch_joypad_info_t *joypad_info,
1370 const struct retro_keybind **binds,
1371 bool keyboard_mapping_blocked,
1372 unsigned port,
1373 unsigned device,
1374 unsigned idx,
1375 unsigned id)
1376 {
1377 android_input_t *android = (android_input_t*)data;
1378
1379 switch (device)
1380 {
1381 case RETRO_DEVICE_JOYPAD:
1382 if (id == RETRO_DEVICE_ID_JOYPAD_MASK)
1383 {
1384 unsigned i;
1385 int16_t ret = 0;
1386 for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
1387 {
1388 if (binds[port][i].valid)
1389 {
1390 if (ANDROID_KEYBOARD_PORT_INPUT_PRESSED(binds[port], i))
1391 ret |= (1 << i);
1392 }
1393 }
1394 return ret;
1395 }
1396
1397 if (binds[port][id].valid)
1398 if (ANDROID_KEYBOARD_PORT_INPUT_PRESSED(binds[port], id))
1399 return 1;
1400 break;
1401 case RETRO_DEVICE_ANALOG:
1402 break;
1403 case RETRO_DEVICE_KEYBOARD:
1404 return (id < RETROK_LAST)
1405 && BIT_GET(android_key_state[ANDROID_KEYBOARD_PORT],
1406 rarch_keysym_lut[id]);
1407 case RETRO_DEVICE_MOUSE:
1408 {
1409 int val = 0;
1410 if(port > 0) return 0; /* TODO: implement mouse for additional ports/players */
1411 switch (id)
1412 {
1413 case RETRO_DEVICE_ID_MOUSE_LEFT:
1414 return android->mouse_l || android_check_quick_tap(android);
1415 case RETRO_DEVICE_ID_MOUSE_RIGHT:
1416 return android->mouse_r;
1417 case RETRO_DEVICE_ID_MOUSE_MIDDLE:
1418 return android->mouse_m;
1419 case RETRO_DEVICE_ID_MOUSE_X:
1420 val = android->mouse_x_delta;
1421 android->mouse_x_delta = 0;
1422 /* flush delta after it has been read */
1423 return val;
1424 case RETRO_DEVICE_ID_MOUSE_Y:
1425 val = android->mouse_y_delta;
1426 android->mouse_y_delta = 0;
1427 /* flush delta after it has been read */
1428 return val;
1429 case RETRO_DEVICE_ID_MOUSE_WHEELUP:
1430 val = android->mouse_wu;
1431 android->mouse_wu = 0;
1432 return val;
1433 case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
1434 val = android->mouse_wd;
1435 android->mouse_wd = 0;
1436 return val;
1437 }
1438 }
1439 break;
1440 case RETRO_DEVICE_LIGHTGUN:
1441 {
1442 int val = 0;
1443 if(port > 0) return 0; /* TODO: implement lightgun for additional ports/players */
1444 switch (id)
1445 {
1446 case RETRO_DEVICE_ID_LIGHTGUN_X:
1447 val = android->mouse_x_delta;
1448 android->mouse_x_delta = 0;
1449 /* flush delta after it has been read */
1450 return val;
1451 case RETRO_DEVICE_ID_LIGHTGUN_Y:
1452 val = android->mouse_y_delta;
1453 android->mouse_y_delta = 0;
1454 /* flush delta after it has been read */
1455 return val;
1456 case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER:
1457 return android->mouse_l || android_check_quick_tap(android);
1458 case RETRO_DEVICE_ID_LIGHTGUN_CURSOR:
1459 return android->mouse_m;
1460 case RETRO_DEVICE_ID_LIGHTGUN_TURBO:
1461 return android->mouse_r;
1462 case RETRO_DEVICE_ID_LIGHTGUN_START:
1463 return android->mouse_m && android->mouse_r;
1464 case RETRO_DEVICE_ID_LIGHTGUN_PAUSE:
1465 return android->mouse_m && android->mouse_l;
1466 }
1467 }
1468 break;
1469 case RETRO_DEVICE_POINTER:
1470 case RARCH_DEVICE_POINTER_SCREEN:
1471 switch (id)
1472 {
1473 case RETRO_DEVICE_ID_POINTER_X:
1474 if (device == RARCH_DEVICE_POINTER_SCREEN)
1475 return android->pointer[idx].full_x;
1476 return android->pointer[idx].x;
1477 case RETRO_DEVICE_ID_POINTER_Y:
1478 if (device == RARCH_DEVICE_POINTER_SCREEN)
1479 return android->pointer[idx].full_y;
1480 return android->pointer[idx].y;
1481 case RETRO_DEVICE_ID_POINTER_PRESSED:
1482 if (device == RARCH_DEVICE_POINTER_SCREEN)
1483 return (idx < android->pointer_count) &&
1484 (android->pointer[idx].full_x != -0x8000) &&
1485 (android->pointer[idx].full_y != -0x8000);
1486 return (idx < android->pointer_count) &&
1487 (android->pointer[idx].x != -0x8000) &&
1488 (android->pointer[idx].y != -0x8000);
1489 case RETRO_DEVICE_ID_POINTER_COUNT:
1490 return android->pointer_count;
1491 case RARCH_DEVICE_ID_POINTER_BACK:
1492 {
1493 const struct retro_keybind *keyptr =
1494 &input_autoconf_binds[0][RARCH_MENU_TOGGLE];
1495 if (keyptr->joykey == 0)
1496 return ANDROID_KEYBOARD_INPUT_PRESSED(AKEYCODE_BACK);
1497 }
1498 }
1499 break;
1500 }
1501
1502 return 0;
1503 }
1504
android_input_free_input(void * data)1505 static void android_input_free_input(void *data)
1506 {
1507 android_input_t *android = (android_input_t*)data;
1508 struct android_app *android_app = (struct android_app*)g_android;
1509 if (!android)
1510 return;
1511
1512 if (android_app->sensorManager &&
1513 android_app->sensorEventQueue)
1514 ASensorManager_destroyEventQueue(android_app->sensorManager,
1515 android_app->sensorEventQueue);
1516
1517 android_app->sensorEventQueue = NULL;
1518 android_app->accelerometerSensor = NULL;
1519 android_app->gyroscopeSensor = NULL;
1520 android_app->sensorManager = NULL;
1521
1522 android_app->input_alive = false;
1523
1524 #ifdef HAVE_DYNAMIC
1525 dylib_close((dylib_t)libandroid_handle);
1526 libandroid_handle = NULL;
1527 #endif
1528
1529 android_keyboard_free();
1530 free(data);
1531 }
1532
android_input_get_capabilities(void * data)1533 static uint64_t android_input_get_capabilities(void *data)
1534 {
1535 return
1536 (1 << RETRO_DEVICE_JOYPAD) |
1537 (1 << RETRO_DEVICE_POINTER) |
1538 (1 << RETRO_DEVICE_KEYBOARD) |
1539 (1 << RETRO_DEVICE_LIGHTGUN) |
1540 (1 << RETRO_DEVICE_ANALOG);
1541 }
1542
android_input_enable_sensor_manager(struct android_app * android_app)1543 static void android_input_enable_sensor_manager(struct android_app *android_app)
1544 {
1545 if (!android_app->sensorManager)
1546 android_app->sensorManager = ASensorManager_getInstance();
1547
1548 if (android_app->sensorManager)
1549 {
1550 if (!android_app->accelerometerSensor)
1551 android_app->accelerometerSensor =
1552 ASensorManager_getDefaultSensor(android_app->sensorManager,
1553 ASENSOR_TYPE_ACCELEROMETER);
1554
1555 if (!android_app->gyroscopeSensor)
1556 android_app->gyroscopeSensor =
1557 ASensorManager_getDefaultSensor(android_app->sensorManager,
1558 ASENSOR_TYPE_GYROSCOPE);
1559
1560 if (!android_app->sensorEventQueue)
1561 android_app->sensorEventQueue =
1562 ASensorManager_createEventQueue(android_app->sensorManager,
1563 android_app->looper, LOOPER_ID_USER, NULL, NULL);
1564 }
1565 }
1566
android_input_set_sensor_state(void * data,unsigned port,enum retro_sensor_action action,unsigned event_rate)1567 static bool android_input_set_sensor_state(void *data, unsigned port,
1568 enum retro_sensor_action action, unsigned event_rate)
1569 {
1570 struct android_app *android_app = (struct android_app*)g_android;
1571 android_input_t *android = (android_input_t*)data;
1572
1573 if (port > 0)
1574 return false;
1575
1576 if (event_rate == 0)
1577 event_rate = DEFAULT_ASENSOR_EVENT_RATE;
1578
1579 switch (action)
1580 {
1581 case RETRO_SENSOR_ACCELEROMETER_ENABLE:
1582 if (!android_app->accelerometerSensor)
1583 android_input_enable_sensor_manager(android_app);
1584
1585 if (android_app->sensorEventQueue &&
1586 android_app->accelerometerSensor)
1587 {
1588 ASensorEventQueue_enableSensor(android_app->sensorEventQueue,
1589 android_app->accelerometerSensor);
1590
1591 /* Events per second (in microseconds). */
1592 ASensorEventQueue_setEventRate(android_app->sensorEventQueue,
1593 android_app->accelerometerSensor, (1000L / event_rate)
1594 * 1000);
1595 }
1596
1597 android_app->accelerometer_event_rate = event_rate;
1598
1599 BIT64_CLEAR(android_app->sensor_state_mask, RETRO_SENSOR_ACCELEROMETER_DISABLE);
1600 BIT64_SET(android_app->sensor_state_mask, RETRO_SENSOR_ACCELEROMETER_ENABLE);
1601 return true;
1602
1603 case RETRO_SENSOR_ACCELEROMETER_DISABLE:
1604 if (android_app->sensorEventQueue &&
1605 android_app->accelerometerSensor)
1606 ASensorEventQueue_disableSensor(android_app->sensorEventQueue,
1607 android_app->accelerometerSensor);
1608
1609 android->accelerometer_state.x = 0.0f;
1610 android->accelerometer_state.y = 0.0f;
1611 android->accelerometer_state.z = 0.0f;
1612
1613 BIT64_CLEAR(android_app->sensor_state_mask, RETRO_SENSOR_ACCELEROMETER_ENABLE);
1614 BIT64_SET(android_app->sensor_state_mask, RETRO_SENSOR_ACCELEROMETER_DISABLE);
1615 return true;
1616
1617 case RETRO_SENSOR_GYROSCOPE_ENABLE:
1618 if (!android_app->gyroscopeSensor)
1619 android_input_enable_sensor_manager(android_app);
1620
1621 if (android_app->sensorEventQueue &&
1622 android_app->gyroscopeSensor)
1623 {
1624 ASensorEventQueue_enableSensor(android_app->sensorEventQueue,
1625 android_app->gyroscopeSensor);
1626
1627 /* Events per second (in microseconds). */
1628 ASensorEventQueue_setEventRate(android_app->sensorEventQueue,
1629 android_app->gyroscopeSensor, (1000L / event_rate)
1630 * 1000);
1631 }
1632
1633 android_app->gyroscope_event_rate = event_rate;
1634
1635 BIT64_CLEAR(android_app->sensor_state_mask, RETRO_SENSOR_GYROSCOPE_DISABLE);
1636 BIT64_SET(android_app->sensor_state_mask, RETRO_SENSOR_GYROSCOPE_ENABLE);
1637 return true;
1638
1639 case RETRO_SENSOR_GYROSCOPE_DISABLE:
1640 if (android_app->sensorEventQueue &&
1641 android_app->gyroscopeSensor)
1642 ASensorEventQueue_disableSensor(android_app->sensorEventQueue,
1643 android_app->gyroscopeSensor);
1644
1645 android->gyroscope_state.x = 0.0f;
1646 android->gyroscope_state.y = 0.0f;
1647 android->gyroscope_state.z = 0.0f;
1648
1649 BIT64_CLEAR(android_app->sensor_state_mask, RETRO_SENSOR_GYROSCOPE_ENABLE);
1650 BIT64_SET(android_app->sensor_state_mask, RETRO_SENSOR_GYROSCOPE_DISABLE);
1651 return true;
1652
1653 default:
1654 break;
1655 }
1656
1657 return false;
1658 }
1659
android_input_get_sensor_input(void * data,unsigned port,unsigned id)1660 static float android_input_get_sensor_input(void *data,
1661 unsigned port, unsigned id)
1662 {
1663 android_input_t *android = (android_input_t*)data;
1664
1665 if (port > 0)
1666 return 0.0f;
1667
1668 switch (id)
1669 {
1670 case RETRO_SENSOR_ACCELEROMETER_X:
1671 return android->accelerometer_state.x;
1672 case RETRO_SENSOR_ACCELEROMETER_Y:
1673 return android->accelerometer_state.y;
1674 case RETRO_SENSOR_ACCELEROMETER_Z:
1675 return android->accelerometer_state.z;
1676 case RETRO_SENSOR_GYROSCOPE_X:
1677 return android->gyroscope_state.x;
1678 case RETRO_SENSOR_GYROSCOPE_Y:
1679 return android->gyroscope_state.y;
1680 case RETRO_SENSOR_GYROSCOPE_Z:
1681 return android->gyroscope_state.z;
1682 }
1683
1684 return 0.0f;
1685 }
1686
1687 input_driver_t input_android = {
1688 android_input_init,
1689 android_input_poll,
1690 android_input_state,
1691 android_input_free_input,
1692 android_input_set_sensor_state,
1693 android_input_get_sensor_input,
1694 android_input_get_capabilities,
1695 "android",
1696
1697 NULL, /* grab_mouse */
1698 NULL
1699 };
1700