Compare commits

...

5 Commits

Author SHA1 Message Date
nanahi fb677da5c6
win32: support multitouch
Use the multitouch API. To disable system's defualt mouse emulation,
set --native-touch=yes.
2024-04-27 12:50:56 -04:00
nanahi 19010d769d
options: add --native-touch option
For platforms which send emulated mouse inputs for touch-unaware clients,
such as Win32 and X11, this option enables the native multitouch handling
and disables emulated mouse inputs. This enables interested scripts to
handle multitouch events while keeping compatibility with touch-unaware
scripts.
2024-04-27 12:50:56 -04:00
nanahi dcf724bad4
wayland_common: support multitouch
Use the multitouch API. No need to emulate mouse input as it's already
done by the input system.
2024-04-27 12:50:56 -04:00
nanahi 3bf4acc18b
input: add MP_TOUCH_RELEASE_ALL
Release all touch points. Used by some VOs like Wayland touch cancel
event.
2024-04-27 12:50:56 -04:00
nanahi 9a5e311f52
input: add --input-touch-emulate-mouse option
This adds --input-touch-emulate-mouse option, which controls whether to
enable legacy touch handling where touch inputs are emulated as mouse
inputs. This establishes a primary touch point (the one with the lowest
index) as the emulated mouse position, and MBTN_LEFT up/down with the
appearance of the first touch point and the disappearance of the last
touch point.

This fixes some problems with touch handling on Wayland, for example
attempting to pinch results in a double click.
2024-04-27 12:50:56 -04:00
9 changed files with 82 additions and 10 deletions

View File

@ -0,0 +1 @@
add --input-touch-emulate-mouse option

View File

@ -0,0 +1 @@
add --native-touch option

View File

@ -4101,6 +4101,11 @@ Input
Whether this applies depends on the VO backend and how it handles
keyboard input. Does not apply to terminal input.
``--native-touch=<yes|no>``
(Windows only)
Use system native touch events, instead of receiving them as emulated mouse
events (default: no). This is required for multi-touch support.
``--input-ar-delay``
Delay in milliseconds before we start to autorepeat a key (default: 200).
Set it to 0 to disable.
@ -4281,6 +4286,13 @@ Input
disabled by default in libmpv as well - it should be enabled if you want
the mpv default key bindings.
``--input-touch-emulate-mouse=<yes|no>``
When multi-touch support is enabled (either required by the platform,
or enabled by ``--native-touch``), emulate mouse move and button presses
for the touch events (default: yes). This is useful for compatibility
for mouse key bindings and scripts which read mouse positions for platforms
which do not support ``--native-touch=no`` (e.g. Wayland).
OSD
---

View File

@ -187,6 +187,7 @@ struct input_opts {
bool test;
bool allow_win_drag;
bool preprocess_wheel;
bool touch_emulate_mouse;
};
const struct m_sub_options input_config = {
@ -207,6 +208,7 @@ const struct m_sub_options input_config = {
{"input-vo-keyboard", OPT_BOOL(vo_key_input)},
{"input-media-keys", OPT_BOOL(use_media_keys)},
{"input-preprocess-wheel", OPT_BOOL(preprocess_wheel)},
{"input-touch-emulate-mouse", OPT_BOOL(touch_emulate_mouse)},
#if HAVE_SDL2_GAMEPAD
{"input-gamepad", OPT_BOOL(use_gamepad)},
#endif
@ -227,6 +229,7 @@ const struct m_sub_options input_config = {
.vo_key_input = true,
.allow_win_drag = true,
.preprocess_wheel = true,
.touch_emulate_mouse = true,
},
.change_flags = UPDATE_INPUT,
};
@ -732,6 +735,11 @@ static void feed_key(struct input_ctx *ictx, int code, double scale,
release_down_cmd(ictx, false);
return;
}
if (code == MP_TOUCH_RELEASE_ALL) {
MP_TRACE(ictx, "release all touch\n");
ictx->num_touch_points = 0;
return;
}
if (!opts->enable_mouse_movements && MP_KEY_IS_MOUSE(unmod) && !force_mouse)
return;
if (unmod == MP_KEY_MOUSE_LEAVE || unmod == MP_KEY_MOUSE_ENTER) {
@ -927,6 +935,9 @@ static void update_touch_point(struct input_ctx *ictx, int idx, int id, int x, i
return;
ictx->touch_points[idx].x = x;
ictx->touch_points[idx].y = y;
// Emulate mouse input from the primary touch point (the first one added)
if (ictx->opts->touch_emulate_mouse && idx == 0)
set_mouse_pos(ictx, x, y);
notify_touch_update(ictx);
}
@ -943,6 +954,11 @@ void mp_input_add_touch_point(struct input_ctx *ictx, int id, int x, int y)
ictx->num_touch_points, id, x, y);
MP_TARRAY_APPEND(ictx, ictx->touch_points, ictx->num_touch_points,
(struct touch_point){id, x, y});
// Emulate MBTN_LEFT down if this is the only touch point
if (ictx->opts->touch_emulate_mouse && ictx->num_touch_points == 1) {
set_mouse_pos(ictx, x, y);
feed_key(ictx, MP_MBTN_LEFT | MP_KEY_STATE_DOWN, 1, false);
}
notify_touch_update(ictx);
}
input_unlock(ictx);
@ -967,6 +983,9 @@ void mp_input_remove_touch_point(struct input_ctx *ictx, int id)
if (idx != -1) {
MP_TRACE(ictx, "Touch point %d remove (id %d)\n", idx, id);
MP_TARRAY_REMOVE_AT(ictx->touch_points, ictx->num_touch_points, idx);
// Emulate MBTN_LEFT up if there are no touch points left
if (ictx->opts->touch_emulate_mouse && ictx->num_touch_points == 0)
feed_key(ictx, MP_MBTN_LEFT | MP_KEY_STATE_UP, 1, false);
notify_touch_update(ictx);
}
input_unlock(ictx);

View File

@ -216,6 +216,8 @@
#define MP_KEY_ANY_UNICODE (MP_KEY_INTERN+5)
// For mp_input_put_key(): release all keys that are down.
#define MP_INPUT_RELEASE_ALL (MP_KEY_INTERN+6)
// For mp_input_put_key(): release all touch points.
#define MP_TOUCH_RELEASE_ALL (MP_KEY_INTERN+7)
// Emit a command even on key-up (normally key-up is ignored). This means by
// default they binding will be triggered on key-up instead of key-down.

View File

@ -169,6 +169,7 @@ static const m_option_t mp_vo_opt_list[] = {
{"keepaspect-window", OPT_BOOL(keepaspect_window)},
{"hidpi-window-scale", OPT_BOOL(hidpi_window_scale)},
{"native-fs", OPT_BOOL(native_fs)},
{"native-touch", OPT_BOOL(native_touch)},
{"show-in-taskbar", OPT_BOOL(show_in_taskbar)},
{"display-fps-override", OPT_DOUBLE(display_fps_override),
M_RANGE(0, DBL_MAX)},

View File

@ -56,6 +56,7 @@ typedef struct mp_vo_opts {
bool keepaspect_window;
bool hidpi_window_scale;
bool native_fs;
bool native_touch;
bool show_in_taskbar;
int64_t WinID;

View File

@ -1315,6 +1315,17 @@ static void update_cursor_passthrough(const struct vo_w32_state *w32)
}
}
static void update_native_touch(const struct vo_w32_state *w32)
{
if (w32->parent)
return;
if (w32->opts->native_touch)
RegisterTouchWindow(w32->window, 0);
else
UnregisterTouchWindow(w32->window);
}
static void set_ime_conversion_mode(const struct vo_w32_state *w32, DWORD mode)
{
if (w32->parent)
@ -1713,6 +1724,26 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
case WM_SHOWMENU:
mp_win32_menu_show(w32->menu_ctx, w32->window);
break;
case WM_TOUCH: {
UINT count = LOWORD(wParam);
TOUCHINPUT *inputs = talloc_array_ptrtype(NULL, inputs, count);
if (GetTouchInputInfo((HTOUCHINPUT)lParam, count, inputs, sizeof(TOUCHINPUT))) {
for (UINT i = 0; i < count; i++) {
TOUCHINPUT ti = inputs[i];
POINT pt = {TOUCH_COORD_TO_PIXEL(ti.x), TOUCH_COORD_TO_PIXEL(ti.y)};
ScreenToClient(w32->window, &pt);
if (ti.dwFlags & TOUCHEVENTF_DOWN)
mp_input_add_touch_point(w32->input_ctx, ti.dwID, pt.x, pt.y);
else if (ti.dwFlags & TOUCHEVENTF_MOVE)
mp_input_update_touch_point(w32->input_ctx, ti.dwID, pt.x, pt.y);
else if (ti.dwFlags & TOUCHEVENTF_UP)
mp_input_remove_touch_point(w32->input_ctx, ti.dwID);
}
}
CloseTouchInputHandle((HTOUCHINPUT)lParam);
talloc_free(inputs);
return 0;
}
}
if (message == w32->tbtn_created_msg) {
@ -1996,6 +2027,8 @@ static MP_THREAD_VOID gui_thread(void *ptr)
update_backdrop(w32);
if (w32->opts->cursor_passthrough)
update_cursor_passthrough(w32);
if (w32->opts->native_touch)
update_native_touch(w32);
if (SUCCEEDED(OleInitialize(NULL))) {
ole_ok = true;
@ -2193,6 +2226,8 @@ static int gui_thread_control(struct vo_w32_state *w32, int request, void *arg)
update_maximized_state(w32, false);
} else if (changed_option == &vo_opts->window_corners) {
update_corners_pref(w32);
} else if (changed_option == &vo_opts->native_touch) {
update_native_touch(w32);
} else if (changed_option == &vo_opts->geometry || changed_option == &vo_opts->autofit ||
changed_option == &vo_opts->autofit_smaller || changed_option == &vo_opts->autofit_larger)
{

View File

@ -440,19 +440,16 @@ static void touch_handle_down(void *data, struct wl_touch *wl_touch,
{
struct vo_wayland_seat *s = data;
struct vo_wayland_state *wl = s->wl;
wl->mouse_x = wl_fixed_to_int(x_w) * wl->scaling;
wl->mouse_y = wl_fixed_to_int(y_w) * wl->scaling;
int x = wl_fixed_to_int(x_w) * wl->scaling;
int y = wl_fixed_to_int(y_w) * wl->scaling;
mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_DOWN);
mp_input_add_touch_point(wl->vo->input_ctx, id, x, y);
enum xdg_toplevel_resize_edge edge;
if (!mp_input_test_dragging(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y) &&
!wl->locked_size && check_for_resize(wl, wl->opts->edge_pixels_touch, &edge))
{
xdg_toplevel_resize(wl->xdg_toplevel, s->seat, serial, edge);
// Explicitly send an UP event after the client finishes a resize
mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_UP);
} else {
// Save the serial and seat for voctrl-initialized dragging requests.
s->pointer_button_serial = serial;
@ -465,7 +462,7 @@ static void touch_handle_up(void *data, struct wl_touch *wl_touch,
{
struct vo_wayland_seat *s = data;
struct vo_wayland_state *wl = s->wl;
mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_UP);
mp_input_remove_touch_point(wl->vo->input_ctx, id);
wl->last_button_seat = NULL;
}
@ -475,10 +472,10 @@ static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
struct vo_wayland_seat *s = data;
struct vo_wayland_state *wl = s->wl;
wl->mouse_x = wl_fixed_to_int(x_w) * wl->scaling;
wl->mouse_y = wl_fixed_to_int(y_w) * wl->scaling;
int x = wl_fixed_to_int(x_w) * wl->scaling;
int y = wl_fixed_to_int(y_w) * wl->scaling;
mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
mp_input_update_touch_point(wl->vo->input_ctx, id, x, y);
}
static void touch_handle_frame(void *data, struct wl_touch *wl_touch)
@ -487,6 +484,9 @@ static void touch_handle_frame(void *data, struct wl_touch *wl_touch)
static void touch_handle_cancel(void *data, struct wl_touch *wl_touch)
{
struct vo_wayland_seat *s = data;
struct vo_wayland_state *wl = s->wl;
mp_input_put_key(wl->vo->input_ctx, MP_TOUCH_RELEASE_ALL);
}
static void touch_handle_shape(void *data, struct wl_touch *wl_touch,