Skip to content

Commit f3b83f1

Browse files
f4mrfauxclaude
andcommitted
💡 Using bat (modern cat with syntax)
android/input: Route S Pen to RETRO_DEVICE_POINTER for menu interaction Fixes phantom hover clicks while enabling proper menu activation: Core Changes: - Route stylus contact events to pointer array (not mouse state) - Use proper motion_ptr indexing for multi-touch support - Implement pointer compaction on UP events - Maintain early returns to prevent contamination of finger touch logic Contact Detection: - Accept pressure >= 0.0f (was > 0.01f) for broader device support - Relax distance check to <= 1.0f for better contact detection - Respect input_stylus_require_contact_for_click setting Debug Support: - Add comprehensive logging for POINTER DOWN/UP events - Log pointer state queries for menu system debugging - Enable DEBUG_ANDROID_INPUT flag for detailed analysis Version: 1.21.69 for easy identification during testing This resolves GitHub issue libretro#15490 and improves upon rejected PR libretro#15597 by providing proper pointer lifecycle management and multi-touch support. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent de2f19f commit f3b83f1

4 files changed

Lines changed: 74 additions & 40 deletions

File tree

input/drivers/android_input.c

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,6 @@ static bool hover_guard_drop(float x, float y, int64_t now_ms, float eps_px)
132132
fabsf(y - g_hover_guard_y) <= eps_px);
133133
}
134134

135-
static void android_stylus_proximity_check_expire(android_input_t *android)
136-
{
137-
if (android->stylus_proximity_active)
138-
{
139-
retro_time_t now = cpu_features_get_time_usec();
140-
/* Convert both to milliseconds for comparison: now(µs)/1000 vs proximity(ns)/1000000 */
141-
if (now / 1000 > android->stylus_proximity_until_ns / 1000000)
142-
android->stylus_proximity_active = false;
143-
}
144-
}
145135

146136
#define ANDROID_KEYBOARD_PORT_INPUT_PRESSED(binds, id) (BIT_GET(android_key_state[ANDROID_KEYBOARD_PORT], rarch_keysym_lut[(binds)[(id)].key]))
147137

@@ -213,6 +203,17 @@ typedef struct android_input
213203
char device_model[256];
214204
} android_input_t;
215205

206+
static void android_stylus_proximity_check_expire(android_input_t *android)
207+
{
208+
if (android->stylus_proximity_active)
209+
{
210+
retro_time_t now = cpu_features_get_time_usec();
211+
/* Convert both to milliseconds for comparison: now(µs)/1000 vs proximity(ns)/1000000 */
212+
if (now / 1000 > android->stylus_proximity_until_ns / 1000000)
213+
android->stylus_proximity_active = false;
214+
}
215+
}
216+
216217
static void frontend_android_get_version_sdk(int32_t *sdk);
217218
static void frontend_android_get_name(char *s, size_t len);
218219

@@ -918,8 +919,8 @@ static INLINE void android_input_poll_event_type_motion(
918919

919920
/* Determine if stylus tip is actually touching the screen */
920921
tip_down = (action != AMOTION_EVENT_ACTION_UP) &&
921-
(pressure > 0.01f) &&
922-
(distance <= 0.0f);
922+
(pressure >= 0.0f) && /* Accept any pressure including 0 */
923+
(distance <= 1.0f); /* More lenient distance check */
923924

924925
/* Get button state */
925926
buttons = p_AMotionEvent_getButtonState ?
@@ -942,42 +943,62 @@ static INLINE void android_input_poll_event_type_motion(
942943
pressure, distance);
943944
#endif
944945

945-
/* Handle as mouse input with immediate response */
946-
if (!android->mouse_activated && stylus_pressed)
946+
/* STYLUS AS POINTER: Route to RETRO_DEVICE_POINTER for menu interaction
947+
* Handle DOWN/MOVE => active pointer; UP => release pointer
948+
* Only activate pointer when stylus_pressed (respects contact setting) */
949+
if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE)
947950
{
948-
android->mouse_activated = true;
949-
/* Initialize mouse position to prevent cursor jump */
950-
android->mouse_x_prev = x;
951-
android->mouse_y_prev = y;
951+
if (stylus_pressed) /* Only when contact detected */
952+
{
953+
struct video_viewport vp = {0};
954+
955+
/* Translate coords exactly like the finger touch path */
956+
video_driver_translate_coord_viewport_confined_wrap(
957+
&vp, x, y,
958+
&android->pointer[motion_ptr].confined_x,
959+
&android->pointer[motion_ptr].confined_y,
960+
&android->pointer[motion_ptr].full_x,
961+
&android->pointer[motion_ptr].full_y);
962+
963+
video_driver_translate_coord_viewport_wrap(
964+
&vp, x, y,
965+
&android->pointer[motion_ptr].x,
966+
&android->pointer[motion_ptr].y,
967+
&android->pointer[motion_ptr].full_x,
968+
&android->pointer[motion_ptr].full_y);
969+
970+
/* Ensure pointer_count covers this motion_ptr */
971+
if (android->pointer_count < (int)motion_ptr + 1)
972+
android->pointer_count = (int)motion_ptr + 1;
973+
952974
#ifdef DEBUG_ANDROID_INPUT
953-
RARCH_LOG("[Android Input] S Pen activated\n");
975+
if (action == AMOTION_EVENT_ACTION_DOWN)
976+
RARCH_LOG("[Stylus] POINTER DOWN @ (%.1f, %.1f) idx=%zu cnt=%d\n",
977+
x, y, motion_ptr, android->pointer_count);
954978
#endif
979+
}
980+
return; /* Early return - no shared processing */
955981
}
956982

957-
/* Button mapping: tip=left, side=right */
958-
android->mouse_r = side_primary; /* Side button = right-click */
959-
android->mouse_l = stylus_pressed && !side_primary;
960-
/* Tip contact = left-click (when not using side) */
961-
962-
/* Handle coordinate updates and mouse activation
963-
* for contact events */
964-
if (action == AMOTION_EVENT_ACTION_DOWN ||
965-
action == AMOTION_EVENT_ACTION_MOVE)
966-
{
967-
android_mouse_calculate_deltas(android, event, motion_ptr, source);
968-
}
969-
970-
/* Deactivate mouse mode when stylus is lifted */
971-
if (action == AMOTION_EVENT_ACTION_UP && !android->mouse_r)
983+
if (action == AMOTION_EVENT_ACTION_UP)
972984
{
973-
android->mouse_activated = false;
974-
android->mouse_l = 0;
975-
android->mouse_r = 0;
985+
/* Compact/release pointer array like the touch path */
986+
if (motion_ptr < MAX_TOUCH - 1)
987+
{
988+
memmove(android->pointer + motion_ptr,
989+
android->pointer + motion_ptr + 1,
990+
(MAX_TOUCH - motion_ptr - 1) * sizeof(android->pointer[0]));
991+
}
992+
if (android->pointer_count > 0)
993+
android->pointer_count--;
994+
976995
#ifdef DEBUG_ANDROID_INPUT
977-
RARCH_LOG("[Android Input] S Pen mouse deactivated\n");
996+
RARCH_LOG("[Stylus] POINTER UP idx=%zu cnt=%d\n", motion_ptr, android->pointer_count);
978997
#endif
998+
return; /* Early return - no shared processing */
979999
}
9801000

1001+
/* Important: do NOT set android->mouse_activated/mouse_l/mouse_r for stylus */
9811002
return;
9821003

9831004
default:
@@ -2038,7 +2059,13 @@ static int16_t android_input_state(
20382059
case RETRO_DEVICE_ID_MOUSE_LEFT:
20392060
/* S Pen bypasses timeout for immediate response */
20402061
if (android->mouse_activated)
2062+
{
2063+
#ifdef DEBUG_ANDROID_INPUT
2064+
RARCH_LOG("[Mouse Query] mouse_l=%d activated=%d\n",
2065+
android->mouse_l, android->mouse_activated);
2066+
#endif
20412067
return android->mouse_l;
2068+
}
20422069
else
20432070
{
20442071
/* Only finger taps should participate in quick-tap emulation.
@@ -2163,6 +2190,12 @@ static int16_t android_input_state(
21632190
return android->pointer[idx].full_y;
21642191
return android->pointer[idx].confined_y;
21652192
case RETRO_DEVICE_ID_POINTER_PRESSED:
2193+
#ifdef DEBUG_ANDROID_INPUT
2194+
RARCH_LOG("[PtrQuery] count=%d x0=%d y0=%d\n",
2195+
android->pointer_count,
2196+
android->pointer_count > 0 ? android->pointer[0].confined_x : 0,
2197+
android->pointer_count > 0 ? android->pointer[0].confined_y : 0);
2198+
#endif
21662199
/* On mobile platforms, touches outside screen / core viewport are not reported. */
21672200
if (device == RARCH_DEVICE_POINTER_SCREEN)
21682201
return (idx < android->pointer_count) &&

pkg/android/phoenix-common/jni/Android.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ DEFINES += -DRARCH_MOBILE \
7575
-DHAVE_STB_VORBIS \
7676
-DHAVE_LANGEXTRA \
7777
-DANDROID \
78+
-DDEBUG_ANDROID_INPUT \
7879
-DHAVE_DYNAMIC \
7980
-DHAVE_OPENGL \
8081
-DHAVE_OVERLAY \

pkg/android/phoenix/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
xmlns:tools="http://schemas.android.com/tools"
44
package="com.retroarch"
55
android:versionCode="1597175264"
6-
android:versionName="1.21.0"
6+
android:versionName="1.21.69"
77
android:installLocation="internalOnly">
88
<uses-feature android:glEsVersion="0x00020000" />
99
<uses-feature android:name="android.hardware.type.pc" android:required="false"/>

version.all

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
# /* - pkg/snap/snapcraft.yaml (including the github url) */
77

88
#ifndef PACKAGE_VERSION
9-
#define PACKAGE_VERSION "1.21.0"
9+
#define PACKAGE_VERSION "1.21.69"
1010
#endif

0 commit comments

Comments
 (0)