From 28a4fb8e4eaeab1d0c058aaf2192814ea1017cdd Mon Sep 17 00:00:00 2001 From: nanahi <130121847+na-na-hi@users.noreply.github.com> Date: Sat, 27 Apr 2024 01:25:19 -0400 Subject: [PATCH] input: add multitouch support functions The goal of multitouch support is to interpret as little as possible: mpv just stores the touch point information and makes the position available for query. Does not participate in the deprecated input section system. The API is modeled after the common part of the touch input APIs of Win32, X11, and Wayland, to make sure the platform-specific implementations are as simple as possible. --- input/input.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++ input/input.h | 10 ++++++ 2 files changed, 102 insertions(+) diff --git a/input/input.c b/input/input.c index b24e82fe50..1f747f01cd 100644 --- a/input/input.c +++ b/input/input.c @@ -93,6 +93,11 @@ struct wheel_state { double unit_accum; }; +struct touch_point { + int id; + int x, y; +}; + struct input_ctx { mp_mutex mutex; struct mp_log *log; @@ -143,6 +148,10 @@ struct input_ctx { struct active_section *active_sections; int num_active_sections; + // List currently active touch points + struct touch_point *touch_points; + int num_touch_points; + unsigned int mouse_event_counter; struct mp_input_src *sources[MP_MAX_SOURCES]; @@ -894,6 +903,88 @@ void mp_input_set_mouse_pos(struct input_ctx *ictx, int x, int y) input_unlock(ictx); } +static int find_touch_point_index(struct input_ctx *ictx, int id) +{ + for (int i = 0; i < ictx->num_touch_points; i++) { + if (ictx->touch_points[i].id == id) + return i; + } + return -1; +} + +static void notify_touch_update(struct input_ctx *ictx) +{ + // queue dummy cmd so that touch-pos can notify observers + mp_cmd_t *cmd = mp_input_parse_cmd(ictx, bstr0("ignore"), ""); + queue_cmd(ictx, cmd); +} + +static void update_touch_point(struct input_ctx *ictx, int idx, int id, int x, int y) +{ + MP_TRACE(ictx, "Touch point %d update (id %d) %d/%d\n", + idx, id, x, y); + if (ictx->touch_points[idx].x == x && ictx->touch_points[idx].y == y) + return; + ictx->touch_points[idx].x = x; + ictx->touch_points[idx].y = y; + notify_touch_update(ictx); +} + +void mp_input_add_touch_point(struct input_ctx *ictx, int id, int x, int y) +{ + input_lock(ictx); + int idx = find_touch_point_index(ictx, id); + if (idx != -1) { + MP_WARN(ictx, "Touch point %d (id %d) already exists! Treat as update.\n", + idx, id); + update_touch_point(ictx, idx, id, x, y); + } else { + MP_TRACE(ictx, "Touch point %d add (id %d) %d/%d\n", + ictx->num_touch_points, id, x, y); + MP_TARRAY_APPEND(ictx, ictx->touch_points, ictx->num_touch_points, + (struct touch_point){id, x, y}); + notify_touch_update(ictx); + } + input_unlock(ictx); +} + +void mp_input_update_touch_point(struct input_ctx *ictx, int id, int x, int y) +{ + input_lock(ictx); + int idx = find_touch_point_index(ictx, id); + if (idx != -1) { + update_touch_point(ictx, idx, id, x, y); + } else { + MP_WARN(ictx, "Touch point id %d does not exist!\n", id); + } + input_unlock(ictx); +} + +void mp_input_remove_touch_point(struct input_ctx *ictx, int id) +{ + input_lock(ictx); + int idx = find_touch_point_index(ictx, 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); + notify_touch_update(ictx); + } + input_unlock(ictx); +} + +int mp_input_get_touch_pos(struct input_ctx *ictx, int count, int *x, int *y, int *id) +{ + input_lock(ictx); + int num_touch_points = ictx->num_touch_points; + for (int i = 0; i < MPMIN(num_touch_points, count); i++) { + x[i] = ictx->touch_points[i].x; + y[i] = ictx->touch_points[i].y; + id[i] = ictx->touch_points[i].id; + } + input_unlock(ictx); + return num_touch_points; +} + static bool test_mouse(struct input_ctx *ictx, int x, int y, int rej_flags) { bool res = false; @@ -1348,6 +1439,7 @@ struct input_ctx *mp_input_init(struct mpv_global *global, .wakeup_cb = wakeup_cb, .wakeup_ctx = wakeup_ctx, .active_sections = talloc_array(ictx, struct active_section, 0), + .touch_points = talloc_array(ictx, struct touch_point, 0), }; ictx->opts = ictx->opts_cache->opts; diff --git a/input/input.h b/input/input.h index 7f6707eeca..aafabdb9cb 100644 --- a/input/input.h +++ b/input/input.h @@ -102,6 +102,16 @@ void mp_input_set_mouse_pos_artificial(struct input_ctx *ictx, int x, int y); void mp_input_get_mouse_pos(struct input_ctx *ictx, int *x, int *y, int *hover); +// Add/Update/Remove a touch point (in window coordinates). +void mp_input_add_touch_point(struct input_ctx *ictx, int id, int x, int y); +void mp_input_update_touch_point(struct input_ctx *ictx, int id, int x, int y); +void mp_input_remove_touch_point(struct input_ctx *ictx, int id); + +// Get the positions of the touch points. xs and ys are arrays of at least +// count elements. ids is an array of at least count elements to uniquely +// identify touch points. Return the current number of touch points. +int mp_input_get_touch_pos(struct input_ctx *ictx, int count, int *xs, int *ys, int *ids); + // Return whether we want/accept mouse input. bool mp_input_mouse_enabled(struct input_ctx *ictx);