Adds the registry key `HKEY_CURRENT_USER\Software\Wine\Wayland Driver\unaccelerated_pointer` witch allows raw input. This makes it easier to calculate the same sensitivity in different games, use sensitivity calculators, and easily change values when changing DPI and do not depend on the compositor or OS.
For example, you want to set the sensitivity to half as much, and sensitivity curves in libinput are more difficult to calculate than in the games themselves.
-- v7: winewayland.drv: Add unaccelerated pointer support
From: Grigory Vasilyev h0tc0d3@gmail.com
Adds the registry key HKEY_CURRENT_USER\Software\Wine\Wayland Driver\unaccelerated_pointer witch allows raw input. This makes it easier to calculate the same sensitivity in different games, use sensitivity calculators, and easily change values when changing DPI and do not depend on the compositor or OS.
For example, you want to set the sensitivity to half as much, and sensitivity curves in libinput are more difficult to calculate than in the games themselves. --- dlls/winewayland.drv/Makefile.in | 1 + dlls/winewayland.drv/dllmain.c | 44 ++++++++++++++++++++++++++ dlls/winewayland.drv/unixlib.h | 1 + dlls/winewayland.drv/wayland_pointer.c | 23 +++++++++++--- dlls/winewayland.drv/waylanddrv_main.c | 10 ++++++ 5 files changed, 75 insertions(+), 4 deletions(-)
diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index 9ad1ad6889d..bee478257ae 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -2,6 +2,7 @@ MODULE = winewayland.drv UNIXLIB = winewayland.so UNIX_CFLAGS = $(EGL_CFLAGS) $(WAYLAND_CLIENT_CFLAGS) $(WAYLAND_EGL_CFLAGS) $(XKBCOMMON_CFLAGS) $(XKBREGISTRY_CFLAGS) UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS) $(WAYLAND_EGL_LIBS) $(XKBCOMMON_LIBS) $(XKBREGISTRY_LIBS) $(PTHREAD_LIBS) -lm +IMPORTS = advapi32
SOURCES = \ display.c \ diff --git a/dlls/winewayland.drv/dllmain.c b/dlls/winewayland.drv/dllmain.c index d040620957b..4fe2ba2561c 100644 --- a/dlls/winewayland.drv/dllmain.c +++ b/dlls/winewayland.drv/dllmain.c @@ -20,6 +20,7 @@
#include "waylanddrv_dll.h"
+#include "winreg.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); @@ -38,12 +39,55 @@ static DWORD WINAPI wayland_read_events_thread(void *arg) BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { DWORD tid; + DWORD regRes; + DWORD regValueSize; + LPWSTR regValue = NULL; + HKEY hSubKey = NULL; + BOOL unaccelerated_pointer = FALSE;
if (reason != DLL_PROCESS_ATTACH) return TRUE;
DisableThreadLibraryCalls(instance); if (__wine_init_unix_call()) return FALSE;
+ regRes = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\Wine\Wayland Driver", 0, KEY_READ, &hSubKey); + if (regRes != ERROR_SUCCESS) + { + WINE_TRACE("Registry key HKCU\Software\Wine\Wayland Driver not exist.\n"); + goto close_registry; + } + + regRes = RegQueryValueExW(hSubKey, L"unaccelerated_pointer", NULL, NULL, NULL, ®ValueSize); + if (regRes != ERROR_SUCCESS) + { + WINE_ERR("Can't get value size for HKCU\Software\Wine\Wayland Driver\unaccelerated_pointer. Error: %ld\n", regRes); + goto close_registry; + } + + regValue = calloc(regValueSize + 1, sizeof(*regValue)); + + regRes = RegQueryValueExW(hSubKey, L"unaccelerated_pointer", NULL, NULL, (LPBYTE)regValue, ®ValueSize); + if (regRes != ERROR_SUCCESS) + { + WINE_ERR("Can't get value for HKCU\Software\Wine\Wayland Driver\unaccelerated_pointer. Error: %ld\n", regRes); + free(regValue); + goto close_registry; + } + + WINE_TRACE("Registry HKCU\Software\Wine\Wayland Driver\unaccelerated_pointer value=%hs.\n", regValue); + if(*regValue) + unaccelerated_pointer = TRUE; + + free(regValue); + +close_registry: + RegCloseKey(hSubKey); + + if(unaccelerated_pointer) + WAYLANDDRV_UNIX_CALL(set_unaccelerated_pointer, &unaccelerated_pointer); + else + WAYLANDDRV_UNIX_CALL(set_unaccelerated_pointer, NULL); + if (WAYLANDDRV_UNIX_CALL(init, NULL)) return FALSE;
diff --git a/dlls/winewayland.drv/unixlib.h b/dlls/winewayland.drv/unixlib.h index dc3bfdf8893..53b8afada1d 100644 --- a/dlls/winewayland.drv/unixlib.h +++ b/dlls/winewayland.drv/unixlib.h @@ -27,6 +27,7 @@ enum waylanddrv_unix_func { waylanddrv_unix_func_init, waylanddrv_unix_func_read_events, + waylanddrv_unix_func_set_unaccelerated_pointer, waylanddrv_unix_func_count, };
diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index df76a4e9954..05aea799e45 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -34,6 +34,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
+extern BOOL waylanddrv_unaccelerated_pointer; + static HWND wayland_pointer_get_focused_hwnd(void) { struct wayland_pointer *pointer = &process_wayland.pointer; @@ -259,15 +261,28 @@ static void relative_pointer_v1_relative_motion(void *data, POINT screen, origin; struct wayland_surface *surface; RECT window_rect; + double delta_x; + double delta_y;
if (!(hwnd = wayland_pointer_get_focused_hwnd())) return; if (!(surface = wayland_surface_lock_hwnd(hwnd))) return;
window_rect = surface->window.rect;
+ if(waylanddrv_unaccelerated_pointer) + { + delta_x = wl_fixed_to_double(dx_unaccel); + delta_y = wl_fixed_to_double(dy_unaccel); + } + else + { + delta_x = wl_fixed_to_double(dx); + delta_y = wl_fixed_to_double(dy); + } + wayland_surface_coords_to_window(surface, - wl_fixed_to_double(dx), - wl_fixed_to_double(dy), + delta_x, + delta_y, (int *)&screen.x, (int *)&screen.y);
pthread_mutex_unlock(&surface->mutex); @@ -313,8 +328,8 @@ static void relative_pointer_v1_relative_motion(void *data, input.mi.dy = screen.y; input.mi.dwFlags = MOUSEEVENTF_MOVE;
- TRACE("hwnd=%p wayland_dxdy=%.2f,%.2f screen_dxdy=%d,%d\n", - hwnd, wl_fixed_to_double(dx), wl_fixed_to_double(dy), + TRACE("hwnd=%p unaccelerated_pointer=%d wayland_dxdy=%.2f,%.2f screen_dxdy=%d,%d\n", + hwnd, waylanddrv_unaccelerated_pointer, delta_x, delta_y, (int)screen.x, (int)screen.y);
NtUserSendHardwareInput(hwnd, 0, &input, 0); diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c index 61e7df16f14..5072cb8696e 100644 --- a/dlls/winewayland.drv/waylanddrv_main.c +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -79,6 +79,14 @@ static void wayland_init_process_name(void) } }
+BOOL waylanddrv_unaccelerated_pointer; + +static NTSTATUS waylanddrv_unix_set_unaccelerated_pointer(void *arg) +{ + waylanddrv_unaccelerated_pointer = arg ? *((BOOL *)arg) : FALSE; + return 0; +} + static NTSTATUS waylanddrv_unix_init(void *arg) { /* Set the user driver functions now so that they are available during @@ -110,6 +118,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = { waylanddrv_unix_init, waylanddrv_unix_read_events, + waylanddrv_unix_set_unaccelerated_pointer, };
C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == waylanddrv_unix_func_count); @@ -120,6 +129,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { waylanddrv_unix_init, waylanddrv_unix_read_events, + waylanddrv_unix_set_unaccelerated_pointer, };
C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == waylanddrv_unix_func_count);
@h0tc0d3 I think this is not the correct approach for raw input.
First you need to take the wine-staging patches from user32-rawinput-mouse that add wineserver support for RAWINPUT mouse message: - [0001-server-Add-support-for-absolute-rawinput-mouse-messa.patch](https://gitlab.winehq.org/wine/wine-staging/-/blob/12bbb07ced41f421b47d0d7be...) - [0004-server-Add-send_hardware_message-flags-for-rawinput-.patch](https://gitlab.winehq.org/wine/wine-staging/-/blob/12bbb07ced41f421b47d0d7be...)
Then you need to inject the normal mouse input motion with NtUserSendHardwareInput with flag `SEND_HWMSG_NO_RAW`. That will prevent wineserver from synthesizing rawinput from regular accelerated input.
Finally you need to inject the unaccelerated values with NtUserSendHardwareInput with flag `SEND_HWMSG_NO_MSG`. It will take the x/y values given and apply it directly to the rawinput input msg sent to the windows app.
Some care might be needed with respect to non-motion raw events (like button presses). You might want to let wine synthesize raw button press, I'm not really sure what is best.
I did a similar patch for x11drv -- https://github.com/EBADBEEF/wine/commit/106840af0eb1d13e790c4fcbf6b08ca6d6c5... . Take a look at [X11DRV_RawMotion()](https://github.com/EBADBEEF/wine/blob/proton_9_0-1-rawinput1/dlls/winex11.dr...) there to see how I injected *just* the raw input and not regular input. Also [send_mouse_input](https://github.com/EBADBEEF/wine/blob/proton_9_0-1-rawinput1/dlls/winex11.dr...). I'm forgetting some of the details of the implementation (wish I had left myself more comments!). Anyway, hopefully you get the idea.
Proton is still using the old-style wine-staging server patches (that adds SEND_HWMSG_RAWINPUT flag), and needs to be refreshed for wine 9.0. I also re-wrote the xinput2 handling to be much simpler, which might be too ambitious to be accepted in wine as-is. BUT I have been using it to play FPS games for the last 6 months or so on proton and it is really nice to have actual raw input working. I think this is a really important feature for wine!
My quick method for testing raw input was: - Use MouseTester exe from https://github.com/microe1/MouseTester/releases - Using sway on wayland, set desktop mouse sensitivity really really slow `swaymsg -- input "*" accel_profile "flat" ; input "*" pointer_accel '-1.0'` - Make sure that raw input is not really really slow like my desktop mouse ;-) - Add rawinput trace prints ;-) - Also note that for XWayland input events only come if window is focused
I'm about to go on vacation for two weeks but I'm going to try to refresh my changes against the new wine when I get back. If you haven't given it a shot with the wayland driver, I will! I like the idea of a registry key to make this easier to merge in. Hopefully this brain dump was useful to someone.