mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
Android: Samsung S-Pen stylus support (#19076)
* android: Add Samsung S-Pen stylus input support Stylus input for the Android driver, squashed from PR #19076 and rebased onto current master (three conflicts, all additive: the hover-guard block in android_input.c, an include in runloop.c and the stylus rows in tools/settings_table.reference). - toolType-based stylus/finger classification with an input-source fallback - hover, contact and click handled separately; hover can move the pointer without pressing - phantom-touch suppression for Samsung pens (hover guard, proximity window) - both barrel buttons read - four Android-only settings: input_stylus_enable, input_stylus_require_contact_for_click, input_stylus_hover_moves_pointer, input_stylus_pressure_sensitivity - android_mouse_calculate_deltas computed its fallback delta from the zeroed delta instead of the event position; fixed Closes #15490 Closes #18194 * overlay: hide for a stylus without unloading the pack The S-Pen support unloaded the on-screen overlay from the run loop whenever a stylus became active and loaded it again two seconds after the last pen event. A pen that leaves and returns does that over and over, and each round is the pack's file and texture work, triggered by input while a core runs. It was a full unload because a soft-hidden overlay still took over pointer input: with input_overlay_pointer_enable the overlay poll tracks every touch as its own pointing device and sets INP_FLAG_BLOCK_POINTER_INPUT, so input_state never reaches the driver and the pen's native state (hover included) is lost. Add INPUT_OVERLAY_STYLUS_HIDDEN and make it complete. While it is set the overlay: - is not drawn (alpha 0, as the gamepad soft-hide does); - reads no touches, so the poll releases whatever a finger was holding the way lifting it would, and no hitbox or pointing device sees the pen; - does not answer mouse, lightgun or pointer queries and does not block pointer input. The run loop sets and clears the flag each frame on the current overlay, the way the gamepad soft-hide is driven. Nothing is unloaded or reloaded. * android: report a pen as one pointer, its barrel button as the right mouse button The S-Pen support gave pointer indices a meaning of its own: index 0 was the cursor, index 1 the tip pressing and index 2 the barrel button, with the pointer count raised to 2 or 3 to match. Only a core written for that contract can read it. Everywhere else an index is a separate touch, so a pressing pen looked like two fingers and a press with the barrel button like three - to cores that count pointers, to the on-screen overlay, and to this driver's own lightgun mapping, where two pointers are turbo and three are reload. With the barrel button held but the tip not pressing, index 1 was stale and still inside the count. Map the pen onto the devices the driver already reports instead: - position is pointer 0, and moves without a press while hovering (input_stylus_hover_moves_pointer); - a press is pointer 0 pressed with a count of 1: the tip pressing past the pressure threshold, or, with input_stylus_require_contact_for_click off, the barrel button, touching or hovering; - the barrel button is the right mouse button. This also puts two settings to work. The contact-for-click option and the pressure threshold only fed a latch nothing read; they now decide the press, as their menu text says. The pen no longer switches the driver into mouse mode (mouse_activated). That flag is never cleared, and once set the lightgun position is read from the mouse coordinates, which a pen does not update, so lightgun aim went stale after the first pen contact. The mouse_x_viewport/mouse_y_viewport values it wrote alongside are not read anywhere. A cancelled pen gesture now releases the press like a lift does; before it fell through to the touchscreen path and left the pen's contact latched. Compiled with the NDK through the Android unity build. Not run on a device: it needs a pass on S-Pen hardware before merging. * android: let a mouse's hover events reach the mouse path again The S-Pen support drops every hover event before the source is looked at, so hover cannot be taken for a touch. A mouse moved with no button held reports its motion as hover events too, and they were dropped with the rest: the pointer only moved while a button was down. Drop hover events after the mouse branch instead. Mouse motion is handled as before the stylus work, and hover from any other source is still kept out of the touchscreen path. --------- Co-authored-by: LibretroAdmin <[email protected]>
This commit is contained in:
1 parent
11dc8ba30d
commit
4592b490bd
17 files changed
+656
-23
No files matched your search
@@ -89,6 +89,8 @@
|
||||
|
||||
#define DEFAULT_TOUCH_SCALE 1
|
||||
|
||||
#define DEFAULT_INPUT_STYLUS_PRESSURE_SENSITIVITY 70
|
||||
|
||||
#if defined(RARCH_MOBILE) || defined(HAVE_LIBNX) || defined(__WINRT__) || defined(__EMSCRIPTEN__) || defined (VITA)
|
||||
#define DEFAULT_POINTER_ENABLE true
|
||||
#else
|
||||
|
||||
+8
-2
@@ -2913,6 +2913,11 @@ static struct config_bool_setting *populate_settings_bool(
|
||||
SETTING_BOOL("netplay_request_device_p16", &settings->bools.netplay_request_devices[15], true, false, false);
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
SETTING_BOOL("input_stylus_enable", &settings->bools.input_stylus_enable, true, true, false);
|
||||
SETTING_BOOL("input_stylus_require_contact_for_click", &settings->bools.input_stylus_require_contact_for_click, true, true, false);
|
||||
SETTING_BOOL("input_stylus_hover_moves_pointer", &settings->bools.input_stylus_hover_moves_pointer, true, true, false);
|
||||
#endif
|
||||
|
||||
#ifdef _3DS
|
||||
SETTING_BOOL("new3ds_speedup_enable", &settings->bools.new3ds_speedup_enable, true, DEFAULT_NEW_3DS_SPEEDUP_ENABLE, false);
|
||||
@@ -4233,9 +4238,10 @@ static struct config_uint_setting *populate_settings_uint(
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
SETTING_UINT("input_sensor_orientation", &settings->uints.input_sensor_orientation, true, 0, false);
|
||||
SETTING_UINT("input_stylus_pressure_sensitivity", &settings->uints.input_stylus_pressure_sensitivity, true, DEFAULT_INPUT_STYLUS_PRESSURE_SENSITIVITY, false);
|
||||
SETTING_UINT("input_sensor_orientation", &settings->uints.input_sensor_orientation, true, 0, false);
|
||||
#else
|
||||
SETTING_UINT("input_sensor_orientation", &settings->uints.input_sensor_orientation, true, 1, false);
|
||||
SETTING_UINT("input_sensor_orientation", &settings->uints.input_sensor_orientation, true, 1, false);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_OVERLAY)
|
||||
|
||||
@@ -453,6 +453,9 @@ typedef struct settings
|
||||
unsigned nfs_readahead;
|
||||
#endif
|
||||
unsigned input_sensor_orientation;
|
||||
#ifdef ANDROID
|
||||
unsigned input_stylus_pressure_sensitivity;
|
||||
#endif
|
||||
} uints;
|
||||
|
||||
struct
|
||||
@@ -1152,6 +1155,9 @@ typedef struct settings
|
||||
|
||||
#ifdef ANDROID
|
||||
bool android_input_disconnect_workaround;
|
||||
bool input_stylus_enable;
|
||||
bool input_stylus_require_contact_for_click;
|
||||
bool input_stylus_hover_moves_pointer;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_COCOATOUCH)
|
||||
|
||||
+419
-13
@@ -19,6 +19,7 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <android/keycodes.h>
|
||||
|
||||
@@ -69,9 +70,16 @@ enum {
|
||||
AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2,
|
||||
AMOTION_EVENT_BUTTON_BACK = 1 << 3,
|
||||
AMOTION_EVENT_BUTTON_FORWARD = 1 << 4,
|
||||
AMOTION_EVENT_BUTTON_STYLUS_PRIMARY = 1 << 5,
|
||||
AMOTION_EVENT_BUTTON_STYLUS_SECONDARY = 1 << 6,
|
||||
AMOTION_EVENT_AXIS_VSCROLL = 9,
|
||||
AMOTION_EVENT_AXIS_DISTANCE = 24,
|
||||
AMOTION_EVENT_ACTION_HOVER_MOVE = 7,
|
||||
AINPUT_SOURCE_STYLUS = 0x00004000
|
||||
AMOTION_EVENT_ACTION_HOVER_ENTER = 9,
|
||||
AMOTION_EVENT_ACTION_HOVER_EXIT = 10,
|
||||
AINPUT_SOURCE_STYLUS = 0x00004000,
|
||||
AMOTION_EVENT_TOOL_TYPE_FINGER = 1,
|
||||
AMOTION_EVENT_TOOL_TYPE_STYLUS = 2
|
||||
};
|
||||
#endif
|
||||
/* If using an NDK lower than 16b then add missing definition */
|
||||
@@ -105,6 +113,40 @@ enum {
|
||||
* writers bound incoming keycodes, readers bound bind keysyms. */
|
||||
static uint8_t android_key_state[DEFAULT_MAX_PADS + 1][MAX_KEYS];
|
||||
|
||||
/* Samsung S-Pen firmware emits phantom touchscreen DOWN events shortly
|
||||
* after a hover ends. arm() records the last hover point and a deadline;
|
||||
* drop() returns true for incoming touches inside that spatial/temporal
|
||||
* window so the caller can discard them. */
|
||||
static bool g_hover_guard_active = false;
|
||||
static int64_t g_hover_guard_until_ms = 0;
|
||||
static float g_hover_guard_x = 0.0f, g_hover_guard_y = 0.0f;
|
||||
|
||||
static void hover_guard_arm(float x, float y, int64_t now_ms, int guard_ms)
|
||||
{
|
||||
g_hover_guard_active = true;
|
||||
g_hover_guard_until_ms = now_ms + guard_ms;
|
||||
g_hover_guard_x = x;
|
||||
g_hover_guard_y = y;
|
||||
#ifdef DEBUG_ANDROID_INPUT
|
||||
RARCH_LOG("[RA Input] Hover guard ARMED at (%.1f,%.1f) for %dms\n",
|
||||
x, y, guard_ms);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool hover_guard_drop(float x, float y, int64_t now_ms, float eps_px)
|
||||
{
|
||||
if (!g_hover_guard_active)
|
||||
return false;
|
||||
if (now_ms > g_hover_guard_until_ms)
|
||||
{
|
||||
g_hover_guard_active = false;
|
||||
return false;
|
||||
}
|
||||
return (fabsf(x - g_hover_guard_x) <= eps_px &&
|
||||
fabsf(y - g_hover_guard_y) <= eps_px);
|
||||
}
|
||||
|
||||
|
||||
#define ANDROID_KEYBOARD_PORT_INPUT_PRESSED(binds, id) (BIT_GET(android_key_state[ANDROID_KEYBOARD_PORT], rarch_keysym_lut[RETRO_KEYBIND_KEY(&(binds)[(id)])]))
|
||||
|
||||
#define ANDROID_KEYBOARD_INPUT_PRESSED(key) (BIT_GET(android_key_state[0], (key)))
|
||||
@@ -157,6 +199,12 @@ typedef struct state_device
|
||||
typedef struct android_input
|
||||
{
|
||||
int64_t quick_tap_time;
|
||||
/* 120ms window after any stylus event during which the touchscreen
|
||||
* quick-tap emulation is suppressed. */
|
||||
bool stylus_proximity_active;
|
||||
int64_t stylus_proximity_until_ns;
|
||||
bool stylus_contact_active; /* Tip has touched since the last UP */
|
||||
bool stylus_press_active; /* The pen holds pointer 0 pressed */
|
||||
state_device_t pad_states[MAX_USERS]; /* int alignment */
|
||||
int mouse_x, mouse_y;
|
||||
int16_t mouse_x_viewport_screen, mouse_y_viewport_screen;
|
||||
@@ -173,10 +221,31 @@ typedef struct android_input
|
||||
char device_model[256];
|
||||
} android_input_t;
|
||||
|
||||
static void android_stylus_proximity_check_expire(android_input_t *android)
|
||||
{
|
||||
if (android->stylus_proximity_active)
|
||||
{
|
||||
retro_time_t now = cpu_features_get_time_usec();
|
||||
if (now / 1000 > android->stylus_proximity_until_ns / 1000000)
|
||||
android->stylus_proximity_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool (*engine_lookup_name)(char *buf,
|
||||
int *vendorId, int *productId, size_t len, int id);
|
||||
void (*engine_handle_dpad)(struct android_app *, AInputEvent*, int, int);
|
||||
|
||||
/* Nanosecond timestamp of the most recent stylus event; queried by
|
||||
* android_input_stylus_recently_active() so runloop.c can auto-hide the
|
||||
* touch overlay while the S-Pen is in use. */
|
||||
int64_t g_android_stylus_last_event_ns = 0;
|
||||
|
||||
bool android_input_stylus_recently_active(void)
|
||||
{
|
||||
int64_t now_ns = (int64_t)cpu_features_get_time_usec() * 1000;
|
||||
return (now_ns - g_android_stylus_last_event_ns) < 2000000000LL; /* 2 s */
|
||||
}
|
||||
|
||||
static void android_input_poll_input_gingerbread(android_input_t *android);
|
||||
static void android_input_poll_input_default(android_input_t *android);
|
||||
static void (*android_input_poll_input)(android_input_t *android);
|
||||
@@ -202,6 +271,18 @@ static typeof(AMotionEvent_getButtonState) *p_AMotionEvent_getButtonState;
|
||||
|
||||
#define AMotionEvent_getButtonState (*p_AMotionEvent_getButtonState)
|
||||
|
||||
extern int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index);
|
||||
|
||||
static typeof(AMotionEvent_getToolType) *p_AMotionEvent_getToolType;
|
||||
|
||||
#define AMotionEvent_getToolType (*p_AMotionEvent_getToolType)
|
||||
|
||||
extern float AMotionEvent_getPressure(const AInputEvent* motion_event, size_t pointer_index);
|
||||
|
||||
static typeof(AMotionEvent_getPressure) *p_AMotionEvent_getPressure;
|
||||
|
||||
#define AMotionEvent_getPressure (*p_AMotionEvent_getPressure)
|
||||
|
||||
#ifdef HAVE_DYLIB
|
||||
static void *libandroid_handle;
|
||||
#endif
|
||||
@@ -1198,6 +1279,10 @@ static bool android_input_init_handle(void)
|
||||
|
||||
p_AMotionEvent_getButtonState = dlsym(RTLD_DEFAULT,
|
||||
"AMotionEvent_getButtonState");
|
||||
p_AMotionEvent_getToolType = dlsym(RTLD_DEFAULT,
|
||||
"AMotionEvent_getToolType");
|
||||
p_AMotionEvent_getPressure = dlsym(RTLD_DEFAULT,
|
||||
"AMotionEvent_getPressure");
|
||||
#endif
|
||||
|
||||
pad_id1 = -1;
|
||||
@@ -1219,6 +1304,10 @@ static void *android_input_init(const char *joypad_driver)
|
||||
android->mouse_activated = false;
|
||||
android->pads_connected = 0;
|
||||
android->quick_tap_time = 0;
|
||||
android->stylus_proximity_active = false;
|
||||
android->stylus_proximity_until_ns = 0;
|
||||
android->stylus_contact_active = false;
|
||||
android->stylus_press_active = false;
|
||||
|
||||
input_keymaps_init_keyboard_lut(rarch_key_map_android);
|
||||
|
||||
@@ -1288,6 +1377,14 @@ static void *android_input_init(const char *joypad_driver)
|
||||
|
||||
static int android_check_quick_tap(android_input_t *android)
|
||||
{
|
||||
/* Suppress quick-tap promotion while the hover guard is active: phantom
|
||||
* touchscreen events after a stylus hover exit must not fire clicks. */
|
||||
if (g_hover_guard_active)
|
||||
{
|
||||
android->quick_tap_time = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if the touch screen has been been quick tapped
|
||||
* and then not touched again for 200ms
|
||||
* If so then return true and deactivate quick tap timer */
|
||||
@@ -1360,8 +1457,8 @@ static INLINE void android_mouse_calculate_deltas(android_input_t *android,
|
||||
x = AMotionEvent_getX(event, motion_ptr);
|
||||
y = AMotionEvent_getY(event, motion_ptr);
|
||||
|
||||
x_delta = (x_delta - android->mouse_x_prev);
|
||||
y_delta = (y_delta - android->mouse_y_prev);
|
||||
x_delta = (x - android->mouse_x_prev);
|
||||
y_delta = (y - android->mouse_y_prev);
|
||||
|
||||
android->mouse_x_prev = x;
|
||||
android->mouse_y_prev = y;
|
||||
@@ -1390,23 +1487,273 @@ static INLINE void android_mouse_calculate_deltas(android_input_t *android,
|
||||
android->mouse_y = y;
|
||||
}
|
||||
|
||||
/* How a pen maps onto the libretro devices this driver already
|
||||
* reports. Nothing here is pen-specific to a core:
|
||||
*
|
||||
* - Position: pointer 0. While hovering it moves without being
|
||||
* pressed (input_stylus_hover_moves_pointer).
|
||||
* - Press: pointer 0 pressed, pointer count 1. The tip pressing
|
||||
* harder than input_stylus_pressure_sensitivity allows is a press;
|
||||
* with input_stylus_require_contact_for_click off, so is the barrel
|
||||
* button, touching or hovering.
|
||||
* - Barrel button: the right mouse button.
|
||||
*
|
||||
* Pointer indices keep their meaning: index N is the Nth touch. A pen
|
||||
* is one touch, so it never occupies more than index 0. Reporting the
|
||||
* tip and the barrel button as further "touches" would read as a
|
||||
* two- and three-finger touch to everything that counts pointers,
|
||||
* this driver's own lightgun mapping included (two pointers are
|
||||
* turbo, three are reload). */
|
||||
|
||||
/* The pen's position, written to pointer 0. */
|
||||
static void android_stylus_set_position(android_input_t *android,
|
||||
float x, float y)
|
||||
{
|
||||
struct video_viewport vp = {0};
|
||||
|
||||
/* The same pair of calls the touchscreen path makes: the confined
|
||||
* variant for the pointer query, the plain one for the true
|
||||
* offscreen value. */
|
||||
video_driver_translate_coord_viewport_confined_wrap(
|
||||
&vp, x, y,
|
||||
&android->pointer[0].confined_x,
|
||||
&android->pointer[0].confined_y,
|
||||
&android->pointer[0].full_x,
|
||||
&android->pointer[0].full_y);
|
||||
|
||||
video_driver_translate_coord_viewport_wrap(
|
||||
&vp, x, y,
|
||||
&android->pointer[0].x,
|
||||
&android->pointer[0].y,
|
||||
&android->pointer[0].full_x,
|
||||
&android->pointer[0].full_y);
|
||||
}
|
||||
|
||||
/* Press or release pointer 0 for the pen. pointer_count is shared
|
||||
* with the touchscreen. A pressing pen takes it, as a touchscreen
|
||||
* event does, and says so on every event so a finger lifting in
|
||||
* between cannot leave it released. A pen that is not pressing leaves
|
||||
* it alone, apart from letting go of its own press: a hover event
|
||||
* must not release a finger. */
|
||||
static void android_stylus_set_pressed(android_input_t *android,
|
||||
bool pressed)
|
||||
{
|
||||
if (pressed)
|
||||
android->pointer_count = 1;
|
||||
else if (android->stylus_press_active)
|
||||
android->pointer_count = 0;
|
||||
|
||||
android->stylus_press_active = pressed;
|
||||
}
|
||||
|
||||
static INLINE void android_input_poll_event_type_motion(
|
||||
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;
|
||||
bool keyup = (
|
||||
action == AMOTION_EVENT_ACTION_UP
|
||||
|| action == AMOTION_EVENT_ACTION_CANCEL
|
||||
|| action == AMOTION_EVENT_ACTION_POINTER_UP);
|
||||
int getaction, action;
|
||||
size_t motion_ptr;
|
||||
int64_t event_time_ms;
|
||||
float x, y;
|
||||
int32_t tool_type;
|
||||
bool is_stylus, is_finger, is_hover_action;
|
||||
settings_t *settings;
|
||||
bool require_contact, tip_down, stylus_pressed;
|
||||
bool side_pressed, tip_touching;
|
||||
float pressure, distance, pressure_threshold;
|
||||
int buttons;
|
||||
bool keyup;
|
||||
|
||||
getaction = AMotionEvent_getAction(event);
|
||||
action = getaction & AMOTION_EVENT_ACTION_MASK;
|
||||
motion_ptr = getaction >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||
event_time_ms = AMotionEvent_getEventTime(event) / 1000000;
|
||||
x = AMotionEvent_getX(event, motion_ptr);
|
||||
y = AMotionEvent_getY(event, motion_ptr);
|
||||
|
||||
tool_type = 0;
|
||||
if (p_AMotionEvent_getToolType && motion_ptr < AMotionEvent_getPointerCount(event))
|
||||
tool_type = AMotionEvent_getToolType(event, motion_ptr);
|
||||
|
||||
is_stylus = (tool_type == AMOTION_EVENT_TOOL_TYPE_STYLUS);
|
||||
is_finger = (tool_type == AMOTION_EVENT_TOOL_TYPE_FINGER);
|
||||
|
||||
/* Fall back to source bits if toolType is unknown. */
|
||||
if (!is_stylus && !is_finger)
|
||||
{
|
||||
is_stylus = ((source & AINPUT_SOURCE_STYLUS) == AINPUT_SOURCE_STYLUS);
|
||||
is_finger = ((source & AINPUT_SOURCE_TOUCHSCREEN) == AINPUT_SOURCE_TOUCHSCREEN);
|
||||
}
|
||||
|
||||
is_hover_action = (action == AMOTION_EVENT_ACTION_HOVER_MOVE ||
|
||||
action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
|
||||
action == AMOTION_EVENT_ACTION_HOVER_EXIT);
|
||||
|
||||
#ifdef DEBUG_ANDROID_INPUT
|
||||
RARCH_LOG("[RA Input] act=%d src=0x%x tool=%d dev=%d btn=0x%x dropped=%d\n",
|
||||
action, source, tool_type, AInputEvent_getDeviceId(event),
|
||||
p_AMotionEvent_getButtonState ?
|
||||
AMotionEvent_getButtonState(event) : 0, 0);
|
||||
#endif
|
||||
|
||||
if (is_stylus)
|
||||
{
|
||||
settings = config_get_ptr();
|
||||
if (!settings)
|
||||
return;
|
||||
|
||||
if (motion_ptr >= MAX_TOUCH)
|
||||
return;
|
||||
|
||||
if (!settings->bools.input_stylus_enable)
|
||||
{
|
||||
#ifdef DEBUG_ANDROID_INPUT
|
||||
RARCH_LOG("[RA Input] Stylus support disabled - ignoring stylus event\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* Refresh overlay auto-hide timer (runloop.c reads this) only after the
|
||||
* enable gate, so a passing pen does not hide the overlay for a user
|
||||
* who has disabled S-Pen support. */
|
||||
g_android_stylus_last_event_ns = (int64_t)cpu_features_get_time_usec() * 1000;
|
||||
|
||||
require_contact = settings->bools.input_stylus_require_contact_for_click;
|
||||
buttons = p_AMotionEvent_getButtonState ?
|
||||
AMotionEvent_getButtonState(event) : 0;
|
||||
/* Which of the two the barrel button reports varies by device. */
|
||||
side_pressed = (buttons & (AMOTION_EVENT_BUTTON_STYLUS_PRIMARY
|
||||
| AMOTION_EVENT_BUTTON_STYLUS_SECONDARY)) != 0;
|
||||
|
||||
/* The barrel button is the pen's secondary button: report it
|
||||
* the way a mouse's is (see the mapping above). */
|
||||
android->mouse_r = side_pressed;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case AMOTION_EVENT_ACTION_HOVER_ENTER:
|
||||
case AMOTION_EVENT_ACTION_HOVER_MOVE:
|
||||
case AMOTION_EVENT_ACTION_HOVER_EXIT:
|
||||
#ifdef DEBUG_ANDROID_INPUT
|
||||
RARCH_LOG("[RA Input] Stylus hover (act=%d) - arming hover guard\n", action);
|
||||
#endif
|
||||
hover_guard_arm(x, y, event_time_ms, 100);
|
||||
|
||||
android->stylus_proximity_active = true;
|
||||
android->stylus_proximity_until_ns =
|
||||
AMotionEvent_getEventTime(event) + 120000000; /* 120ms */
|
||||
android->quick_tap_time = 0;
|
||||
|
||||
if (action == AMOTION_EVENT_ACTION_HOVER_EXIT)
|
||||
{
|
||||
/* Out of range: nothing the pen held stays held. */
|
||||
android->mouse_r = false;
|
||||
android_stylus_set_pressed(android, false);
|
||||
return;
|
||||
}
|
||||
|
||||
/* A hovering pen presses only when the user allowed a click
|
||||
* without contact and holds the barrel button. */
|
||||
stylus_pressed = !require_contact && side_pressed;
|
||||
|
||||
if ( stylus_pressed
|
||||
|| settings->bools.input_stylus_hover_moves_pointer)
|
||||
android_stylus_set_position(android, x, y);
|
||||
|
||||
android_stylus_set_pressed(android, stylus_pressed);
|
||||
return;
|
||||
|
||||
case AMOTION_EVENT_ACTION_UP:
|
||||
case AMOTION_EVENT_ACTION_CANCEL:
|
||||
/* A lifted pen keeps reporting its barrel button through
|
||||
* the hover events that follow; a cancelled gesture has
|
||||
* none coming. */
|
||||
if (action == AMOTION_EVENT_ACTION_CANCEL)
|
||||
android->mouse_r = false;
|
||||
android->stylus_contact_active = false;
|
||||
android_stylus_set_pressed(android, false);
|
||||
#ifdef DEBUG_ANDROID_INPUT
|
||||
RARCH_LOG("[Stylus] UP - pointer released\n");
|
||||
#endif
|
||||
return;
|
||||
|
||||
case AMOTION_EVENT_ACTION_DOWN:
|
||||
case AMOTION_EVENT_ACTION_MOVE:
|
||||
if (action == AMOTION_EVENT_ACTION_DOWN)
|
||||
{
|
||||
g_hover_guard_active = false;
|
||||
android->stylus_proximity_active = false;
|
||||
}
|
||||
|
||||
pressure = p_AMotionEvent_getPressure ?
|
||||
AMotionEvent_getPressure(event, motion_ptr) : 1.0f;
|
||||
distance = 0.0f;
|
||||
if (p_AMotionEvent_getAxisValue &&
|
||||
motion_ptr < AMotionEvent_getPointerCount(event))
|
||||
distance = AMotionEvent_getAxisValue(event,
|
||||
AMOTION_EVENT_AXIS_DISTANCE, motion_ptr);
|
||||
|
||||
/* Contact is distance-based (instant, no pressure needed);
|
||||
* click is pressure-based against a user-configurable threshold. */
|
||||
tip_touching = (distance <= 0.0f);
|
||||
|
||||
/* Map sensitivity 1..100 to threshold 0.02475..0.0 (higher = more
|
||||
* sensitive; 100 = instant click on any pressure > 0). */
|
||||
{
|
||||
unsigned sens = settings->uints.input_stylus_pressure_sensitivity;
|
||||
if (sens > 100)
|
||||
sens = 100;
|
||||
pressure_threshold = (100 - (int)sens) * 0.00025f;
|
||||
}
|
||||
tip_down = tip_touching && (pressure > pressure_threshold);
|
||||
stylus_pressed = tip_down || (!require_contact && side_pressed);
|
||||
|
||||
#ifdef DEBUG_ANDROID_INPUT
|
||||
RARCH_LOG("[RA Input] S Pen contact - req_contact:%s tip_down:%s "
|
||||
"side:%s pressed:%s p=%.3f d=%.3f\n",
|
||||
require_contact ? "Y" : "N", tip_down ? "Y" : "N",
|
||||
side_pressed ? "Y" : "N", stylus_pressed ? "Y" : "N",
|
||||
pressure, distance);
|
||||
#endif
|
||||
|
||||
if (tip_touching)
|
||||
android->stylus_contact_active = true;
|
||||
|
||||
/* Before the tip has touched, a DOWN or MOVE that still
|
||||
* reports distance is a hover: the position stays where the
|
||||
* last contact left it, so the cursor does not jump. */
|
||||
if (android->stylus_contact_active || stylus_pressed)
|
||||
android_stylus_set_position(android, x, y);
|
||||
|
||||
android_stylus_set_pressed(android, stylus_pressed);
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Drop phantom touches near a recent stylus hover (see hover_guard). */
|
||||
if ((action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE) &&
|
||||
hover_guard_drop(x, y, event_time_ms, 12.0f))
|
||||
{
|
||||
#ifdef DEBUG_ANDROID_INPUT
|
||||
RARCH_LOG("[RA Input] DROPPED phantom touch near stylus hover (x=%.1f y=%.1f)\n", x, y);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
keyup = (action == AMOTION_EVENT_ACTION_UP ||
|
||||
action == AMOTION_EVENT_ACTION_CANCEL ||
|
||||
action == AMOTION_EVENT_ACTION_POINTER_UP);
|
||||
|
||||
/* If source is mouse then calculate button state
|
||||
* and mouse deltas and don't process as touchscreen event.
|
||||
* NOTE: AINPUT_SOURCE_* defines have multiple bits set so do full check */
|
||||
if ( (source & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE
|
||||
if (((source & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE
|
||||
|| (source & AINPUT_SOURCE_MOUSE_RELATIVE) == AINPUT_SOURCE_MOUSE_RELATIVE)
|
||||
&& !is_stylus)
|
||||
{
|
||||
if (!android->mouse_activated)
|
||||
{
|
||||
@@ -1441,7 +1788,18 @@ static INLINE void android_input_poll_event_type_motion(
|
||||
}
|
||||
|
||||
android_mouse_calculate_deltas(android,event,motion_ptr,source);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Drop hover events from touchscreen processing so they can't drive
|
||||
* clicks. This has to come after the mouse branch above: a mouse
|
||||
* moved with no button held reports its motion as hover events, and
|
||||
* dropping those first would leave it unable to move. */
|
||||
if (is_hover_action)
|
||||
{
|
||||
#ifdef DEBUG_ANDROID_INPUT
|
||||
RARCH_LOG("[Android Input] Blocking hover event from touchscreen processing - action:%d source:0x%X\n", action, source);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2873,7 +3231,31 @@ static int16_t android_input_state(
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_MOUSE_LEFT:
|
||||
return android->mouse_l || android_check_quick_tap(android);
|
||||
if (android->mouse_activated)
|
||||
{
|
||||
#ifdef DEBUG_ANDROID_INPUT
|
||||
RARCH_LOG("[Mouse Query] mouse_l=%d activated=%d\n",
|
||||
android->mouse_l, android->mouse_activated);
|
||||
#endif
|
||||
return android->mouse_l;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Suppress quick-tap emulation while a stylus is nearby;
|
||||
* only finger taps should trigger it. */
|
||||
bool allow_quick_tap;
|
||||
android_stylus_proximity_check_expire(android);
|
||||
allow_quick_tap = !android->stylus_proximity_active
|
||||
&& !g_hover_guard_active;
|
||||
|
||||
if (allow_quick_tap)
|
||||
return android_check_quick_tap(android);
|
||||
else
|
||||
{
|
||||
android->quick_tap_time = 0; /* cancel any pending quick tap when stylus nearby */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
case RETRO_DEVICE_ID_MOUSE_RIGHT:
|
||||
return android->mouse_r;
|
||||
case RETRO_DEVICE_ID_MOUSE_MIDDLE:
|
||||
@@ -2944,7 +3326,25 @@ static int16_t android_input_state(
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_TURBO:
|
||||
return android->mouse_r || android->pointer_count == 2;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER:
|
||||
return android->mouse_l || android_check_quick_tap(android) || android->pointer_count == 1;
|
||||
if (android->mouse_activated)
|
||||
return android->mouse_l || android->pointer_count == 1;
|
||||
else
|
||||
{
|
||||
/* Suppress quick-tap emulation while a stylus is nearby;
|
||||
* only finger taps should trigger it. */
|
||||
bool allow_quick_tap;
|
||||
android_stylus_proximity_check_expire(android);
|
||||
allow_quick_tap = !android->stylus_proximity_active
|
||||
&& !g_hover_guard_active;
|
||||
|
||||
if (allow_quick_tap)
|
||||
return android_check_quick_tap(android) || android->pointer_count == 1;
|
||||
else
|
||||
{
|
||||
android->quick_tap_time = 0; /* cancel any pending quick tap when stylus nearby */
|
||||
return android->pointer_count == 1;
|
||||
}
|
||||
}
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN:
|
||||
if (idx >= MAX_TOUCH)
|
||||
return 0;
|
||||
@@ -2973,6 +3373,12 @@ static int16_t android_input_state(
|
||||
return android->pointer[idx].full_y;
|
||||
return android->pointer[idx].confined_y;
|
||||
case RETRO_DEVICE_ID_POINTER_PRESSED:
|
||||
#ifdef DEBUG_ANDROID_INPUT
|
||||
RARCH_LOG("[PtrQuery] count=%d x0=%d y0=%d\n",
|
||||
android->pointer_count,
|
||||
android->pointer_count > 0 ? android->pointer[0].confined_x : 0,
|
||||
android->pointer_count > 0 ? android->pointer[0].confined_y : 0);
|
||||
#endif
|
||||
/* On mobile platforms, touches outside screen / core viewport are not reported. */
|
||||
if (device == RARCH_DEVICE_POINTER_SCREEN)
|
||||
return (idx < android->pointer_count) &&
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
* Copyright (C) 2012-2015 - Michael Lelli
|
||||
* Copyright (C) 2013-2014 - Steven Crowe
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ANDROID_INPUT_H__
|
||||
#define __ANDROID_INPUT_H__
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
/* True for ~2s after the last stylus event. */
|
||||
bool android_input_stylus_recently_active(void);
|
||||
|
||||
#endif
|
||||
+14
-4
@@ -2405,6 +2405,7 @@ static int16_t input_state_device(
|
||||
#ifdef HAVE_OVERLAY
|
||||
if ( (input_st->overlay_ptr)
|
||||
&& (input_st->overlay_ptr->flags & INPUT_OVERLAY_ENABLE)
|
||||
&& !(input_st->overlay_ptr->flags & INPUT_OVERLAY_STYLUS_HIDDEN)
|
||||
&& (settings->bools.input_overlay_pointer_enable))
|
||||
res = input_overlay_pointing_device_state(
|
||||
settings->ints.input_overlay_lightgun_port,
|
||||
@@ -4433,8 +4434,14 @@ INPUT_NOINLINE static void input_poll_overlay(
|
||||
/* input_data is dereferenced by the driver's pointer paths, so a
|
||||
* NULL current_data (mid driver teardown/reinit, e.g. Android
|
||||
* surface recreation) must skip driver input for this frame
|
||||
* instead of faulting inside the input driver. */
|
||||
if (input->input_state && input_data)
|
||||
* instead of faulting inside the input driver.
|
||||
*
|
||||
* A stylus-hidden overlay reads no touches either: with none, the
|
||||
* rest of this poll releases whatever a finger was holding (button,
|
||||
* key, pointing device) the same way lifting it would. */
|
||||
if ( input->input_state
|
||||
&& input_data
|
||||
&& !(ol->flags & INPUT_OVERLAY_STYLUS_HIDDEN))
|
||||
{
|
||||
rarch_joypad_info_t joypad_info;
|
||||
unsigned device = (ol->active->flags & OVERLAY_FULL_SCREEN)
|
||||
@@ -4723,8 +4730,11 @@ INPUT_NOINLINE static void input_poll_overlay(
|
||||
(input_overlay_show_inputs == OVERLAY_SHOW_INPUT_TOUCHED),
|
||||
input_overlay_show_inputs_port);
|
||||
|
||||
/* Block other touchscreen input as needed. */
|
||||
if ( button_pressed
|
||||
/* Block other touchscreen input as needed. A stylus-hidden overlay
|
||||
* blocks nothing: the pen's pointer state has to reach the core. */
|
||||
if (ol->flags & INPUT_OVERLAY_STYLUS_HIDDEN)
|
||||
input_st->flags &= ~INP_FLAG_BLOCK_POINTER_INPUT;
|
||||
else if (button_pressed
|
||||
#if TARGET_OS_IPHONE
|
||||
|| (ptr_state->device_mask & (1 << RETRO_DEVICE_LIGHTGUN))
|
||||
|| (ol->flags & INPUT_OVERLAY_BLOCKED))
|
||||
|
||||
@@ -124,7 +124,12 @@ enum INPUT_OVERLAY_FLAGS
|
||||
INPUT_OVERLAY_TEXTURES_DECLINED = (1 << 5),
|
||||
/* The pack names its LED images (overlayN_descM_led): the overlay
|
||||
* LED driver shows and hides those, and ledN_map is not used. */
|
||||
INPUT_OVERLAY_HAS_LEDS = (1 << 6)
|
||||
INPUT_OVERLAY_HAS_LEDS = (1 << 6),
|
||||
/* A stylus is in use: the overlay stays loaded but is not drawn,
|
||||
* takes no touches and answers no pointer queries, so the pen
|
||||
* reaches the core through the input driver. Level-triggered from
|
||||
* the run loop. */
|
||||
INPUT_OVERLAY_STYLUS_HIDDEN = (1 << 7)
|
||||
};
|
||||
|
||||
enum OVERLAY_FLAGS
|
||||
|
||||
@@ -133,7 +133,8 @@ void input_overlay_alpha_pass(input_overlay_t *ol, float mod,
|
||||
if (!ol || !ol->active || !ol->iface->set_alpha)
|
||||
return;
|
||||
|
||||
if (ol->flags & INPUT_OVERLAY_GAMEPAD_HIDDEN)
|
||||
if (ol->flags & (INPUT_OVERLAY_GAMEPAD_HIDDEN
|
||||
| INPUT_OVERLAY_STYLUS_HIDDEN))
|
||||
mod = 0.0f;
|
||||
n = ol->active->load_images_size;
|
||||
want = (ol->alpha_want && n <= ol->alpha_cap) ? ol->alpha_want : NULL;
|
||||
|
||||
@@ -1379,6 +1379,22 @@ MSG_HASH(
|
||||
MENU_ENUM_LABEL_INPUT_SELECT_PHYSICAL_KEYBOARD,
|
||||
MENU_ENUM_LABEL_INPUT_SELECT_PHYSICAL_KEYBOARD_STR
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_INPUT_STYLUS_ENABLE,
|
||||
"input_stylus_enable"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_INPUT_STYLUS_REQUIRE_CONTACT_FOR_CLICK,
|
||||
"input_stylus_require_contact_for_click"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_INPUT_STYLUS_HOVER_MOVES_POINTER,
|
||||
"input_stylus_hover_moves_pointer"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_INPUT_STYLUS_PRESSURE_SENSITIVITY,
|
||||
"input_stylus_pressure_sensitivity"
|
||||
)
|
||||
#endif
|
||||
#ifdef ANDROID
|
||||
MSG_HASH(
|
||||
|
||||
@@ -10678,6 +10678,38 @@ MSG_HASH(
|
||||
MENU_ENUM_LABEL_HELP_INPUT_SELECT_PHYSICAL_KEYBOARD,
|
||||
"If RetroArch identifies a hardware keyboard as some kind of gamepad, this setting can be used to force RetroArch to treat the misidentified device as a keyboard.\nThis can be useful if you are trying to emulate a computer in some Android TV device and also own a physical keyboard that can be attached to the box."
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_STYLUS_ENABLE,
|
||||
"Stylus Support"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_SUBLABEL_INPUT_STYLUS_ENABLE,
|
||||
"Enable stylus devices. Provides precise input for drawing and pointing games. Disable if experiencing input conflicts."
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_STYLUS_REQUIRE_CONTACT_FOR_CLICK,
|
||||
"Stylus Requires Screen Contact"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_SUBLABEL_INPUT_STYLUS_REQUIRE_CONTACT_FOR_CLICK,
|
||||
"ON: Stylus must physically touch screen to register as a click. OFF: Stylus can click by touching screen OR by hovering and pressing the side button."
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_STYLUS_HOVER_MOVES_POINTER,
|
||||
"Stylus Hover Moves Cursor"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_SUBLABEL_INPUT_STYLUS_HOVER_MOVES_POINTER,
|
||||
"Allow stylus hover (without touching screen) to move the cursor. Essential for drawing and painting games or lightgun games. Turn OFF if cursor moves unexpectedly."
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_STYLUS_PRESSURE_SENSITIVITY,
|
||||
"Stylus Pressure Sensitivity"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_SUBLABEL_INPUT_STYLUS_PRESSURE_SENSITIVITY,
|
||||
"Stylus touch sensitivity. Higher values = more sensitive (lighter touch). Default 70 works for most devices. Lower if using a screen protector (40-50)."
|
||||
)
|
||||
#endif
|
||||
/* GENERATED REGION: analog deadzone and sensitivity group (see settings_def_analog_deadzone.h). */
|
||||
#define SETTINGS_DEF_STRINGS_PASS
|
||||
|
||||
@@ -404,6 +404,10 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_touch_vmouse_touchpad, MENU_
|
||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_touch_vmouse_trackball, MENU_ENUM_SUBLABEL_INPUT_TOUCH_VMOUSE_TRACKBALL)
|
||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_touch_vmouse_gesture, MENU_ENUM_SUBLABEL_INPUT_TOUCH_VMOUSE_GESTURE)
|
||||
#endif
|
||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_stylus_enable, MENU_ENUM_SUBLABEL_INPUT_STYLUS_ENABLE)
|
||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_stylus_require_contact_for_click, MENU_ENUM_SUBLABEL_INPUT_STYLUS_REQUIRE_CONTACT_FOR_CLICK)
|
||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_stylus_hover_moves_pointer, MENU_ENUM_SUBLABEL_INPUT_STYLUS_HOVER_MOVES_POINTER)
|
||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_stylus_pressure_sensitivity, MENU_ENUM_SUBLABEL_INPUT_STYLUS_PRESSURE_SENSITIVITY)
|
||||
|
||||
|
||||
#ifndef HAVE_DYNAMIC
|
||||
@@ -3383,6 +3387,18 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
|
||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_touch_vmouse_gesture);
|
||||
break;
|
||||
#endif
|
||||
case MENU_ENUM_LABEL_INPUT_STYLUS_ENABLE:
|
||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_stylus_enable);
|
||||
break;
|
||||
case MENU_ENUM_LABEL_INPUT_STYLUS_REQUIRE_CONTACT_FOR_CLICK:
|
||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_stylus_require_contact_for_click);
|
||||
break;
|
||||
case MENU_ENUM_LABEL_INPUT_STYLUS_HOVER_MOVES_POINTER:
|
||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_stylus_hover_moves_pointer);
|
||||
break;
|
||||
case MENU_ENUM_LABEL_INPUT_STYLUS_PRESSURE_SENSITIVITY:
|
||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_stylus_pressure_sensitivity);
|
||||
break;
|
||||
case MENU_ENUM_LABEL_AUDIO_MIXER_VOLUME:
|
||||
#ifdef HAVE_AUDIOMIXER
|
||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_mixer_volume);
|
||||
|
||||
@@ -9850,6 +9850,10 @@ unsigned menu_displaylist_build_list(
|
||||
#endif
|
||||
#ifdef ANDROID
|
||||
{MENU_ENUM_LABEL_ANDROID_INPUT_DISCONNECT_WORKAROUND, PARSE_ONLY_BOOL, true},
|
||||
{MENU_ENUM_LABEL_INPUT_STYLUS_ENABLE, PARSE_ONLY_BOOL, true},
|
||||
{MENU_ENUM_LABEL_INPUT_STYLUS_REQUIRE_CONTACT_FOR_CLICK, PARSE_ONLY_BOOL, true},
|
||||
{MENU_ENUM_LABEL_INPUT_STYLUS_HOVER_MOVES_POINTER, PARSE_ONLY_BOOL, true},
|
||||
{MENU_ENUM_LABEL_INPUT_STYLUS_PRESSURE_SENSITIVITY, PARSE_ONLY_UINT, true},
|
||||
{MENU_ENUM_LABEL_INPUT_BLOCK_TIMEOUT, PARSE_ONLY_UINT, true},
|
||||
#endif
|
||||
{MENU_ENUM_LABEL_INPUT_POLL_TYPE_BEHAVIOR, PARSE_ONLY_UINT, true},
|
||||
|
||||
+3
-2
@@ -6532,8 +6532,9 @@ MENU_NOINLINE static int menu_input_post_iterate(
|
||||
/* Normal menu input */
|
||||
else
|
||||
{
|
||||
/* Detect gesture type */
|
||||
if (!(menu_input->pointer.flags & MENU_INP_PTR_FLG_DRAGGED))
|
||||
if (menu_input->pointer.type != MENU_POINTER_TOUCHSCREEN)
|
||||
point.gesture = MENU_INPUT_GESTURE_NONE;
|
||||
else if (!(menu_input->pointer.flags & MENU_INP_PTR_FLG_DRAGGED))
|
||||
{
|
||||
/* Pointer hasn't moved - check press duration */
|
||||
if (menu_input->pointer.press_duration
|
||||
|
||||
@@ -15432,6 +15432,67 @@ static void settings_build_input(
|
||||
general_write_handler,
|
||||
general_read_handler,
|
||||
SD_FLAG_NONE);
|
||||
|
||||
CONFIG_BOOL(
|
||||
list, list_info,
|
||||
&settings->bools.input_stylus_enable,
|
||||
MENU_ENUM_LABEL_INPUT_STYLUS_ENABLE,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_STYLUS_ENABLE,
|
||||
true,
|
||||
MENU_ENUM_LABEL_VALUE_OFF,
|
||||
MENU_ENUM_LABEL_VALUE_ON,
|
||||
&group_info,
|
||||
&subgroup_info,
|
||||
parent_group,
|
||||
general_write_handler,
|
||||
general_read_handler,
|
||||
SD_FLAG_NONE);
|
||||
|
||||
CONFIG_BOOL(
|
||||
list, list_info,
|
||||
&settings->bools.input_stylus_require_contact_for_click,
|
||||
MENU_ENUM_LABEL_INPUT_STYLUS_REQUIRE_CONTACT_FOR_CLICK,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_STYLUS_REQUIRE_CONTACT_FOR_CLICK,
|
||||
true,
|
||||
MENU_ENUM_LABEL_VALUE_OFF,
|
||||
MENU_ENUM_LABEL_VALUE_ON,
|
||||
&group_info,
|
||||
&subgroup_info,
|
||||
parent_group,
|
||||
general_write_handler,
|
||||
general_read_handler,
|
||||
SD_FLAG_NONE);
|
||||
|
||||
CONFIG_BOOL(
|
||||
list, list_info,
|
||||
&settings->bools.input_stylus_hover_moves_pointer,
|
||||
MENU_ENUM_LABEL_INPUT_STYLUS_HOVER_MOVES_POINTER,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_STYLUS_HOVER_MOVES_POINTER,
|
||||
false,
|
||||
MENU_ENUM_LABEL_VALUE_OFF,
|
||||
MENU_ENUM_LABEL_VALUE_ON,
|
||||
&group_info,
|
||||
&subgroup_info,
|
||||
parent_group,
|
||||
general_write_handler,
|
||||
general_read_handler,
|
||||
SD_FLAG_NONE);
|
||||
|
||||
CONFIG_UINT(
|
||||
list, list_info,
|
||||
&settings->uints.input_stylus_pressure_sensitivity,
|
||||
MENU_ENUM_LABEL_INPUT_STYLUS_PRESSURE_SENSITIVITY,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_STYLUS_PRESSURE_SENSITIVITY,
|
||||
DEFAULT_INPUT_STYLUS_PRESSURE_SENSITIVITY,
|
||||
&group_info,
|
||||
&subgroup_info,
|
||||
parent_group,
|
||||
general_write_handler,
|
||||
general_read_handler);
|
||||
SETTINGS_ACTION_SET(ok, &(*list)[list_info->index - 1], &setting_action_ok_uint)
|
||||
SETTINGS_ACTION_SET(repr, &(*list)[list_info->index - 1], &setting_get_string_representation_max_users)
|
||||
(*list)[list_info->index - 1].offset_by = 1;
|
||||
menu_settings_list_current_add_range(list, list_info, 1, 100, 1, true, true);
|
||||
#endif
|
||||
#ifdef HAVE_SDL3
|
||||
{
|
||||
|
||||
+12
@@ -2149,6 +2149,10 @@ enum msg_hash_enums
|
||||
MENU_ENUM_LABEL_INPUT_DEVICE_RESERVED_DEVICE_NAME_LAST = MENU_ENUM_LABEL_INPUT_DEVICE_RESERVED_DEVICE_NAME + MAX_USERS,
|
||||
MENU_ENUM_LABEL_INPUT_MOUSE_INDEX,
|
||||
MENU_ENUM_LABEL_INPUT_MOUSE_INDEX_LAST = MENU_ENUM_LABEL_INPUT_MOUSE_INDEX + MAX_USERS,
|
||||
MENU_ENUM_LABEL_INPUT_STYLUS_ENABLE,
|
||||
MENU_ENUM_LABEL_INPUT_STYLUS_REQUIRE_CONTACT_FOR_CLICK,
|
||||
MENU_ENUM_LABEL_INPUT_STYLUS_HOVER_MOVES_POINTER,
|
||||
MENU_ENUM_LABEL_INPUT_STYLUS_PRESSURE_SENSITIVITY,
|
||||
MENU_ENUM_LABEL_INPUT_REMAP_PORT,
|
||||
MENU_ENUM_LABEL_INPUT_REMAP_PORT_LAST = MENU_ENUM_LABEL_INPUT_REMAP_PORT + MAX_USERS,
|
||||
|
||||
@@ -2571,6 +2575,10 @@ enum msg_hash_enums
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_WHEEL_DOWN,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_UP,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_HORIZ_WHEEL_DOWN,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_STYLUS_ENABLE,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_STYLUS_REQUIRE_CONTACT_FOR_CLICK,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_STYLUS_HOVER_MOVES_POINTER,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_STYLUS_PRESSURE_SENSITIVITY,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS,
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS,
|
||||
@@ -2690,6 +2698,10 @@ enum msg_hash_enums
|
||||
MENU_ENUM_SUBLABEL_INPUT_DEVICE_RESERVATION_TYPE,
|
||||
MENU_ENUM_LABEL_HELP_INPUT_DEVICE_RESERVATION_TYPE,
|
||||
MENU_ENUM_SUBLABEL_INPUT_MOUSE_INDEX,
|
||||
MENU_ENUM_SUBLABEL_INPUT_STYLUS_ENABLE,
|
||||
MENU_ENUM_SUBLABEL_INPUT_STYLUS_REQUIRE_CONTACT_FOR_CLICK,
|
||||
MENU_ENUM_SUBLABEL_INPUT_STYLUS_HOVER_MOVES_POINTER,
|
||||
MENU_ENUM_SUBLABEL_INPUT_STYLUS_PRESSURE_SENSITIVITY,
|
||||
MENU_ENUM_SUBLABEL_INPUT_ADC_TYPE,
|
||||
MENU_ENUM_LABEL_HELP_INPUT_ADC_TYPE,
|
||||
MENU_ENUM_SUBLABEL_INPUT_BIND_ALL,
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
#if defined(ANDROID)
|
||||
#include "play_feature_delivery/play_feature_delivery.h"
|
||||
#include "frontend/drivers/platform_unix.h"
|
||||
#include "input/drivers/android_input.h"
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID) && defined(HAVE_SAF)
|
||||
@@ -6725,6 +6726,29 @@ static enum runloop_state_enum runloop_check_state(
|
||||
last_controller_connected = controller_connected;
|
||||
}
|
||||
|
||||
#if defined(ANDROID)
|
||||
/* Hide the on-screen overlay while a stylus is in use, and bring
|
||||
* it back once the pen has been idle for a moment (the window is
|
||||
* android_input.c's). The overlay is hidden, not unloaded:
|
||||
* unloading and reloading a pack is file and texture work, and a
|
||||
* pen leaving and returning would trigger it over and over while
|
||||
* a core runs. While hidden it takes no touches and answers no
|
||||
* pointer queries (INPUT_OVERLAY_STYLUS_HIDDEN), so the pen
|
||||
* reaches the core through the input driver whether or not the
|
||||
* overlay is set up as a pointing device.
|
||||
* Level-triggered, like the gamepad soft-hide above: the overlay
|
||||
* can be replaced at any time, so the flag is set on whichever
|
||||
* one is current this frame. */
|
||||
if (input_st->overlay_ptr)
|
||||
{
|
||||
if ( settings->bools.input_stylus_enable
|
||||
&& android_input_stylus_recently_active())
|
||||
input_st->overlay_ptr->flags |= INPUT_OVERLAY_STYLUS_HIDDEN;
|
||||
else
|
||||
input_st->overlay_ptr->flags &= ~INPUT_OVERLAY_STYLUS_HIDDEN;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check next overlay hotkey */
|
||||
HOTKEY_CHECK(RARCH_OVERLAY_NEXT, CMD_EVENT_OVERLAY_NEXT, true, &check_next_rotation);
|
||||
|
||||
|
||||
@@ -405,6 +405,9 @@ bool netplay_request_device_p13 1 0
|
||||
bool netplay_request_device_p14 1 0
|
||||
bool netplay_request_device_p15 1 0
|
||||
bool netplay_request_device_p16 1 0
|
||||
bool input_stylus_enable 1 1
|
||||
bool input_stylus_require_contact_for_click 1 1
|
||||
bool input_stylus_hover_moves_pointer 1 1
|
||||
int custom_viewport_x 0 0
|
||||
int custom_viewport_y 0 0
|
||||
int video_windowed_position_x 1 0
|
||||
@@ -588,6 +591,7 @@ uint video_stream_scale_factor 1 1
|
||||
uint video_hdr_mode 1 0
|
||||
uint video_swapchain_bit_depth 1 0
|
||||
uint streaming_mode 1 STREAMING_MODE_TWITCH
|
||||
uint input_stylus_pressure_sensitivity 1 70
|
||||
uint input_sensor_orientation 1 0
|
||||
uint input_overlay_show_inputs 1 OVERLAY_SHOW_INPUT_TOUCHED
|
||||
uint input_overlay_show_inputs_port 1 0
|
||||
|
||||
Reference in new issue
Block a user