Skip to content

Commit dce5b91

Browse files
f4mrfauxclaude
andcommitted
fix: Make S-Pen behave like native touchscreen to prevent menu jumping
- Only update coordinates on actual S-Pen contact, not during hover - Matches native touchscreen behavior where hover events are ignored - Prevents menu jumping between hover and tap states - Maintains virtual barrel pointer system for libretro cores - Improves user experience consistency with native touch interaction 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 3473e9e commit dce5b91

1 file changed

Lines changed: 64 additions & 61 deletions

File tree

input/drivers/android_input.c

Lines changed: 64 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,77 +1081,80 @@ static INLINE void android_input_poll_event_type_motion(
10811081
pressure, distance);
10821082
#endif
10831083

1084-
/* STYLUS AS POINTER: Route to RETRO_DEVICE_POINTER for menu interaction
1085-
* Handle DOWN/MOVE => active pointer; UP => release pointer
1086-
* Only activate pointer when stylus_pressed (respects contact setting) */
1084+
/* STYLUS POINTER: Mimic native touchscreen behavior for menu consistency
1085+
* Native touchscreen ONLY updates coordinates on contact, NOT during hover
1086+
* This prevents menu jumping between hover and tap states */
10871087
if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE)
10881088
{
1089-
/* Always update coordinates for hover support, but only set pressed state when touching */
1090-
struct video_viewport vp = {0};
1091-
1092-
/* Translate coords exactly like the finger touch path */
1093-
video_driver_translate_coord_viewport_confined_wrap(
1094-
&vp, x, y,
1095-
&android->pointer[motion_ptr].confined_x,
1096-
&android->pointer[motion_ptr].confined_y,
1097-
&android->pointer[motion_ptr].full_x,
1098-
&android->pointer[motion_ptr].full_y);
1099-
1100-
video_driver_translate_coord_viewport_wrap(
1101-
&vp, x, y,
1102-
&android->pointer[motion_ptr].x,
1103-
&android->pointer[motion_ptr].y,
1104-
&android->pointer[motion_ptr].full_x,
1105-
&android->pointer[motion_ptr].full_y);
1106-
1107-
/* S-Pen Menu Coordination: Activate mouse mode for menu consistency
1108-
* This prevents menu jumping between hover and tap states */
1109-
if (!android->mouse_activated)
1089+
if (stylus_pressed) /* ONLY update coordinates on actual contact, like native touchscreen */
11101090
{
1111-
RARCH_LOG("[Android Input] S-Pen activated menu mouse mode.\n");
1112-
android->mouse_activated = true;
1113-
}
1114-
1115-
/* Update mouse coordinates for both hover and contact - enables smooth cursor movement */
1116-
android->mouse_x_viewport = android->pointer[motion_ptr].x;
1117-
android->mouse_y_viewport = android->pointer[motion_ptr].y;
1118-
1119-
/* S-Pen Virtual Pointer System for libretro cores:
1120-
* Index 0 = tip pointer (when tip pressed)
1121-
* Index 1 = virtual barrel pointer (when barrel pressed, mirrors tip XY)
1122-
* This allows cores to detect barrel via pointer_count > 1 or checking index 1 */
1123-
1124-
android->pointer_count = 0; /* Reset count, will increment based on active states */
1125-
1126-
if (tip_down) {
1127-
/* Set up tip pointer at index 0 */
1128-
android->pointer[0] = android->pointer[motion_ptr]; /* Copy translated coordinates */
1129-
android->pointer_count = 1;
1130-
}
1131-
1132-
if (side_primary) {
1133-
/* Set up virtual barrel pointer at index 1, mirroring tip coordinates */
1134-
android->pointer[1] = android->pointer[motion_ptr]; /* Same coordinates as tip */
1135-
android->pointer_count = tip_down ? 2 : 1; /* Increment if tip also active */
1136-
}
1137-
1138-
/* Update mouse button states for menu interaction */
1139-
android->mouse_l = tip_down; /* Left click when tip touches */
1140-
android->mouse_r = side_primary; /* Right click on barrel button */
1141-
1091+
struct video_viewport vp = {0};
1092+
1093+
/* Translate coords exactly like the finger touch path */
1094+
video_driver_translate_coord_viewport_confined_wrap(
1095+
&vp, x, y,
1096+
&android->pointer[motion_ptr].confined_x,
1097+
&android->pointer[motion_ptr].confined_y,
1098+
&android->pointer[motion_ptr].full_x,
1099+
&android->pointer[motion_ptr].full_y);
1100+
1101+
video_driver_translate_coord_viewport_wrap(
1102+
&vp, x, y,
1103+
&android->pointer[motion_ptr].x,
1104+
&android->pointer[motion_ptr].y,
1105+
&android->pointer[motion_ptr].full_x,
1106+
&android->pointer[motion_ptr].full_y);
1107+
1108+
/* S-Pen Menu Coordination: Activate mouse mode for menu consistency */
1109+
if (!android->mouse_activated)
1110+
{
1111+
RARCH_LOG("[Android Input] S-Pen activated menu mouse mode.\n");
1112+
android->mouse_activated = true;
1113+
}
1114+
1115+
/* Update mouse coordinates only on contact - matches native touchscreen behavior */
1116+
android->mouse_x_viewport = android->pointer[motion_ptr].x;
1117+
android->mouse_y_viewport = android->pointer[motion_ptr].y;
1118+
1119+
/* S-Pen Virtual Pointer System for libretro cores:
1120+
* Index 0 = tip pointer (when tip pressed)
1121+
* Index 1 = virtual barrel pointer (when barrel pressed, mirrors tip XY)
1122+
* This allows cores to detect barrel via pointer_count > 1 or checking index 1 */
1123+
1124+
android->pointer_count = 0; /* Reset count, will increment based on active states */
1125+
1126+
if (tip_down) {
1127+
/* Set up tip pointer at index 0 */
1128+
android->pointer[0] = android->pointer[motion_ptr]; /* Copy translated coordinates */
1129+
android->pointer_count = 1;
1130+
}
1131+
1132+
if (side_primary) {
1133+
/* Set up virtual barrel pointer at index 1, mirroring tip coordinates */
1134+
android->pointer[1] = android->pointer[motion_ptr]; /* Same coordinates as tip */
1135+
android->pointer_count = tip_down ? 2 : 1; /* Increment if tip also active */
1136+
}
1137+
1138+
/* Update mouse button states for menu interaction */
1139+
android->mouse_l = tip_down; /* Left click when tip touches */
1140+
android->mouse_r = side_primary; /* Right click on barrel button */
1141+
11421142
#ifdef DEBUG_ANDROID_INPUT
1143-
if (action == AMOTION_EVENT_ACTION_DOWN)
1144-
RARCH_LOG("[Stylus] POINTER DOWN @ (%.1f, %.1f) tip=%d barrel=%d cnt=%d\n",
1145-
x, y, tip_down, side_primary, android->pointer_count);
1143+
if (action == AMOTION_EVENT_ACTION_DOWN)
1144+
RARCH_LOG("[Stylus] POINTER DOWN @ (%.1f, %.1f) tip=%d barrel=%d cnt=%d\n",
1145+
x, y, tip_down, side_primary, android->pointer_count);
11461146
#endif
1147-
if (!tip_down && !side_primary) {
1148-
/* Hovering: no active pointers, clear button states but maintain cursor position */
1147+
}
1148+
else
1149+
{
1150+
/* Hovering: Like native touchscreen, DON'T update coordinates during hover
1151+
* This prevents menu jumping and matches user expectations */
11491152
android->pointer_count = 0;
11501153
android->mouse_l = false;
11511154
android->mouse_r = false;
11521155

11531156
#ifdef DEBUG_ANDROID_INPUT
1154-
RARCH_LOG("[Stylus] HOVER @ (%.1f, %.1f) p=%.3f d=%.3f\n",
1157+
RARCH_LOG("[Stylus] HOVER (no coord update) @ (%.1f, %.1f) p=%.3f d=%.3f\n",
11551158
x, y, pressure, distance);
11561159
#endif
11571160
}

0 commit comments

Comments
 (0)