Having a pointer lock implies that relative motion is also used. When refocusing on a mouselook application which the driver is using relative motion for, an absolute motion hardware input is sent because of handling the wl_pointer.enter event. This can result in an unwanted warp/jerk.
The need to handle enter motion isn't applicable to mouselook or cases where the pointer is locked because the application is drawing its own cursor while covering vscreen, so it can be ignored during pointer lock.
-- v2: winewayland: Ignore absolute motion during pointer lock. winewayland: Ignore enter motion during pointer lock.
From: Attila Fidan dev@print0.net
Having a pointer lock implies that relative motion is also used. When refocusing on a mouselook application which the driver is using relative motion for, an absolute motion hardware input is sent because of handling the wl_pointer.enter event. This can result in an unwanted warp/jerk.
The need to handle enter motion isn't applicable to mouselook or cases where the pointer is locked because the application is drawing its own cursor while covering vscreen, so it can be ignored during pointer lock. --- dlls/winewayland.drv/wayland_pointer.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index 52aaa337aac..b9a31c24b2a 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -111,6 +111,8 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, { struct wayland_pointer *pointer = &process_wayland.pointer; HWND hwnd; + BOOL locked = FALSE; + BOOL focus_on_constraint_hwnd = FALSE;
if (!wl_surface) return; /* The wl_surface user data remains valid and immutable for the whole @@ -122,6 +124,10 @@ 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; + if (pointer->zwp_locked_pointer_v1) + locked = TRUE; + if (hwnd == pointer->constraint_hwnd) + focus_on_constraint_hwnd = TRUE; pthread_mutex_unlock(&pointer->mutex);
/* The cursor is undefined at every enter, so we set it again with @@ -131,7 +137,8 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, /* Handle the enter as a motion, to account for cases where the * window first appears beneath the pointer and won't get a separate * motion event. */ - pointer_handle_motion_internal(sx, sy); + if (!locked || !focus_on_constraint_hwnd) + pointer_handle_motion_internal(sx, sy); }
static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
From: Attila Fidan dev@print0.net
This has the same idea as ignoring it if in relative mode, but the effect is slightly different. Relative motion is disabled while pointer focus is not on the constraint hwnd and re-enabled when pointer focus is back on the constraint hwnd. An absolute motion event may be handled before the foreground thread gets to re-enabling relative motion during ClipCursor, which may result in an unwanted warp/jerk despite the previous commit. --- dlls/winewayland.drv/wayland_pointer.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index b9a31c24b2a..d9d0929d9b8 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -97,8 +97,14 @@ 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; + /* Ignore absolute motion events if the pointer is locked and the pointer is + * focused on the lock surface. Relative mode is or will be enabled. The + * latter case may happen if a motion event is being handled immediately + * after an enter event, and the foreground thread has yet to re-enable + * relative motion. */ + if (pointer->zwp_locked_pointer_v1 && + pointer->focused_hwnd == pointer->constraint_hwnd) + return;
pointer_handle_motion_internal(sx, sy); }
v2 * Handle enter motion during pointer lock if pointer focus isn't on the constraint hwnd. * In some cases (sway, when entering the pointer from the top of a floating windowed window, and no windows are layered on top of the window), the enter event is immediately followed by a motion event, which gets handled before the foreground thread gets to re-enable relative motion. The check for relative mode in `pointer_handle_motion` is adjusted slightly.
Alexandros Frantzis (@afrantzis) commented about dlls/winewayland.drv/wayland_pointer.c:
{ struct wayland_pointer *pointer = &process_wayland.pointer;
- /* Ignore absolute motion events if in relative mode. */
- if (pointer->zwp_relative_pointer_v1) return;
- /* Ignore absolute motion events if the pointer is locked and the pointer is
* focused on the lock surface. Relative mode is or will be enabled. The
* latter case may happen if a motion event is being handled immediately
* after an enter event, and the foreground thread has yet to re-enable
* relative motion. */
- if (pointer->zwp_locked_pointer_v1 &&
pointer->focused_hwnd == pointer->constraint_hwnd)
The concept of 'needs relative pointer' is used twice in this MR and also already implemented internally in `wayland_pointer_update_constraint`. In order to keep all such checks in sync, I suggest that we introduce a simple function and use it in all locations:
`static BOOL wayland_pointer_needs_relative(struct wayland_pointer *pointer, HWND hwnd)`
Note that `needs_relative` in `wayland_pointer_update_constraint` is not explicitly expressed in terms of locking, but the condition is effectively equivalent to what you are using (with the exception of when `force_lock == TRUE`, but that's a temporary situation).