From abcd42777f7c17559cf6eb509dc86aca63e48527 Mon Sep 17 00:00:00 2001 From: Max Kupriianov Date: Tue, 15 Aug 2023 20:13:53 +0200 Subject: [PATCH] refactor: rewrite input handling to better support AINPUT_SOURCE_STYLUS (#15597) Resolves issues with S-Pen on Samsung devices, also adds support for S-Pen button that is handled as r-mouse click now. --- input/drivers/android_input.c | 93 +++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 4 deletions(-) diff --git a/input/drivers/android_input.c b/input/drivers/android_input.c index a596492c08..7f5b222f77 100644 --- a/input/drivers/android_input.c +++ b/input/drivers/android_input.c @@ -61,10 +61,14 @@ enum { AMOTION_EVENT_BUTTON_FORWARD = 1 << 4, AMOTION_EVENT_AXIS_VSCROLL = 9, AMOTION_EVENT_ACTION_HOVER_MOVE = 7, - AINPUT_SOURCE_STYLUS = 0x00004000 + AINPUT_SOURCE_STYLUS = 0x00004002, + AMOTION_EVENT_BUTTON_STYLUS_PRIMARY = 1 << 5, + AMOTION_EVENT_BUTTON_STYLUS_SECONDARY = 1 << 6 }; #endif +#define AINPUT_SOURCE_TOUCHSCREEN_OR_MOUSE AINPUT_SOURCE_TOUCHSCREEN|AINPUT_SOURCE_MOUSE + /* If using an SDK lower than 24 then add missing relative axis codes */ #ifndef AMOTION_EVENT_AXIS_RELATIVE_X #define AMOTION_EVENT_AXIS_RELATIVE_X 27 @@ -818,6 +822,86 @@ static INLINE void android_input_poll_event_type_motion( android->mouse_r = (android->pointer_count == 2); } + +static INLINE void android_input_poll_event_type_motion_stylus( + android_input_t *android, AInputEvent *event, + int port, int source) +{ + int getaction = AMotionEvent_getAction(event); + int action = getaction & AMOTION_EVENT_ACTION_MASK; + size_t motion_ptr = getaction >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + + if (ENABLE_TOUCH_SCREEN_MOUSE) + { + // mouse right button press on stylus primary button + int btn = (int)AMotionEvent_getButtonState(event); + android->mouse_r = (btn & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY); + } + + bool hovered_or_moving = ( + action == AMOTION_EVENT_ACTION_HOVER_MOVE + || action == AMOTION_EVENT_ACTION_MOVE); + + if (hovered_or_moving && motion_ptr < MAX_TOUCH) + { + if (ENABLE_TOUCH_SCREEN_MOUSE) + { + if (action == AMOTION_EVENT_ACTION_MOVE) { + android->mouse_l = 1; + } else { + android->mouse_l = 0; + } + + android_mouse_calculate_deltas(android,event,motion_ptr); + } + + if (action == AMOTION_EVENT_ACTION_MOVE) { + // move pointer + + struct video_viewport vp; + float x = AMotionEvent_getX(event, motion_ptr); + float y = AMotionEvent_getY(event, motion_ptr); + + vp.x = 0; + vp.y = 0; + vp.width = 0; + vp.height = 0; + vp.full_width = 0; + vp.full_height = 0; + + video_driver_translate_coord_viewport_wrap( + &vp, + x, y, + &android->pointer[motion_ptr].x, + &android->pointer[motion_ptr].y, + &android->pointer[motion_ptr].full_x, + &android->pointer[motion_ptr].full_y); + + android->pointer_count = MAX( + android->pointer_count, + motion_ptr + 1); + } else if (action == AMOTION_EVENT_ACTION_HOVER_MOVE) { + // release the pointer + + memmove(android->pointer + motion_ptr, + android->pointer + motion_ptr + 1, + (MAX_TOUCH - motion_ptr - 1) * sizeof(struct input_pointer)); + + if (android->pointer_count > 0) + android->pointer_count--; + } + } else if ((action == AMOTION_EVENT_ACTION_HOVER_EXIT) && motion_ptr < MAX_TOUCH) { + if (ENABLE_TOUCH_SCREEN_MOUSE) + { + android->mouse_l = 0; + + android_mouse_calculate_deltas(android,event,motion_ptr); + } + + // pointer was already released during AMOTION_EVENT_ACTION_HOVER_MOVE + } +} + static bool android_is_keyboard_id(int id) { unsigned i; @@ -1477,9 +1561,10 @@ static void android_input_poll_input_default(android_input_t *android) case AINPUT_EVENT_TYPE_MOTION: if ((source & AINPUT_SOURCE_TOUCHPAD)) engine_handle_touchpad(android_app, event, port); - /* Only handle events from a touchscreen or mouse */ - else if ((source & (AINPUT_SOURCE_TOUCHSCREEN - | AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE))) + else if ((source & AINPUT_SOURCE_STYLUS) == AINPUT_SOURCE_STYLUS) + android_input_poll_event_type_motion_stylus(android, event, + port, source); + else if ((source & AINPUT_SOURCE_TOUCHSCREEN_OR_MOUSE) == AINPUT_SOURCE_TOUCHSCREEN_OR_MOUSE) android_input_poll_event_type_motion(android, event, port, source); else