diff --git a/input/input.c b/input/input.c index 4cf7c43acd..307b3416f6 100644 --- a/input/input.c +++ b/input/input.c @@ -158,6 +158,14 @@ struct input_ctx { struct touch_point *touch_points; int num_touch_points; + int tablet_x, tablet_y; + // Indicates tablet tools in proximity + bool tablet_tool_in_proximity; + bool tablet_tool_down; + bool tablet_tool_stylus_btn1_pressed; + bool tablet_tool_stylus_btn2_pressed; + bool tablet_tool_stylus_btn3_pressed; + unsigned int mouse_event_counter; struct mp_input_src *sources[MP_MAX_SOURCES]; @@ -197,6 +205,7 @@ struct input_opts { bool allow_win_drag; bool preprocess_wheel; bool touch_emulate_mouse; + bool tablet_emulate_mouse; }; const struct m_sub_options input_config = { @@ -219,6 +228,7 @@ const struct m_sub_options input_config = { {"input-media-keys", OPT_BOOL(use_media_keys)}, {"input-preprocess-wheel", OPT_BOOL(preprocess_wheel)}, {"input-touch-emulate-mouse", OPT_BOOL(touch_emulate_mouse)}, + {"input-tablet-emulate-mouse", OPT_BOOL(tablet_emulate_mouse)}, {"input-dragging-deadzone", OPT_INT(dragging_deadzone)}, #if HAVE_SDL2_GAMEPAD {"input-gamepad", OPT_BOOL(use_gamepad)}, @@ -243,6 +253,7 @@ const struct m_sub_options input_config = { .allow_win_drag = true, .preprocess_wheel = true, .touch_emulate_mouse = true, + .tablet_emulate_mouse = true, }, .change_flags = UPDATE_INPUT, }; @@ -1066,6 +1077,122 @@ int mp_input_get_touch_pos(struct input_ctx *ictx, int count, int *x, int *y, in return num_touch_points; } +static void notify_tablet_update(struct input_ctx *ictx) +{ + // queue dummy cmd so that tablet-pos can notify observers + mp_cmd_t *cmd = mp_input_parse_cmd(ictx, bstr0("ignore"), ""); + if (cmd) + cmd->notify_event = true; + queue_cmd(ictx, cmd); +} + +void mp_input_set_tablet_tool_in_proximity(struct input_ctx *ictx, bool in_proximity) +{ + MP_TRACE(ictx, "tablet tool proximity %s\n", in_proximity ? "in" : "out"); + + input_lock(ictx); + ictx->tablet_tool_in_proximity = in_proximity; + if (!in_proximity) { + ictx->tablet_tool_down = false; + ictx->tablet_tool_stylus_btn1_pressed = false; + ictx->tablet_tool_stylus_btn2_pressed = false; + ictx->tablet_tool_stylus_btn3_pressed = false; + } + notify_tablet_update(ictx); + input_unlock(ictx); +} + +void mp_input_tablet_tool_down(struct input_ctx *ictx) +{ + MP_TRACE(ictx, "tablet tool down\n"); + + input_lock(ictx); + ictx->tablet_tool_down = true; + if (ictx->opts->tablet_emulate_mouse && ictx->tablet_tool_in_proximity) + feed_key(ictx, MP_MBTN_LEFT | MP_KEY_STATE_DOWN, 1, false); + + notify_tablet_update(ictx); + input_unlock(ictx); +} + +void mp_input_tablet_tool_up(struct input_ctx *ictx) +{ + MP_TRACE(ictx, "tablet tool up\n"); + + input_lock(ictx); + ictx->tablet_tool_down = false; + if (ictx->opts->tablet_emulate_mouse && ictx->tablet_tool_in_proximity) + feed_key(ictx, MP_MBTN_LEFT | MP_KEY_STATE_UP, 1, false); + + notify_tablet_update(ictx); + input_unlock(ictx); +} + +void mp_input_tablet_tool_button(struct input_ctx *ictx, int button, int state) +{ + char *key = mp_input_get_key_name(button); + MP_TRACE(ictx, "tablet tool button %s %s%s \n", + key, + (state & MP_KEY_STATE_DOWN) ? "pressed" : "", + (state & MP_KEY_STATE_UP) ? "released" : ""); + + input_lock(ictx); + + switch (button) { + case MP_KEY_TABLET_TOOL_STYLUS_BTN1: + ictx->tablet_tool_stylus_btn1_pressed = state == MP_KEY_STATE_DOWN; + button = MP_MBTN_MID; + break; + case MP_KEY_TABLET_TOOL_STYLUS_BTN2: + ictx->tablet_tool_stylus_btn2_pressed = state == MP_KEY_STATE_DOWN; + button = MP_MBTN_RIGHT; + break; + case MP_KEY_TABLET_TOOL_STYLUS_BTN3: + ictx->tablet_tool_stylus_btn3_pressed = state == MP_KEY_STATE_DOWN; + button = MP_MBTN_BACK; + break; + default: + break; + } + + if (ictx->opts->tablet_emulate_mouse && ictx->tablet_tool_in_proximity && button) + feed_key(ictx, button | state, 1, false); + + notify_tablet_update(ictx); + input_unlock(ictx); +} + +void mp_input_set_tablet_pos(struct input_ctx *ictx, int x, int y, bool quiet) +{ + MP_TRACE(ictx, "tablet tool position %d/%d \n", x, y); + + input_lock(ictx); + ictx->tablet_x = x; + ictx->tablet_y = y; + if (ictx->opts->tablet_emulate_mouse && ictx->tablet_tool_in_proximity) + set_mouse_pos(ictx, x, y, quiet); + + notify_tablet_update(ictx); + input_unlock(ictx); +} + +void mp_input_get_tablet_pos(struct input_ctx *ictx, int *x, int *y, + bool *tool_in_proximity, bool *tool_down, + bool *tool_stylus_btn1_pressed, + bool *tool_stylus_btn2_pressed, + bool *tool_stylus_btn3_pressed) +{ + input_lock(ictx); + *x = ictx->tablet_x; + *y = ictx->tablet_y; + *tool_in_proximity = ictx->tablet_tool_in_proximity; + *tool_down = ictx->tablet_tool_down; + *tool_stylus_btn1_pressed = ictx->tablet_tool_stylus_btn1_pressed; + *tool_stylus_btn2_pressed = ictx->tablet_tool_stylus_btn2_pressed; + *tool_stylus_btn3_pressed = ictx->tablet_tool_stylus_btn3_pressed; + input_unlock(ictx); +} + static bool test_mouse(struct input_ctx *ictx, int x, int y, int rej_flags) { bool res = false; diff --git a/input/input.h b/input/input.h index 4da6178c05..8f89683445 100644 --- a/input/input.h +++ b/input/input.h @@ -112,6 +112,22 @@ void mp_input_remove_touch_point(struct input_ctx *ictx, int id); // 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); +// Set tablet tool proximity and process tool tip down/up and buttons +void mp_input_set_tablet_tool_in_proximity(struct input_ctx *ictx, bool in_proximity); +void mp_input_tablet_tool_down(struct input_ctx *ictx); +void mp_input_tablet_tool_up(struct input_ctx *ictx); +void mp_input_tablet_tool_button(struct input_ctx *ictx, int button, int state); + +// Update tablet position (in window coordinates). +void mp_input_set_tablet_pos(struct input_ctx *ictx, int x, int y, bool quiet); + +void mp_input_get_tablet_pos(struct input_ctx *ictx, int *x, int *y, + bool *tool_in_proximity, + bool *tool_down, + bool *tool_stylus_btn1_pressed, + bool *tool_stylus_btn2_pressed, + bool *tool_stylus_btn3_pressed); + // Return whether we want/accept mouse input. bool mp_input_mouse_enabled(struct input_ctx *ictx); diff --git a/input/keycodes.c b/input/keycodes.c index 418389bd4d..6bc660d925 100644 --- a/input/keycodes.c +++ b/input/keycodes.c @@ -127,6 +127,11 @@ static const struct key_name key_names[] = { { MP_MBTN_MID_DBL, "MBTN_MID_DBL" }, { MP_MBTN_RIGHT_DBL, "MBTN_RIGHT_DBL" }, + { MP_KEY_TABLET_TOOL_TIP, "TABLET_TOOL_TIP" }, + { MP_KEY_TABLET_TOOL_STYLUS_BTN1, "TABLET_TOOL_STYLUS_BTN1" }, + { MP_KEY_TABLET_TOOL_STYLUS_BTN2, "TABLET_TOOL_STYLUS_BTN2" }, + { MP_KEY_TABLET_TOOL_STYLUS_BTN3, "TABLET_TOOL_STYLUS_BTN3" }, + { MP_KEY_GAMEPAD_ACTION_DOWN, "GAMEPAD_ACTION_DOWN" }, { MP_KEY_GAMEPAD_ACTION_RIGHT, "GAMEPAD_ACTION_RIGHT" }, { MP_KEY_GAMEPAD_ACTION_LEFT, "GAMEPAD_ACTION_LEFT" }, diff --git a/input/keycodes.h b/input/keycodes.h index e2384d6719..b640f79d64 100644 --- a/input/keycodes.h +++ b/input/keycodes.h @@ -161,6 +161,13 @@ #define MP_KEY_MOUSE_BTN_COUNT (MP_MBTN_END - MP_MBTN_BASE) +/* tablet buttons */ +#define MP_KEY_TABLET (MP_KEY_BASE+0xD0) +#define MP_KEY_TABLET_TOOL_TIP (MP_KEY_TABLET+1) +#define MP_KEY_TABLET_TOOL_STYLUS_BTN1 (MP_KEY_TABLET+2) +#define MP_KEY_TABLET_TOOL_STYLUS_BTN2 (MP_KEY_TABLET+3) +#define MP_KEY_TABLET_TOOL_STYLUS_BTN3 (MP_KEY_TABLET+4) + /* game controller keys */ #define MP_KEY_GAMEPAD (MP_KEY_BASE+0xF0) #define MP_KEY_GAMEPAD_ACTION_DOWN (MP_KEY_GAMEPAD+0) diff --git a/player/command.c b/player/command.c index 2d61ea642e..085eafe56d 100644 --- a/player/command.c +++ b/player/command.c @@ -3124,6 +3124,43 @@ static int mp_property_touch_pos(void *ctx, struct m_property *prop, get_touch_pos, (void *)pos); } +static int mp_property_tablet_pos(void *ctx, struct m_property *prop, + int action, void *arg) +{ + MPContext *mpctx = ctx; + + switch (action) { + case M_PROPERTY_GET_TYPE: + *(struct m_option *)arg = (struct m_option){.type = CONF_TYPE_NODE}; + return M_PROPERTY_OK; + + case M_PROPERTY_GET: { + int xs, ys; + bool tool_in_proximity; + bool tool_down; + bool tool_stylus_btn1_pressed; + bool tool_stylus_btn2_pressed; + bool tool_stylus_btn3_pressed; + mp_input_get_tablet_pos(mpctx->input, &xs, &ys, &tool_in_proximity, &tool_down, + &tool_stylus_btn1_pressed, &tool_stylus_btn2_pressed, &tool_stylus_btn3_pressed); + + struct mpv_node node; + node_init(&node, MPV_FORMAT_NODE_MAP, NULL); + node_map_add_int64(&node, "x", xs); + node_map_add_int64(&node, "y", ys); + node_map_add_flag(&node, "tool-in-proximity", tool_in_proximity); + node_map_add_string(&node, "tool-tip", tool_down ? "down" : "up"); + node_map_add_string(&node, "tool-stylus-btn1", tool_stylus_btn1_pressed ? "pressed" : "released"); + node_map_add_string(&node, "tool-stylus-btn2", tool_stylus_btn2_pressed ? "pressed" : "released"); + node_map_add_string(&node, "tool-stylus-btn3", tool_stylus_btn3_pressed ? "pressed" : "released"); + *(struct mpv_node *)arg = node; + return M_PROPERTY_OK; + } + } + + return M_PROPERTY_NOT_IMPLEMENTED; +} + /// Video fps (RO) static int mp_property_fps(void *ctx, struct m_property *prop, int action, void *arg) @@ -4416,6 +4453,7 @@ static const struct m_property mp_properties_base[] = { {"mouse-pos", mp_property_mouse_pos}, {"touch-pos", mp_property_touch_pos}, + {"tablet-pos", mp_property_tablet_pos}, // Subs {"sid", mp_property_switch_track, .priv = (void *)(const int[]){0, STREAM_SUB}}, @@ -4553,7 +4591,7 @@ static const char *const *const mp_event_property_change[] = { E(MP_EVENT_CHANGE_PLAYLIST, "playlist", "playlist-pos", "playlist-pos-1", "playlist-count", "playlist/count", "playlist-current-pos", "playlist-playing-pos"), - E(MP_EVENT_INPUT_PROCESSED, "mouse-pos", "touch-pos"), + E(MP_EVENT_INPUT_PROCESSED, "mouse-pos", "touch-pos", "tablet-pos"), E(MP_EVENT_CORE_IDLE, "core-idle", "eof-reached"), }; #undef E diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index aa197cff39..33ff3ee364 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -698,11 +698,14 @@ static void tablet_tool_handle_proximity_in(void *data, struct vo_wayland_tablet_tool *tablet_tool = data; tablet_tool->proximity_serial = serial; set_cursor_visibility(tablet_tool->seat, true); + mp_input_set_tablet_tool_in_proximity(tablet_tool->wl->vo->input_ctx, true); } static void tablet_tool_handle_proximity_out(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { + struct vo_wayland_tablet_tool *tablet_tool = data; + mp_input_set_tablet_tool_in_proximity(tablet_tool->wl->vo->input_ctx, false); } static void tablet_tool_handle_down(void *data, @@ -724,7 +727,7 @@ static void tablet_tool_handle_down(void *data, tablet_tool->seat->pointer_button_serial = serial; wl->last_button_seat = tablet_tool->seat; - mp_input_put_key(tablet_tool->wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_DOWN | tablet_tool->seat->mpmod); + mp_input_tablet_tool_down(tablet_tool->wl->vo->input_ctx); } static void tablet_tool_handle_up(void *data, @@ -732,7 +735,7 @@ static void tablet_tool_handle_up(void *data, { struct vo_wayland_tablet_tool *tablet_tool = data; tablet_tool->seat->wl->last_button_seat = NULL; - mp_input_put_key(tablet_tool->wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_UP | tablet_tool->seat->mpmod); + mp_input_tablet_tool_up(tablet_tool->wl->vo->input_ctx); } static void tablet_tool_handle_motion(void *data, @@ -746,7 +749,7 @@ static void tablet_tool_handle_motion(void *data, wl->mouse_x = handle_round(wl->scaling, wl_fixed_to_int(x)); wl->mouse_y = handle_round(wl->scaling, wl_fixed_to_int(y)); - mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y, + mp_input_set_tablet_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y, wl->toplevel_configured); wl->toplevel_configured = false; } @@ -799,26 +802,25 @@ static void tablet_tool_handle_button(void *data, tablet_tool->seat->last_serial = serial; switch (button) { - case BTN_STYLUS: - button = MP_MBTN_MID; - break; - case BTN_STYLUS2: - button = MP_MBTN_RIGHT; - break; - case BTN_STYLUS3: - button = MP_MBTN_BACK; - break; - default: - button = 0; - break; + case BTN_STYLUS: + button = MP_KEY_TABLET_TOOL_STYLUS_BTN1; + break; + case BTN_STYLUS2: + button = MP_KEY_TABLET_TOOL_STYLUS_BTN2; + break; + case BTN_STYLUS3: + button = MP_KEY_TABLET_TOOL_STYLUS_BTN3; + break; + default: + button = 0; + break; } state = state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_PRESSED ? MP_KEY_STATE_DOWN : MP_KEY_STATE_UP; - if (button) - mp_input_put_key(tablet_tool->wl->vo->input_ctx, button | state | tablet_tool->seat->mpmod); + mp_input_tablet_tool_button(tablet_tool->wl->vo->input_ctx, button, state); } static void tablet_tool_handle_frame(void *data,