[PATCH v7 0/4] MR11117: winewayland: Implement pointer rawinput.
Implements rawinput by refactoring a few things and adding a wine staging patch. Also fixes a bug with the existing pointer implementation, which can cause the mouse cursor to escape. As much as I would like to make relative pointer protocol mandatory, most compositors don't support it in their nested mode, which makes this a very difficult tradeoff to make. For now I have left it optional. -- v7: winewayland: Store the pending warp position. winewayland: Implement pointer rawinput. server: Add send_hardware_message flags for rawinput translation. https://gitlab.winehq.org/wine/wine/-/merge_requests/11117
From: Etaash Mathamsetty <etaash.mathamsetty@gmail.com> --- dlls/winewayland.drv/wayland_pointer.c | 118 +++++++++++++++++-------- dlls/winewayland.drv/waylanddrv.h | 20 ++++- 2 files changed, 100 insertions(+), 38 deletions(-) diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index 109dd2dd0eb..f6e359c14a5 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -121,9 +121,19 @@ static HWND wayland_pointer_get_focused_hwnd(void) return hwnd; } +static void wayland_pointer_reset_frame(void) +{ + struct wayland_pointer_frame *frame = &process_wayland.pointer.frame; + + frame->dx = frame->dy = 0.0; + frame->horz_scroll = frame->scroll = 0; + frame->flags = 0; +} + static void pointer_handle_motion_internal(wl_fixed_t sx, wl_fixed_t sy) { - INPUT input = {0}; + struct wayland_pointer *pointer = &process_wayland.pointer; + struct wayland_pointer_frame *frame = &pointer->frame; RECT *window_rect; HWND hwnd; POINT screen; @@ -155,16 +165,13 @@ static void pointer_handle_motion_internal(wl_fixed_t sx, wl_fixed_t sy) wayland_win_data_release(data); - input.type = INPUT_MOUSE; - input.mi.dx = screen.x; - input.mi.dy = screen.y; - input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; + frame->x = screen.x; + frame->y = screen.y; + frame->flags |= WAYLAND_POINTER_FRAME_ABSOLUTE; TRACE("hwnd=%p wayland_xy=%.2f,%.2f screen_xy=%d,%d\n", hwnd, wl_fixed_to_double(sx), wl_fixed_to_double(sy), screen.x, screen.y); - - NtUserSendHardwareInput(hwnd, 0, &input, 0); } static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, @@ -179,6 +186,7 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, } static void wayland_set_cursor(HWND hwnd, HCURSOR hcursor, BOOL use_hcursor); +static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer); static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *wl_surface, @@ -199,6 +207,7 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, pthread_mutex_lock(&pointer->mutex); pointer->focused_hwnd = hwnd; pointer->enter_serial = serial; + wayland_pointer_reset_frame(); pthread_mutex_unlock(&pointer->mutex); /* The cursor is undefined at every enter, so we set it again with @@ -209,6 +218,7 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, * window first appears beneath the pointer and won't get a separate * motion event. */ pointer_handle_motion_internal(sx, sy); + pointer_handle_frame(data, pointer->wl_pointer); } static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, @@ -279,6 +289,59 @@ static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) { + INPUT input = {0}; + HWND hwnd; + struct wayland_pointer *pointer = &process_wayland.pointer; + struct wayland_pointer_frame *frame = &pointer->frame; + + /* any stale state will be cleaned up on enter */ + if (!(hwnd = wayland_pointer_get_focused_hwnd())) return; + + TRACE("hwnd=%p\n", hwnd); + + input.type = INPUT_MOUSE; + input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; + + if (frame->flags & WAYLAND_POINTER_FRAME_ABSOLUTE) + { + input.mi.dx = frame->x; + input.mi.dy = frame->y; + NtUserSendHardwareInput(hwnd, 0, &input, 0); + } + + input.mi.dwFlags = MOUSEEVENTF_MOVE; + + if (frame->flags & WAYLAND_POINTER_FRAME_RELATIVE) + { + input.mi.dx = round(frame->dx); + input.mi.dy = round(frame->dy); + frame->dx -= input.mi.dx; + frame->dy -= input.mi.dy; + if (input.mi.dx != 0 || input.mi.dy != 0) + NtUserSendHardwareInput(hwnd, 0, &input, 0); + } + + input.mi.dwFlags = MOUSEEVENTF_WHEEL; + input.mi.dx = input.mi.dy = 0; + + if (frame->flags & WAYLAND_POINTER_FRAME_WHEEL) + { + input.mi.mouseData = frame->scroll; + if (input.mi.mouseData) + NtUserSendHardwareInput(hwnd, 0, &input, 0); + } + + input.mi.dwFlags = MOUSEEVENTF_HWHEEL; + + if (frame->flags & WAYLAND_POINTER_FRAME_WHEEL_HORZ) + { + input.mi.mouseData = frame->horz_scroll; + if (input.mi.mouseData) + NtUserSendHardwareInput(hwnd, 0, &input, 0); + } + + frame->flags = 0; + frame->scroll = frame->horz_scroll = 0; } static void pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer, @@ -294,29 +357,26 @@ static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer, static void pointer_handle_axis_value120(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t value120) { - INPUT input = {0}; + struct wayland_pointer *pointer = &process_wayland.pointer; + struct wayland_pointer_frame *frame = &pointer->frame; HWND hwnd; if (!(hwnd = wayland_pointer_get_focused_hwnd())) return; - input.type = INPUT_MOUSE; - switch (axis) { case WL_POINTER_AXIS_VERTICAL_SCROLL: - input.mi.dwFlags = MOUSEEVENTF_WHEEL; - input.mi.mouseData = -value120; + frame->flags |= WAYLAND_POINTER_FRAME_WHEEL; + frame->scroll += -value120; break; case WL_POINTER_AXIS_HORIZONTAL_SCROLL: - input.mi.dwFlags = MOUSEEVENTF_HWHEEL; - input.mi.mouseData = value120; + frame->flags |= WAYLAND_POINTER_FRAME_WHEEL_HORZ; + frame->horz_scroll += value120; break; default: break; } TRACE("hwnd=%p axis=%u value120=%d\n", hwnd, axis, value120); - - NtUserSendHardwareInput(hwnd, 0, &input, 0); } static void pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer, @@ -360,11 +420,11 @@ static void relative_pointer_v1_relative_motion(void *private, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel) { - INPUT input = {0}; HWND hwnd; struct wayland_win_data *data; double screen_x = 0.0, screen_y = 0.0; struct wayland_pointer *pointer = &process_wayland.pointer; + struct wayland_pointer_frame *frame = &pointer->frame; if (!(hwnd = wayland_pointer_get_focused_hwnd())) return; if (!(data = wayland_win_data_get(hwnd))) return; @@ -375,26 +435,12 @@ static void relative_pointer_v1_relative_motion(void *private, &screen_x, &screen_y); wayland_win_data_release(data); - pthread_mutex_lock(&pointer->mutex); - - pointer->accum_x += screen_x; - pointer->accum_y += screen_y; - - input.type = INPUT_MOUSE; - input.mi.dx = round(pointer->accum_x); - input.mi.dy = round(pointer->accum_y); - input.mi.dwFlags = MOUSEEVENTF_MOVE; - - pointer->accum_x -= input.mi.dx; - pointer->accum_y -= input.mi.dy; + frame->dx += screen_x; + frame->dy += screen_y; - pthread_mutex_unlock(&pointer->mutex); - - TRACE("hwnd=%p wayland_dxdy=%.2f,%.2f accum_dxdy=%d,%d\n", - hwnd, wl_fixed_to_double(dx), wl_fixed_to_double(dy), - input.mi.dx, input.mi.dy); + frame->flags |= WAYLAND_POINTER_FRAME_RELATIVE; - NtUserSendHardwareInput(hwnd, 0, &input, 0); + TRACE("hwnd=%p screen=%.2f,%.2f\n", hwnd, screen_x, screen_y); } static const struct zwp_relative_pointer_v1_listener relative_pointer_v1_listener = @@ -981,7 +1027,7 @@ static void wayland_pointer_update_constraint(struct wl_surface *wl_surface, if (needs_relative && !pointer->zwp_relative_pointer_v1) { - pointer->accum_x = pointer->accum_y = 0; + pointer->frame.dx = pointer->frame.dy = 0.0; pointer->zwp_relative_pointer_v1 = zwp_relative_pointer_manager_v1_get_relative_pointer( process_wayland.zwp_relative_pointer_manager_v1, diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 30fb7f97969..f071448fb04 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -103,6 +103,23 @@ struct wayland_cursor int hotspot_x, hotspot_y; }; +enum wayland_pointer_frame_flags +{ + WAYLAND_POINTER_FRAME_RELATIVE = (1 << 0), + WAYLAND_POINTER_FRAME_ABSOLUTE = (1 << 1), + WAYLAND_POINTER_FRAME_WHEEL = (1 << 2), + WAYLAND_POINTER_FRAME_WHEEL_HORZ = (1 << 3) +}; + +struct wayland_pointer_frame +{ + LONG x, y; + double dx, dy; + LONG scroll, horz_scroll; + + enum wayland_pointer_frame_flags flags; +}; + struct wayland_pointer { struct wl_pointer *wl_pointer; @@ -116,8 +133,7 @@ struct wayland_pointer uint32_t enter_serial; uint32_t button_serial; struct wayland_cursor cursor; - double accum_x; - double accum_y; + struct wayland_pointer_frame frame; pthread_mutex_t mutex; }; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11117
From: Rémi Bernon <rbernon@codeweavers.com> --- include/ntuser.h | 4 ++++ server/protocol.def | 3 +-- server/queue.c | 20 ++++++++++++-------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/include/ntuser.h b/include/ntuser.h index 2bbf77a4cf1..54d0d626d7b 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -1598,6 +1598,10 @@ struct hid_packet C_ASSERT(sizeof(struct hid_packet) == offsetof(struct hid_packet, data[0])); +#define SEND_HWMSG_INJECTED 1 +#define SEND_HWMSG_NO_RAW 2 +#define SEND_HWMSG_NO_MSG 4 + struct send_hardware_input_params { UINT flags; diff --git a/server/protocol.def b/server/protocol.def index 7b467618f7a..c1cc80edd25 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2407,7 +2407,7 @@ enum message_type @REQ(send_hardware_message) user_handle_t win; /* window handle */ union hw_input input; /* input data */ - unsigned int flags; /* flags (see below) */ + unsigned int flags; /* flags (see ntuser.h) */ VARARG(report,bytes); /* HID report data */ @REPLY int wait; /* do we need to wait for a reply? */ @@ -2416,7 +2416,6 @@ enum message_type int new_x; /* new cursor position */ int new_y; @END -#define SEND_HWMSG_INJECTED 0x01 /* Get a message from the current queue */ diff --git a/server/queue.c b/server/queue.c index a04b53b70de..4182ee7bf86 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2211,7 +2211,7 @@ static void dispatch_rawinput_message( struct desktop *desktop, struct rawinput_ /* queue a hardware message for a mouse event */ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const union hw_input *input, - unsigned int origin, struct msg_queue *sender ) + unsigned int origin, struct msg_queue *sender, unsigned int send_flags ) { desktop_shm_t *desktop_shm = desktop->shared; struct hardware_msg_data *msg_data; @@ -2271,7 +2271,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons y = desktop_shm->cursor.y; } - if ((foreground = get_foreground_thread( desktop, win ))) + if (!(send_flags & SEND_HWMSG_NO_RAW) && (foreground = get_foreground_thread( desktop, win ))) { memset( &raw_msg, 0, sizeof(raw_msg) ); raw_msg.foreground = foreground; @@ -2286,6 +2286,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons release_object( foreground ); } + if (send_flags & SEND_HWMSG_NO_MSG) return 0; + for (i = 0; i < ARRAY_SIZE( messages ); i++) { if (!messages[i]) continue; @@ -2316,14 +2318,14 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons } static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const union hw_input *input, - unsigned int origin, struct msg_queue *sender, int repeat ); + unsigned int origin, struct msg_queue *sender, int repeat, unsigned int send_flags); static void key_repeat_timeout( void *private ) { struct desktop *desktop = private; desktop->key_repeat.timeout = NULL; - queue_keyboard_message( desktop, desktop->key_repeat.win, &desktop->key_repeat.input, IMO_HARDWARE, NULL, 1 ); + queue_keyboard_message( desktop, desktop->key_repeat.win, &desktop->key_repeat.input, IMO_HARDWARE, NULL, 1, 0 ); } static void stop_key_repeat( struct desktop *desktop ) @@ -2336,7 +2338,7 @@ static void stop_key_repeat( struct desktop *desktop ) /* queue a hardware message for a keyboard event */ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const union hw_input *input, - unsigned int origin, struct msg_queue *sender, int repeat ) + unsigned int origin, struct msg_queue *sender, int repeat, unsigned int send_flags ) { desktop_shm_t *desktop_shm = desktop->shared; struct hw_msg_source source = { IMDT_KEYBOARD, origin }; @@ -2459,7 +2461,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c } } - if (!unicode && (foreground = get_foreground_thread( desktop, win ))) + if (!(send_flags & SEND_HWMSG_NO_RAW) && ((!unicode && (foreground = get_foreground_thread( desktop, win ))))) { struct rawinput_message raw_msg = {0}; raw_msg.foreground = foreground; @@ -2474,6 +2476,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c release_object( foreground ); } + if (send_flags & SEND_HWMSG_NO_MSG) return 0; + if (!(msg = alloc_hardware_message( input->kbd.info, source, time, 0 ))) return 0; msg_data = msg->data; @@ -3258,10 +3262,10 @@ DECL_HANDLER(send_hardware_message) switch (req->input.type) { case INPUT_MOUSE: - wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender ); + wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender, req->flags ); break; case INPUT_KEYBOARD: - wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender, 0 ); + wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender, 0, req->flags ); break; case INPUT_HARDWARE: queue_custom_hardware_message( desktop, req->win, origin, &req->input ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11117
From: Etaash Mathamsetty <etaash.mathamsetty@gmail.com> --- dlls/winewayland.drv/wayland_pointer.c | 63 ++++++++++++-------------- dlls/winewayland.drv/waylanddrv.h | 2 + 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index f6e359c14a5..6a8e4ea34f1 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -126,6 +126,7 @@ static void wayland_pointer_reset_frame(void) struct wayland_pointer_frame *frame = &process_wayland.pointer.frame; frame->dx = frame->dy = 0.0; + frame->dx_raw = frame->dy_raw = 0.0; frame->horz_scroll = frame->scroll = 0; frame->flags = 0; } @@ -180,7 +181,7 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, struct wayland_pointer *pointer = &process_wayland.pointer; /* Ignore absolute motion events if in relative mode. */ - if (pointer->zwp_relative_pointer_v1) return; + if (pointer->relative_mode) return; pointer_handle_motion_internal(sx, sy); } @@ -306,7 +307,7 @@ static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) { input.mi.dx = frame->x; input.mi.dy = frame->y; - NtUserSendHardwareInput(hwnd, 0, &input, 0); + NtUserSendHardwareInput(hwnd, SEND_HWMSG_NO_RAW, &input, 0); } input.mi.dwFlags = MOUSEEVENTF_MOVE; @@ -318,7 +319,14 @@ static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) frame->dx -= input.mi.dx; frame->dy -= input.mi.dy; if (input.mi.dx != 0 || input.mi.dy != 0) - NtUserSendHardwareInput(hwnd, 0, &input, 0); + NtUserSendHardwareInput(hwnd, SEND_HWMSG_NO_RAW, &input, 0); + + input.mi.dx = round(frame->dx_raw); + input.mi.dy = round(frame->dy_raw); + frame->dx_raw -= input.mi.dx; + frame->dy_raw -= input.mi.dy; + if (input.mi.dx != 0 || input.mi.dy != 0) + NtUserSendHardwareInput(hwnd, SEND_HWMSG_NO_MSG, &input, 0); } input.mi.dwFlags = MOUSEEVENTF_WHEEL; @@ -423,6 +431,8 @@ static void relative_pointer_v1_relative_motion(void *private, HWND hwnd; struct wayland_win_data *data; double screen_x = 0.0, screen_y = 0.0; + double raw_x = wl_fixed_to_double(dx_unaccel); + double raw_y = wl_fixed_to_double(dy_unaccel); struct wayland_pointer *pointer = &process_wayland.pointer; struct wayland_pointer_frame *frame = &pointer->frame; @@ -437,10 +447,12 @@ static void relative_pointer_v1_relative_motion(void *private, frame->dx += screen_x; frame->dy += screen_y; + frame->dx_raw += raw_x; + frame->dy_raw += raw_y; frame->flags |= WAYLAND_POINTER_FRAME_RELATIVE; - TRACE("hwnd=%p screen=%.2f,%.2f\n", hwnd, screen_x, screen_y); + TRACE("hwnd=%p screen=%.2f,%.2f raw=%.2f,%.2f\n", hwnd, screen_x, screen_y, raw_x, raw_y); } static const struct zwp_relative_pointer_v1_listener relative_pointer_v1_listener = @@ -456,6 +468,15 @@ void wayland_pointer_init(struct wl_pointer *wl_pointer) pointer->wl_pointer = wl_pointer; pointer->focused_hwnd = NULL; pointer->enter_serial = 0; + if (process_wayland.zwp_relative_pointer_manager_v1) + { + pointer->zwp_relative_pointer_v1 = + zwp_relative_pointer_manager_v1_get_relative_pointer( + process_wayland.zwp_relative_pointer_manager_v1, + pointer->wl_pointer); + zwp_relative_pointer_v1_add_listener(pointer->zwp_relative_pointer_v1, + &relative_pointer_v1_listener, NULL); + } pthread_mutex_unlock(&pointer->mutex); wl_pointer_add_listener(pointer->wl_pointer, &pointer_listener, NULL); } @@ -925,7 +946,7 @@ static void wayland_pointer_update_constraint(struct wl_surface *wl_surface, BOOL force_lock) { struct wayland_pointer *pointer = &process_wayland.pointer; - BOOL needs_relative, needs_lock, needs_confine, is_visible; + BOOL needs_lock, needs_confine, is_visible; static unsigned int once; if (!process_wayland.zwp_pointer_constraints_v1) @@ -1015,33 +1036,9 @@ static void wayland_pointer_update_constraint(struct wl_surface *wl_surface, } } - if (!process_wayland.zwp_relative_pointer_manager_v1) - { - if (!once++) - ERR("zwp_relative_pointer_manager_v1 isn't supported, skipping relative motion\n"); - return; - } - - needs_relative = !is_visible && pointer->constraint_hwnd && - pointer->constraint_hwnd == pointer->focused_hwnd; - - if (needs_relative && !pointer->zwp_relative_pointer_v1) - { - pointer->frame.dx = pointer->frame.dy = 0.0; - pointer->zwp_relative_pointer_v1 = - zwp_relative_pointer_manager_v1_get_relative_pointer( - process_wayland.zwp_relative_pointer_manager_v1, - pointer->wl_pointer); - zwp_relative_pointer_v1_add_listener(pointer->zwp_relative_pointer_v1, - &relative_pointer_v1_listener, NULL); - TRACE("Enabling relative motion\n"); - } - else if (!needs_relative && pointer->zwp_relative_pointer_v1) - { - zwp_relative_pointer_v1_destroy(pointer->zwp_relative_pointer_v1); - pointer->zwp_relative_pointer_v1 = NULL; - TRACE("Disabling relative motion\n"); - } + pointer->relative_mode = !is_visible && pointer->constraint_hwnd && + pointer->constraint_hwnd == pointer->focused_hwnd && + pointer->zwp_relative_pointer_v1; } void wayland_pointer_clear_constraint(void) @@ -1067,7 +1064,7 @@ BOOL WAYLAND_SetCursorPos(INT x, INT y) struct wayland_pointer *pointer = &process_wayland.pointer; pthread_mutex_lock(&pointer->mutex); - if (pointer->zwp_relative_pointer_v1) + if (pointer->relative_mode) { pthread_mutex_unlock(&pointer->mutex); return FALSE; diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index f071448fb04..86a0d2fa618 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -115,6 +115,7 @@ struct wayland_pointer_frame { LONG x, y; double dx, dy; + double dx_raw, dy_raw; LONG scroll, horz_scroll; enum wayland_pointer_frame_flags flags; @@ -130,6 +131,7 @@ struct wayland_pointer HWND focused_hwnd; HWND constraint_hwnd; BOOL pending_warp; + BOOL relative_mode; uint32_t enter_serial; uint32_t button_serial; struct wayland_cursor cursor; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11117
From: Etaash Mathamsetty <etaash.mathamsetty@gmail.com> --- dlls/winewayland.drv/wayland_pointer.c | 11 +++++++++++ dlls/winewayland.drv/waylanddrv.h | 1 + 2 files changed, 12 insertions(+) diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index 6a8e4ea34f1..b2edc45405e 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -1070,6 +1070,8 @@ BOOL WAYLAND_SetCursorPos(INT x, INT y) return FALSE; } pointer->pending_warp = TRUE; + pointer->warp_x = x; + pointer->warp_y = y; pthread_mutex_unlock(&pointer->mutex); TRACE("warping to %d,%d\n", x, y); @@ -1097,6 +1099,15 @@ BOOL WAYLAND_ClipCursor(const RECT *clip, BOOL reset) NtUserGetCursorPos(&cursor_pos); hwnd = NtUserGetForegroundWindow(); + /* the cursor pos may have changed between SetCursorPos and ClipCursor calls */ + pthread_mutex_lock(&pointer->mutex); + if (pointer->pending_warp) + { + cursor_pos.x = pointer->warp_x; + cursor_pos.y = pointer->warp_y; + } + pthread_mutex_unlock(&pointer->mutex); + if (!(data = wayland_win_data_get(hwnd))) return FALSE; if ((surface = data->wayland_surface)) { diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 86a0d2fa618..954cbf3ba28 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -131,6 +131,7 @@ struct wayland_pointer HWND focused_hwnd; HWND constraint_hwnd; BOOL pending_warp; + INT warp_x, warp_y; BOOL relative_mode; uint32_t enter_serial; uint32_t button_serial; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11117
v2: store the warp x,y position in the wayland_pointer struct. With this approach if there is a warp that is pending being applied and the cursor pos has changed (due the winewayland updating cursor positions in another thread), the correct one would be the one that is stored in the wayland pointer structure. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11117#note_143104
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/wayland_pointer.c:
frame->dx -= input.mi.dx; frame->dy -= input.mi.dy; if (input.mi.dx != 0 || input.mi.dy != 0) - NtUserSendHardwareInput(hwnd, 0, &input, 0); + NtUserSendHardwareInput(hwnd, SEND_HWMSG_NO_RAW, &input, 0); + + input.mi.dx = round(frame->dx_raw); + input.mi.dy = round(frame->dy_raw); + frame->dx_raw -= input.mi.dx; + frame->dy_raw -= input.mi.dy; + if (input.mi.dx != 0 || input.mi.dy != 0) + NtUserSendHardwareInput(hwnd, SEND_HWMSG_NO_MSG, &input, 0); }
Fwiw review might take a bit of time, I'm trying to find a better way than spamming wineserver with requests when both raw/non-raw input is to be sent. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11117#note_143111
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/wayland_pointer.c:
+ input.mi.dy = round(frame->dy); + frame->dx -= input.mi.dx; + frame->dy -= input.mi.dy; + if (input.mi.dx != 0 || input.mi.dy != 0) + NtUserSendHardwareInput(hwnd, 0, &input, 0); + } + + input.mi.dwFlags = MOUSEEVENTF_WHEEL; + input.mi.dx = input.mi.dy = 0; + + if (frame->flags & WAYLAND_POINTER_FRAME_WHEEL) + { + input.mi.mouseData = frame->scroll; + if (input.mi.mouseData) + NtUserSendHardwareInput(hwnd, 0, &input, 0); + } I'm also not completely sure to like this change. As far as I can see we most often get a `frame` event after each individual `axis`/`button`/`motion` event, and this merges them all events together, to later only send them separately.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11117#note_143112
On Mon Jun 15 09:39:15 2026 +0000, Rémi Bernon wrote:
I'm also not completely sure to like this change. As far as I can see we most often get a `frame` event after each individual `axis`/`button`/`motion` event, and this merges them all events together, to later only send them separately. It makes it much easier to handle wl_pointer::axis events in a later patch. One option would be to move sending the hardware inputs to wl_pointer::axis_value120 and then mark that it has been handled in the frame event. Another option would be to just make NtUserSendHardwareInput handle an array of INPUT struct like NtUserSendInput which would fix your other comment as well. (edit: That just calls send_hardware_message in a loop, so I guess it would need to be improved in wineserver)
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11117#note_143146
participants (4)
-
Etaash Mathamsetty -
Etaash Mathamsetty (@etaash.mathamsetty) -
Rémi Bernon -
Rémi Bernon (@rbernon)