diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 49719053..4fd87fea 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -304,6 +304,11 @@ patch_enable_all () enable_user32_ScrollWindowEx="$1" enable_user32_ShowWindow="$1" enable_user32_msgbox_Support_WM_COPY_mesg="$1" + enable_user32_rawinput_hid="$1" + enable_user32_rawinput_keyboard="$1" + enable_user32_rawinput_mouse="$1" + enable_user32_rawinput_mouse_experimental="$1" + enable_user32_rawinput_nolegacy="$1" enable_user32_recursive_activation="$1" enable_user32_window_activation="$1" enable_uxtheme_CloseThemeClass="$1" @@ -1041,6 +1046,21 @@ patch_enable () user32-msgbox-Support-WM_COPY-mesg) enable_user32_msgbox_Support_WM_COPY_mesg="$2" ;; + user32-rawinput-hid) + enable_user32_rawinput_hid="$2" + ;; + user32-rawinput-keyboard) + enable_user32_rawinput_keyboard="$2" + ;; + user32-rawinput-mouse) + enable_user32_rawinput_mouse="$2" + ;; + user32-rawinput-mouse-experimental) + enable_user32_rawinput_mouse_experimental="$2" + ;; + user32-rawinput-nolegacy) + enable_user32_rawinput_nolegacy="$2" + ;; user32-recursive-activation) enable_user32_recursive_activation="$2" ;; @@ -1671,6 +1691,41 @@ if test "$enable_user32_window_activation" -eq 1; then enable_user32_recursive_activation=1 fi +if test "$enable_user32_rawinput_mouse_experimental" -eq 1; then + if test "$enable_user32_rawinput_nolegacy" -gt 1; then + abort "Patchset user32-rawinput-nolegacy disabled, but user32-rawinput-mouse-experimental depends on that." + fi + enable_user32_rawinput_nolegacy=1 +fi + +if test "$enable_user32_rawinput_keyboard" -eq 1; then + if test "$enable_user32_rawinput_hid" -gt 1; then + abort "Patchset user32-rawinput-hid disabled, but user32-rawinput-keyboard depends on that." + fi + enable_user32_rawinput_hid=1 +fi + +if test "$enable_user32_rawinput_hid" -eq 1; then + if test "$enable_user32_rawinput_nolegacy" -gt 1; then + abort "Patchset user32-rawinput-nolegacy disabled, but user32-rawinput-hid depends on that." + fi + enable_user32_rawinput_nolegacy=1 +fi + +if test "$enable_user32_rawinput_nolegacy" -eq 1; then + if test "$enable_user32_rawinput_mouse" -gt 1; then + abort "Patchset user32-rawinput-mouse disabled, but user32-rawinput-nolegacy depends on that." + fi + enable_user32_rawinput_mouse=1 +fi + +if test "$enable_user32_rawinput_mouse" -eq 1; then + if test "$enable_winex11_drv_mouse_coorrds" -gt 1; then + abort "Patchset winex11.drv-mouse-coorrds disabled, but user32-rawinput-mouse depends on that." + fi + enable_winex11_drv_mouse_coorrds=1 +fi + if test "$enable_stdole32_tlb_SLTG_Typelib" -eq 1; then if test "$enable_widl_SLTG_Typelib_Support" -gt 1; then abort "Patchset widl-SLTG_Typelib_Support disabled, but stdole32.tlb-SLTG_Typelib depends on that." @@ -6450,6 +6505,158 @@ if test "$enable_user32_msgbox_Support_WM_COPY_mesg" -eq 1; then ) >> "$patchlist" fi +# Patchset winex11.drv-mouse-coorrds +# | +# | This patchset fixes the following Wine bugs: +# | * [#46309] winex11.drv: Use root-relative coordinates for events, if possible. +# | +# | Modified files: +# | * dlls/winex11.drv/mouse.c +# | +if test "$enable_winex11_drv_mouse_coorrds" -eq 1; then + patch_apply winex11.drv-mouse-coorrds/0001-winex11.drv-mouse-Use-root-relative-coordinates-for-ev.patch + ( + printf '%s\n' '+ { "Gabriel Ivăncescu", "winex11.drv/mouse: Use root-relative coordinates for events, if possible.", 1 },'; + ) >> "$patchlist" +fi + +# Patchset user32-rawinput-mouse +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * winex11.drv-mouse-coorrds +# | +# | This patchset fixes the following Wine bugs: +# | * [#42631] - user32: Add Raw Input support. +# | +# | Modified files: +# | * dlls/dinput/device_private.h, dlls/dinput/dinput_main.c, dlls/dinput/mouse.c, dlls/dinput8/tests/device.c, +# | dlls/user32/input.c, dlls/user32/rawinput.c, dlls/user32/tests/input.c, dlls/user32/user32.spec, +# | dlls/wineandroid.drv/keyboard.c, dlls/wineandroid.drv/window.c, dlls/winemac.drv/ime.c, dlls/winemac.drv/keyboard.c, +# | dlls/winemac.drv/mouse.c, dlls/winex11.drv/event.c, dlls/winex11.drv/keyboard.c, dlls/winex11.drv/mouse.c, +# | dlls/winex11.drv/x11drv.h, dlls/winex11.drv/x11drv_main.c, include/winuser.h, server/protocol.def, server/queue.c +# | +if test "$enable_user32_rawinput_mouse" -eq 1; then + patch_apply user32-rawinput-mouse/0001-user32-tests-Add-rawinput-test-for-ClipCursor-intera.patch + patch_apply user32-rawinput-mouse/0002-user32-tests-Add-rawinput-test-for-cross-thread-inte.patch + patch_apply user32-rawinput-mouse/0003-user32-tests-Add-rawinput-test-for-cross-process-int.patch + patch_apply user32-rawinput-mouse/0004-server-Add-send_hardware_message-flags-for-rawinput-.patch + patch_apply user32-rawinput-mouse/0005-server-Broadcast-rawinput-message-if-request-flag-is.patch + patch_apply user32-rawinput-mouse/0006-user32-Add-__wine_send_input-flags-to-hint-raw-input.patch + patch_apply user32-rawinput-mouse/0007-winex11.drv-Advertise-XInput2-version-2.1-support.patch + patch_apply user32-rawinput-mouse/0008-winex11.drv-Keep-track-of-pointer-and-device-button-.patch + patch_apply user32-rawinput-mouse/0009-winex11.drv-Listen-to-RawMotion-and-RawButton-events.patch + patch_apply user32-rawinput-mouse/0010-user32-Implement-GetRegisteredRawInputDevices.patch + patch_apply user32-rawinput-mouse/0011-dinput8-Add-support-for-dinput-devices-that-use-raw-.patch + patch_apply user32-rawinput-mouse/0012-dinput8-Use-raw-input-interface-for-dinput8-mouse-de.patch + ( + printf '%s\n' '+ { "Rémi Bernon", "user32/tests: Add rawinput test for ClipCursor interactions.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "user32/tests: Add rawinput test for cross-thread interactions.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "user32/tests: Add rawinput test for cross-process interactions.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "server: Add send_hardware_message flags for rawinput translation.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "server: Broadcast rawinput message if request flag is SEND_HWMSG_RAWINPUT.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "user32: Add __wine_send_input flags to hint raw input translation.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "winex11.drv: Advertise XInput2 version 2.1 support.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "winex11.drv: Keep track of pointer and device button mappings.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "winex11.drv: Listen to RawMotion and RawButton* events in the desktop thread.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "user32: Implement GetRegisteredRawInputDevices.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "dinput8: Add support for dinput devices that use raw input interface.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "dinput8: Use raw input interface for dinput8 mouse device.", 1 },'; + ) >> "$patchlist" +fi + +# Patchset user32-rawinput-nolegacy +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * winex11.drv-mouse-coorrds, user32-rawinput-mouse +# | +# | Modified files: +# | * dlls/dinput/dinput_main.c, dlls/dinput8/tests/device.c, dlls/user32/rawinput.c, server/queue.c +# | +if test "$enable_user32_rawinput_nolegacy" -eq 1; then + patch_apply user32-rawinput-nolegacy/0001-dinput8-tests-Add-test-for-DISCL_EXCLUSIVE-flag-inte.patch + patch_apply user32-rawinput-nolegacy/0002-user32-Add-support-for-RIDEV_NOLEGACY-flag-in-Regist.patch + patch_apply user32-rawinput-nolegacy/0003-dinput-Set-RIDEV_INPUTSINK-flag-only-when-DISCL_BACK.patch + patch_apply user32-rawinput-nolegacy/0004-dinput-Set-correct-rawinput-flags-for-DISCL_EXCLUSIV.patch + ( + printf '%s\n' '+ { "Rémi Bernon", "dinput8/tests: Add test for DISCL_EXCLUSIVE flag interaction with rawinput.", 1 },'; + printf '%s\n' '+ { "Derek Lesho", "user32: Add support for RIDEV_NOLEGACY flag in RegisterRawInputDevices.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "dinput: Set RIDEV_INPUTSINK flag only when DISCL_BACKGROUND is requested.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "dinput: Set correct rawinput flags for DISCL_EXCLUSIVE.", 1 },'; + ) >> "$patchlist" +fi + +# Patchset user32-rawinput-hid +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * winex11.drv-mouse-coorrds, user32-rawinput-mouse, user32-rawinput-nolegacy +# | +# | Modified files: +# | * dlls/hidclass.sys/device.c, dlls/hidclass.sys/hid.h, dlls/hidclass.sys/pnp.c, dlls/user32/message.c, +# | dlls/user32/rawinput.c, dlls/user32/user_private.h, server/protocol.def, server/queue.c, server/trace.c +# | +if test "$enable_user32_rawinput_hid" -eq 1; then + patch_apply user32-rawinput-hid/0001-server-Add-process-argument-to-find_rawinput_device.patch + patch_apply user32-rawinput-hid/0002-server-Allow-extra-data-for-hardware_msg_data-messag.patch + patch_apply user32-rawinput-hid/0003-server-Add-HID-input-message-type-to-send_hardware_m.patch + patch_apply user32-rawinput-hid/0004-user32-Implement-WM_INPUT-RIM_TYPEHID-message-handli.patch + patch_apply user32-rawinput-hid/0005-hidclass.sys-Send-input-message-to-server-when-HID-r.patch + ( + printf '%s\n' '+ { "Rémi Bernon", "server: Add process argument to find_rawinput_device.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "server: Allow extra data for hardware_msg_data message.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "server: Add HID input message type to send_hardware_message request.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "user32: Implement WM_INPUT/RIM_TYPEHID message handling.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "hidclass.sys: Send input message to server when HID report is received.", 1 },'; + ) >> "$patchlist" +fi + +# Patchset user32-rawinput-keyboard +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * winex11.drv-mouse-coorrds, user32-rawinput-mouse, user32-rawinput-nolegacy, user32-rawinput-hid +# | +# | Modified files: +# | * dlls/dinput/device.c, dlls/dinput/device_private.h, dlls/dinput/keyboard.c, dlls/dinput/mouse.c, +# | dlls/dinput8/tests/device.c, dlls/user32/rawinput.c, dlls/user32/tests/input.c, dlls/winex11.drv/keyboard.c, +# | dlls/winex11.drv/mouse.c, dlls/winex11.drv/x11drv.h, server/queue.c +# | +if test "$enable_user32_rawinput_keyboard" -eq 1; then + patch_apply user32-rawinput-keyboard/0001-dinput-Add-DIERR_INPUTLOST-error-code-support-for-DI.patch + patch_apply user32-rawinput-keyboard/0002-dinput8-Use-raw-input-interface-for-dinput8-keyboard.patch + patch_apply user32-rawinput-keyboard/0003-user32-Add-support-for-RIDEV_INPUTSINK-flag-in-Regis.patch + patch_apply user32-rawinput-keyboard/0004-winex11.drv-Listen-to-RawKey-events-in-the-desktop-t.patch + ( + printf '%s\n' '+ { "Rémi Bernon", "dinput: Add DIERR_INPUTLOST error code support for DISCL_FOREGROUND cooperative level.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "dinput8: Use raw input interface for dinput8 keyboard device.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "user32: Add support for RIDEV_INPUTSINK flag in RegisterRawInputDevices.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "winex11.drv: Listen to RawKey* events in the desktop thread.", 1 },'; + ) >> "$patchlist" +fi + +# Patchset user32-rawinput-mouse-experimental +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * winex11.drv-mouse-coorrds, user32-rawinput-mouse, user32-rawinput-nolegacy +# | +# | This patchset fixes the following Wine bugs: +# | * [#45882] - Raw Input should use untransformed mouse values (affects Overwatch, several Source games). +# | +# | Modified files: +# | * dlls/user32/message.c, dlls/winex11.drv/mouse.c, dlls/winex11.drv/x11drv.h, dlls/winex11.drv/x11drv_main.c, +# | server/queue.c +# | +if test "$enable_user32_rawinput_mouse_experimental" -eq 1; then + patch_apply user32-rawinput-mouse-experimental/0001-winex11.drv-Add-support-for-absolute-RawMotion-event.patch + patch_apply user32-rawinput-mouse-experimental/0002-winex11.drv-Send-relative-RawMotion-events-unprocess.patch + patch_apply user32-rawinput-mouse-experimental/0003-winex11.drv-Implement-relative-wheel-input-from-RawM.patch + patch_apply user32-rawinput-mouse-experimental/0004-winex11.drv-Accumulate-mouse-movement-to-avoid-round.patch + ( + printf '%s\n' '+ { "Derek Lesho", "winex11.drv: Add support for absolute RawMotion events.", 1 },'; + printf '%s\n' '+ { "Rémi Bernon", "winex11.drv: Send relative RawMotion events unprocessed.", 1 },'; + printf '%s\n' '+ { "Derek Lesho", "winex11.drv: Implement relative wheel input from RawMotion events.", 1 },'; + printf '%s\n' '+ { "Jordan Galby", "winex11.drv: Accumulate mouse movement to avoid rounding losses.", 1 },'; + ) >> "$patchlist" +fi + # Patchset user32-recursive-activation # | # | This patchset fixes the following Wine bugs: @@ -7304,21 +7511,6 @@ if test "$enable_winex11_drv_Query_server_position" -eq 1; then ) >> "$patchlist" fi -# Patchset winex11.drv-mouse-coorrds -# | -# | This patchset fixes the following Wine bugs: -# | * [#46309] winex11.drv: Use root-relative coordinates for events, if possible. -# | -# | Modified files: -# | * dlls/winex11.drv/mouse.c -# | -if test "$enable_winex11_drv_mouse_coorrds" -eq 1; then - patch_apply winex11.drv-mouse-coorrds/0001-winex11.drv-mouse-Use-root-relative-coordinates-for-ev.patch - ( - printf '%s\n' '+ { "Gabriel Ivăncescu", "winex11.drv/mouse: Use root-relative coordinates for events, if possible.", 1 },'; - ) >> "$patchlist" -fi - # Patchset wininet-Cleanup # | # | Modified files: diff --git a/patches/user32-rawinput-hid/0001-server-Add-process-argument-to-find_rawinput_device.patch b/patches/user32-rawinput-hid/0001-server-Add-process-argument-to-find_rawinput_device.patch new file mode 100644 index 00000000..7275a048 --- /dev/null +++ b/patches/user32-rawinput-hid/0001-server-Add-process-argument-to-find_rawinput_device.patch @@ -0,0 +1,53 @@ +From 694ff514bfce59c2590668e3e812d501b713acdb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 12 Sep 2019 14:14:08 +0200 +Subject: [PATCH 1/5] server: Add process argument to find_rawinput_device. + +We need to be able to iterate all registered rawinput devices for +foreign processes, not only the current one. +--- + server/queue.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/server/queue.c b/server/queue.c +index f5dc06100d1..3ed7e82a906 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -1576,11 +1576,11 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru + return win; + } + +-static struct rawinput_device_entry *find_rawinput_device( unsigned short usage_page, unsigned short usage ) ++static struct rawinput_device_entry *find_rawinput_device( struct process *process, unsigned short usage_page, unsigned short usage ) + { + struct rawinput_device_entry *e; + +- LIST_FOR_EACH_ENTRY( e, ¤t->process->rawinput_devices, struct rawinput_device_entry, entry ) ++ LIST_FOR_EACH_ENTRY( e, &process->rawinput_devices, struct rawinput_device_entry, entry ) + { + if (e->device.usage_page != usage_page || e->device.usage != usage) continue; + return e; +@@ -1593,7 +1593,7 @@ static void update_rawinput_device(const struct rawinput_device *device) + { + struct rawinput_device_entry *e; + +- if (!(e = find_rawinput_device( device->usage_page, device->usage ))) ++ if (!(e = find_rawinput_device( current->process, device->usage_page, device->usage ))) + { + if (!(e = mem_alloc( sizeof(*e) ))) return; + list_add_tail( ¤t->process->rawinput_devices, &e->entry ); +@@ -3375,9 +3375,9 @@ DECL_HANDLER(update_rawinput_devices) + update_rawinput_device(&devices[i]); + } + +- e = find_rawinput_device( 1, 2 ); ++ e = find_rawinput_device( current->process, 1, 2 ); + current->process->rawinput_mouse = e ? &e->device : NULL; +- e = find_rawinput_device( 1, 6 ); ++ e = find_rawinput_device( current->process, 1, 6 ); + current->process->rawinput_kbd = e ? &e->device : NULL; + } + +-- +2.24.1 + diff --git a/patches/user32-rawinput-hid/0002-server-Allow-extra-data-for-hardware_msg_data-messag.patch b/patches/user32-rawinput-hid/0002-server-Allow-extra-data-for-hardware_msg_data-messag.patch new file mode 100644 index 00000000..f02292e0 --- /dev/null +++ b/patches/user32-rawinput-hid/0002-server-Allow-extra-data-for-hardware_msg_data-messag.patch @@ -0,0 +1,150 @@ +From 56609fdaab139ec8718cf0c4963e6990c9b88003 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 19 Sep 2019 09:20:44 +0200 +Subject: [PATCH 2/5] server: Allow extra data for hardware_msg_data message. + +The RIM_TYPEHID messages will have to carry the variable length HID +report. +--- + server/queue.c | 43 +++++++++++++++++++++++++++---------------- + 1 file changed, 27 insertions(+), 16 deletions(-) + +diff --git a/server/queue.c b/server/queue.c +index 3ed7e82a906..feff00e2b9f 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -398,13 +398,13 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_ + + /* allocate a hardware message and its data */ + static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_source source, +- unsigned int time ) ++ unsigned int time, data_size_t extra_len ) + { + struct hardware_msg_data *msg_data; + struct message *msg; + + if (!(msg = mem_alloc( sizeof(*msg) ))) return NULL; +- if (!(msg_data = mem_alloc( sizeof(*msg_data) ))) ++ if (!(msg_data = mem_alloc( sizeof(*msg_data) + extra_len ))) + { + free( msg ); + return NULL; +@@ -413,9 +413,9 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour + msg->type = MSG_HARDWARE; + msg->time = time; + msg->data = msg_data; +- msg->data_size = sizeof(*msg_data); ++ msg->data_size = sizeof(*msg_data) + extra_len; + +- memset( msg_data, 0, sizeof(*msg_data) ); ++ memset( msg_data, 0, sizeof(*msg_data) + extra_len ); + msg_data->info = info; + msg_data->source = source; + return msg; +@@ -430,7 +430,7 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) + if (current->process->rawinput_mouse && + current->process->rawinput_mouse->flags & RIDEV_NOLEGACY) return; + +- if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return; ++ if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return; + + msg->msg = WM_MOUSEMOVE; + msg->x = x; +@@ -1743,6 +1743,8 @@ struct rawinput_message + struct hw_msg_source source; + unsigned int time; + struct hardware_msg_data data; ++ const void *extra; ++ data_size_t extra_len; + }; + + static int queue_rawinput_message( struct process* process, void* user ) +@@ -1752,6 +1754,7 @@ static int queue_rawinput_message( struct process* process, void* user ) + struct desktop *desktop = NULL; + struct thread *thread = NULL, *foreground = NULL; + struct message *msg; ++ struct hardware_msg_data *msg_data; + + if (raw_msg->data.rawinput.type == RIM_TYPEMOUSE) + device = process->rawinput_mouse; +@@ -1774,14 +1777,18 @@ static int queue_rawinput_message( struct process* process, void* user ) + thread->process != foreground->process) + goto done; + +- if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time ))) ++ if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time, raw_msg->extra_len ))) + goto done; ++ msg_data = msg->data; + + msg->win = device->target; + msg->msg = WM_INPUT; + msg->wparam = RIM_INPUT; + msg->lparam = 0; +- memcpy( msg->data, &raw_msg->data, sizeof(raw_msg->data) ); ++ ++ memcpy( msg_data, &raw_msg->data, sizeof(*msg_data) ); ++ if (raw_msg->extra_len && raw_msg->extra) ++ memcpy( msg_data + 1, raw_msg->extra, raw_msg->extra_len ); + + queue_hardware_message( desktop, msg, 0 ); + +@@ -1850,9 +1857,11 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons + + if (req_flags & SEND_HWMSG_RAWINPUT) + { +- raw_msg.desktop = desktop; +- raw_msg.source = source; +- raw_msg.time = time; ++ raw_msg.desktop = desktop; ++ raw_msg.source = source; ++ raw_msg.time = time; ++ raw_msg.extra = NULL; ++ raw_msg.extra_len = 0; + + msg_data = &raw_msg.data; + msg_data->info = input->mouse.info; +@@ -1879,7 +1888,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons + if (!(flags & (1 << i))) continue; + flags &= ~(1 << i); + +- if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0; ++ if (!(msg = alloc_hardware_message( input->mouse.info, source, time, 0 ))) return 0; + msg_data = msg->data; + + msg->win = get_user_full_handle( win ); +@@ -1983,9 +1992,11 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c + + if (req_flags & SEND_HWMSG_RAWINPUT) + { +- raw_msg.desktop = desktop; +- raw_msg.source = source; +- raw_msg.time = time; ++ raw_msg.desktop = desktop; ++ raw_msg.source = source; ++ raw_msg.time = time; ++ raw_msg.extra = NULL; ++ raw_msg.extra_len = 0; + + msg_data = &raw_msg.data; + msg_data->info = input->kbd.info; +@@ -2006,7 +2017,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c + if ((device = current->process->rawinput_kbd) && (device->flags & RIDEV_NOLEGACY)) + return 0; + +- if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; ++ if (!(msg = alloc_hardware_message( input->kbd.info, source, time, 0 ))) return 0; + msg_data = msg->data; + + msg->win = get_user_full_handle( win ); +@@ -2044,7 +2055,7 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ + struct hw_msg_source source = { IMDT_UNAVAILABLE, origin }; + struct message *msg; + +- if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return; ++ if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return; + + msg->win = get_user_full_handle( win ); + msg->msg = input->hw.msg; +-- +2.24.1 + diff --git a/patches/user32-rawinput-hid/0003-server-Add-HID-input-message-type-to-send_hardware_m.patch b/patches/user32-rawinput-hid/0003-server-Add-HID-input-message-type-to-send_hardware_m.patch new file mode 100644 index 00000000..19f6f599 --- /dev/null +++ b/patches/user32-rawinput-hid/0003-server-Add-HID-input-message-type-to-send_hardware_m.patch @@ -0,0 +1,262 @@ +From d0347613c7149144d4339109b641901537c4c326 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Mon, 11 Nov 2019 18:35:18 +0100 +Subject: [PATCH 3/5] server: Add HID input message type to + send_hardware_message request. + +--- + dlls/user32/message.c | 4 +++- + server/protocol.def | 26 +++++++++++++++++++--- + server/queue.c | 50 ++++++++++++++++++++++++++++++++++++++----- + server/trace.c | 10 ++++++--- + 4 files changed, 78 insertions(+), 12 deletions(-) + +diff --git a/dlls/user32/message.c b/dlls/user32/message.c +index cc25d2f6c2f..55bbe409c9e 100644 +--- a/dlls/user32/message.c ++++ b/dlls/user32/message.c +@@ -3354,10 +3354,10 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) + { + req->win = wine_server_user_handle( hwnd ); + req->flags = flags; +- req->input.type = input->type; + switch (input->type) + { + case INPUT_MOUSE: ++ req->input.type = HW_INPUT_MOUSE; + req->input.mouse.x = input->u.mi.dx; + req->input.mouse.y = input->u.mi.dy; + req->input.mouse.data = input->u.mi.mouseData; +@@ -3366,6 +3366,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) + req->input.mouse.info = input->u.mi.dwExtraInfo; + break; + case INPUT_KEYBOARD: ++ req->input.type = HW_INPUT_KEYBOARD; + req->input.kbd.vkey = input->u.ki.wVk; + req->input.kbd.scan = input->u.ki.wScan; + req->input.kbd.flags = input->u.ki.dwFlags; +@@ -3373,6 +3374,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) + req->input.kbd.info = input->u.ki.dwExtraInfo; + break; + case INPUT_HARDWARE: ++ req->input.type = HW_INPUT_HARDWARE; + req->input.hw.msg = input->u.hi.uMsg; + req->input.hw.lparam = MAKELONG( input->u.hi.wParamL, input->u.hi.wParamH ); + break; +diff --git a/server/protocol.def b/server/protocol.def +index d37dceba40c..85cc2ac6937 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -321,6 +321,13 @@ struct hardware_msg_data + int y; /* y coordinate */ + unsigned int data; /* mouse data */ + } mouse; ++ struct ++ { ++ int type; /* RIM_TYPEHID */ ++ obj_handle_t device; ++ unsigned int length; /* HID report length */ ++ /* followed by length bytes of HID report data */ ++ } hid; + } rawinput; + }; + +@@ -344,7 +351,7 @@ typedef union + int type; + struct + { +- int type; /* INPUT_KEYBOARD */ ++ int type; /* HW_INPUT_KEYBOARD */ + unsigned short vkey; /* virtual key code */ + unsigned short scan; /* scan code */ + unsigned int flags; /* event flags */ +@@ -353,7 +360,7 @@ typedef union + } kbd; + struct + { +- int type; /* INPUT_MOUSE */ ++ int type; /* HW_INPUT_MOUSE */ + int x; /* coordinates */ + int y; + unsigned int data; /* mouse data */ +@@ -363,11 +370,23 @@ typedef union + } mouse; + struct + { +- int type; /* INPUT_HARDWARE */ ++ int type; /* HW_INPUT_HARDWARE */ + unsigned int msg; /* message code */ + lparam_t lparam; /* message param */ + } hw; ++ struct ++ { ++ int type; /* HW_INPUT_HID */ ++ obj_handle_t device; ++ unsigned char usage_page; ++ unsigned char usage; ++ unsigned int length; ++ } hid; + } hw_input_t; ++#define HW_INPUT_MOUSE 0 ++#define HW_INPUT_KEYBOARD 1 ++#define HW_INPUT_HARDWARE 2 ++#define HW_INPUT_HID 3 + + typedef union + { +@@ -2361,6 +2380,7 @@ enum message_type + user_handle_t win; /* window handle */ + hw_input_t input; /* input data */ + unsigned int flags; /* flags (see below) */ ++ VARARG(data,bytes); /* hid report data */ + @REPLY + int wait; /* do we need to wait for a reply? */ + int prev_x; /* previous cursor position */ +diff --git a/server/queue.c b/server/queue.c +index feff00e2b9f..85aa896c7bd 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -1698,7 +1698,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa + struct msg_queue *queue; + struct message *msg; + timeout_t timeout = 2000 * -10000; /* FIXME: load from registry */ +- int id = (input->type == INPUT_MOUSE) ? WH_MOUSE_LL : WH_KEYBOARD_LL; ++ int id = (input->type == HW_INPUT_MOUSE) ? WH_MOUSE_LL : WH_KEYBOARD_LL; + + if (!(hook_thread = get_first_global_hook( id ))) return 0; + if (!(queue = hook_thread->queue)) return 0; +@@ -1716,7 +1716,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa + msg->data_size = hardware_msg->data_size; + msg->result = NULL; + +- if (input->type == INPUT_KEYBOARD) ++ if (input->type == HW_INPUT_KEYBOARD) + { + unsigned short vkey = input->kbd.vkey; + if (input->kbd.flags & KEYEVENTF_UNICODE) vkey = VK_PACKET; +@@ -1742,6 +1742,8 @@ struct rawinput_message + struct desktop *desktop; + struct hw_msg_source source; + unsigned int time; ++ unsigned char usage_page; ++ unsigned char usage; + struct hardware_msg_data data; + const void *extra; + data_size_t extra_len; +@@ -1750,6 +1752,7 @@ struct rawinput_message + static int queue_rawinput_message( struct process* process, void* user ) + { + const struct rawinput_message* raw_msg = user; ++ const struct rawinput_device_entry *entry; + const struct rawinput_device *device = NULL; + struct desktop *desktop = NULL; + struct thread *thread = NULL, *foreground = NULL; +@@ -1760,6 +1763,8 @@ static int queue_rawinput_message( struct process* process, void* user ) + device = process->rawinput_mouse; + else if (raw_msg->data.rawinput.type == RIM_TYPEKEYBOARD) + device = process->rawinput_kbd; ++ else if ((entry = find_rawinput_device( process, raw_msg->usage_page, raw_msg->usage ))) ++ device = &entry->device; + + if (!device) + goto done; +@@ -2067,6 +2072,38 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ + queue_hardware_message( desktop, msg, 1 ); + } + ++/* queue a hardware message for an hid event */ ++static void queue_hid_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, ++ unsigned int origin, struct msg_queue *sender, unsigned int req_flags, ++ const void *report, data_size_t report_len ) ++{ ++ struct hw_msg_source source = { IMDT_UNAVAILABLE, origin }; ++ struct hardware_msg_data *msg_data; ++ struct rawinput_message raw_msg; ++ ++ if (!(req_flags & SEND_HWMSG_RAWINPUT)) ++ return; ++ ++ raw_msg.desktop = NULL; /* send to all desktops */ ++ raw_msg.source = source; ++ raw_msg.time = get_tick_count(); ++ raw_msg.usage_page = input->hid.usage_page; ++ raw_msg.usage = input->hid.usage; ++ raw_msg.extra = report; ++ raw_msg.extra_len = report_len; ++ ++ msg_data = &raw_msg.data; ++ msg_data->flags = 0; ++ msg_data->rawinput.type = RIM_TYPEHID; ++ msg_data->rawinput.hid.device = input->hid.device; ++ msg_data->rawinput.hid.length = report_len; ++ ++ if (req_flags == SEND_HWMSG_RAWINPUT) ++ enum_processes( queue_rawinput_message, &raw_msg ); ++ else ++ queue_rawinput_message( current->process, &raw_msg ); ++} ++ + /* check message filter for a hardware message */ + static int check_hw_message_filter( user_handle_t win, unsigned int msg_code, + user_handle_t filter_win, unsigned int first, unsigned int last ) +@@ -2577,15 +2614,18 @@ DECL_HANDLER(send_hardware_message) + + switch (req->input.type) + { +- case INPUT_MOUSE: ++ case HW_INPUT_MOUSE: + reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender, req->flags ); + break; +- case INPUT_KEYBOARD: ++ case HW_INPUT_KEYBOARD: + reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender, req->flags ); + break; +- case INPUT_HARDWARE: ++ case HW_INPUT_HARDWARE: + queue_custom_hardware_message( desktop, req->win, origin, &req->input ); + break; ++ case HW_INPUT_HID: ++ queue_hid_message( desktop, req->win, &req->input, origin, sender, req->flags, get_req_data(), get_req_data_size() ); ++ break; + default: + set_error( STATUS_INVALID_PARAMETER ); + } +diff --git a/server/trace.c b/server/trace.c +index 18b56c729e4..c39c56087c1 100644 +--- a/server/trace.c ++++ b/server/trace.c +@@ -381,24 +381,28 @@ static void dump_hw_input( const char *prefix, const hw_input_t *input ) + { + switch (input->type) + { +- case INPUT_MOUSE: ++ case HW_INPUT_MOUSE: + fprintf( stderr, "%s{type=MOUSE,x=%d,y=%d,data=%08x,flags=%08x,time=%u", + prefix, input->mouse.x, input->mouse.y, input->mouse.data, input->mouse.flags, + input->mouse.time ); + dump_uint64( ",info=", &input->mouse.info ); + fputc( '}', stderr ); + break; +- case INPUT_KEYBOARD: ++ case HW_INPUT_KEYBOARD: + fprintf( stderr, "%s{type=KEYBOARD,vkey=%04hx,scan=%04hx,flags=%08x,time=%u", + prefix, input->kbd.vkey, input->kbd.scan, input->kbd.flags, input->kbd.time ); + dump_uint64( ",info=", &input->kbd.info ); + fputc( '}', stderr ); + break; +- case INPUT_HARDWARE: ++ case HW_INPUT_HARDWARE: + fprintf( stderr, "%s{type=HARDWARE,msg=%04x", prefix, input->hw.msg ); + dump_uint64( ",lparam=", &input->hw.lparam ); + fputc( '}', stderr ); + break; ++ case HW_INPUT_HID: ++ fprintf( stderr, "%s{type=HID,device=%04x,usage_page=%02x,usage=%02x,length=%04x}", ++ prefix, input->hid.device, input->hid.usage_page, input->hid.usage, input->hid.length ); ++ break; + default: + fprintf( stderr, "%s{type=%04x}", prefix, input->type ); + break; +-- +2.24.1 + diff --git a/patches/user32-rawinput-hid/0004-user32-Implement-WM_INPUT-RIM_TYPEHID-message-handli.patch b/patches/user32-rawinput-hid/0004-user32-Implement-WM_INPUT-RIM_TYPEHID-message-handli.patch new file mode 100644 index 00000000..204941e9 --- /dev/null +++ b/patches/user32-rawinput-hid/0004-user32-Implement-WM_INPUT-RIM_TYPEHID-message-handli.patch @@ -0,0 +1,138 @@ +From bbb38b3c009d47aced1ba746549fdc51e34cbaf4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 12 Sep 2019 14:48:23 +0200 +Subject: [PATCH 4/5] user32: Implement WM_INPUT/RIM_TYPEHID message handling. + +--- + dlls/user32/message.c | 19 ++++++++++++++++++- + dlls/user32/rawinput.c | 37 +++++++++++++++++++++++++++++++++++++ + dlls/user32/user_private.h | 2 ++ + 3 files changed, 57 insertions(+), 1 deletion(-) + +diff --git a/dlls/user32/message.c b/dlls/user32/message.c +index 55bbe409c9e..ae081cd6eb1 100644 +--- a/dlls/user32/message.c ++++ b/dlls/user32/message.c +@@ -2285,10 +2285,17 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data * + { + struct user_thread_info *thread_info = get_user_thread_info(); + RAWINPUT *rawinput = thread_info->rawinput; ++ SIZE_T data_len = 0; ++ ++ if (msg_data->rawinput.type == RIM_TYPEHID) ++ { ++ data_len = msg_data->rawinput.hid.length; ++ rawinput = thread_info->rawinput = HeapReAlloc( GetProcessHeap(), 0, rawinput, sizeof(*rawinput) + data_len ); ++ } + + if (!rawinput) + { +- thread_info->rawinput = HeapAlloc( GetProcessHeap(), 0, sizeof(*rawinput) ); ++ thread_info->rawinput = HeapAlloc( GetProcessHeap(), 0, sizeof(*rawinput) + data_len ); + if (!(rawinput = thread_info->rawinput)) return FALSE; + } + +@@ -2383,6 +2390,16 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data * + rawinput->data.keyboard.Message = msg_data->rawinput.kbd.message; + rawinput->data.keyboard.ExtraInformation = msg_data->info; + } ++ else if (msg_data->rawinput.type == RIM_TYPEHID) ++ { ++ rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data.hid.bRawData) + data_len; ++ rawinput->header.hDevice = rawinput_handle_from_device_handle(wine_server_ptr_handle(msg_data->rawinput.hid.device)); ++ rawinput->header.wParam = 0; ++ ++ rawinput->data.hid.dwSizeHid = data_len; ++ rawinput->data.hid.dwCount = 1; ++ memcpy(rawinput->data.hid.bRawData, msg_data + 1, data_len); ++ } + else + { + FIXME("Unhandled rawinput type %#x.\n", msg_data->rawinput.type); +diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c +index 8cf9f8ebf62..72ae91cfcb5 100644 +--- a/dlls/user32/rawinput.c ++++ b/dlls/user32/rawinput.c +@@ -43,6 +43,7 @@ struct hid_device + { + WCHAR *path; + HANDLE file; ++ HANDLE handle; + RID_DEVICE_INFO_HID info; + PHIDP_PREPARSED_DATA data; + }; +@@ -59,6 +60,8 @@ static CRITICAL_SECTION_DEBUG hid_devices_cs_debug = + }; + static CRITICAL_SECTION hid_devices_cs = { &hid_devices_cs_debug, -1, 0, 0, 0, 0 }; + ++extern DWORD WINAPI GetFinalPathNameByHandleW(HANDLE file, LPWSTR path, DWORD charcount, DWORD flags); ++ + static BOOL array_reserve(void **elements, unsigned int *capacity, unsigned int count, unsigned int size) + { + unsigned int new_capacity, max_capacity; +@@ -138,10 +141,43 @@ static struct hid_device *add_device(HDEVINFO set, SP_DEVICE_INTERFACE_DATA *ifa + device = &hid_devices[hid_devices_count++]; + device->path = path; + device->file = file; ++ device->handle = INVALID_HANDLE_VALUE; + + return device; + } + ++HANDLE rawinput_handle_from_device_handle(HANDLE device) ++{ ++ WCHAR buffer[sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH + 1]; ++ OBJECT_NAME_INFORMATION *info = (OBJECT_NAME_INFORMATION*)&buffer; ++ ULONG dummy; ++ unsigned int i; ++ ++ for (i = 0; i < hid_devices_count; ++i) ++ { ++ if (hid_devices[i].handle == device) ++ return &hid_devices[i]; ++ } ++ ++ if (NtQueryObject( device, ObjectNameInformation, &buffer, sizeof(buffer) - sizeof(WCHAR), &dummy ) || !info->Name.Buffer) ++ return NULL; ++ ++ /* replace \??\ with \\?\ to match hid_devices paths */ ++ if (info->Name.Length > 1 && info->Name.Buffer[0] == '\\' && info->Name.Buffer[1] == '?') ++ info->Name.Buffer[1] = '\\'; ++ ++ for (i = 0; i < hid_devices_count; ++i) ++ { ++ if (strcmpW(hid_devices[i].path, info->Name.Buffer) == 0) ++ { ++ hid_devices[i].handle = device; ++ return &hid_devices[i]; ++ } ++ } ++ ++ return NULL; ++} ++ + static void find_hid_devices(void) + { + static ULONGLONG last_check; +@@ -415,6 +451,7 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE device, UINT command, void *data, UINT + device, command, data, data_size); + + if (!data_size) return ~0U; ++ if (!device) return ~0U; + + /* each case below must set: + * *data_size: length (meaning defined by command) of data we want to copy +diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h +index e8f6abb6813..0c3d52fca5b 100644 +--- a/dlls/user32/user_private.h ++++ b/dlls/user32/user_private.h +@@ -378,4 +378,6 @@ static inline WCHAR *heap_strdupW(const WCHAR *src) + return dst; + } + ++extern HANDLE rawinput_handle_from_device_handle(HANDLE device); ++ + #endif /* __WINE_USER_PRIVATE_H */ +-- +2.24.1 + diff --git a/patches/user32-rawinput-hid/0005-hidclass.sys-Send-input-message-to-server-when-HID-r.patch b/patches/user32-rawinput-hid/0005-hidclass.sys-Send-input-message-to-server-when-HID-r.patch new file mode 100644 index 00000000..9cb632ef --- /dev/null +++ b/patches/user32-rawinput-hid/0005-hidclass.sys-Send-input-message-to-server-when-HID-r.patch @@ -0,0 +1,139 @@ +From 249548cff4ae17da6731e28a5fafe277a7b3d6ea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 18 Sep 2019 21:04:25 +0200 +Subject: [PATCH 5/5] hidclass.sys: Send input message to server when HID + report is received. + +--- + dlls/hidclass.sys/device.c | 30 ++++++++++++++++++++++++++++++ + dlls/hidclass.sys/hid.h | 1 + + dlls/hidclass.sys/pnp.c | 16 ++++++++++++++++ + 3 files changed, 47 insertions(+) + +diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c +index 0e905c8322f..369d847e3c1 100644 +--- a/dlls/hidclass.sys/device.c ++++ b/dlls/hidclass.sys/device.c +@@ -26,9 +26,11 @@ + #include "winuser.h" + #include "setupapi.h" + ++#include "wine/server.h" + #include "wine/debug.h" + #include "ddk/hidsdi.h" + #include "ddk/hidtypes.h" ++#include "ddk/ntifs.h" + #include "ddk/wdm.h" + + #include "initguid.h" +@@ -123,6 +125,8 @@ NTSTATUS HID_LinkDevice(DEVICE_OBJECT *device) + return status; + } + ++ ext->link_handle = INVALID_HANDLE_VALUE; ++ + /* FIXME: This should probably be done in mouhid.sys. */ + if (ext->preparseData->caps.UsagePage == HID_USAGE_PAGE_GENERIC + && ext->preparseData->caps.Usage == HID_USAGE_GENERIC_MOUSE) +@@ -207,6 +211,8 @@ void HID_DeleteDevice(DEVICE_OBJECT *device) + IoCompleteRequest(irp, IO_NO_INCREMENT); + } + ++ CloseHandle(ext->link_handle); ++ + TRACE("Delete device(%p) %s\n", device, debugstr_w(ext->device_name)); + HeapFree(GetProcessHeap(), 0, ext->device_name); + RtlFreeUnicodeString(&ext->link_name); +@@ -241,6 +247,28 @@ static NTSTATUS copy_packet_into_buffer(HID_XFER_PACKET *packet, BYTE* buffer, U + return STATUS_BUFFER_OVERFLOW; + } + ++static void HID_Device_sendRawInput(DEVICE_OBJECT *device, HID_XFER_PACKET *packet) ++{ ++ BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; ++ ++ if (ext->link_handle == INVALID_HANDLE_VALUE) ++ return; ++ ++ SERVER_START_REQ(send_hardware_message) ++ { ++ req->win = 0; ++ req->flags = SEND_HWMSG_RAWINPUT; ++ req->input.type = HW_INPUT_HID; ++ req->input.hid.device = wine_server_obj_handle(ext->link_handle); ++ req->input.hid.usage_page = ext->preparseData->caps.UsagePage; ++ req->input.hid.usage = ext->preparseData->caps.Usage; ++ req->input.hid.length = packet->reportBufferLen; ++ wine_server_add_data(req, packet->reportBuffer, packet->reportBufferLen); ++ wine_server_call(req); ++ } ++ SERVER_END_REQ; ++} ++ + static void HID_Device_processQueue(DEVICE_OBJECT *device) + { + IRP *irp; +@@ -324,6 +352,7 @@ static DWORD CALLBACK hid_device_thread(void *args) + if (irp->IoStatus.u.Status == STATUS_SUCCESS) + { + RingBuffer_Write(ext->ring_buffer, packet); ++ HID_Device_sendRawInput(device, packet); + HID_Device_processQueue(device); + } + +@@ -370,6 +399,7 @@ static DWORD CALLBACK hid_device_thread(void *args) + else + packet->reportId = 0; + RingBuffer_Write(ext->ring_buffer, packet); ++ HID_Device_sendRawInput(device, packet); + HID_Device_processQueue(device); + } + +diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h +index 36d13c009d7..f12e04d7898 100644 +--- a/dlls/hidclass.sys/hid.h ++++ b/dlls/hidclass.sys/hid.h +@@ -46,6 +46,7 @@ typedef struct _BASE_DEVICE_EXTENSION { + ULONG poll_interval; + WCHAR *device_name; + UNICODE_STRING link_name; ++ HANDLE link_handle; + WCHAR device_id[MAX_DEVICE_ID_LEN]; + WCHAR instance_id[MAX_DEVICE_ID_LEN]; + struct ReportRingBuffer *ring_buffer; +diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c +index 1c130e8dd80..b84a358dba4 100644 +--- a/dlls/hidclass.sys/pnp.c ++++ b/dlls/hidclass.sys/pnp.c +@@ -299,12 +299,28 @@ NTSTATUS WINAPI HID_PNP_Dispatch(DEVICE_OBJECT *device, IRP *irp) + case IRP_MN_START_DEVICE: + { + BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; ++ OBJECT_ATTRIBUTES attr; + + rc = minidriver->PNPDispatch(device, irp); + + IoSetDeviceInterfaceState(&ext->link_name, TRUE); + if (ext->is_mouse) + IoSetDeviceInterfaceState(&ext->mouse_link_name, TRUE); ++ ++ attr.Length = sizeof(attr); ++ attr.RootDirectory = 0; ++ attr.Attributes = OBJ_CASE_INSENSITIVE; ++ attr.ObjectName = &ext->link_name; ++ attr.SecurityDescriptor = NULL; ++ attr.SecurityQualityOfService = NULL; ++ NtOpenSymbolicLinkObject(&ext->link_handle, SYMBOLIC_LINK_QUERY, &attr); ++ ext->link_handle = ConvertToGlobalHandle(ext->link_handle); ++ ++ if (ext->link_handle == INVALID_HANDLE_VALUE) ++ ERR("Failed to open link %s, error %u.\n", debugstr_w(ext->link_name.Buffer), GetLastError()); ++ else ++ TRACE("Opened link handle: %p for %s\n", ext->link_handle, debugstr_w(ext->link_name.Buffer)); ++ + return rc; + } + case IRP_MN_REMOVE_DEVICE: +-- +2.24.1 + diff --git a/patches/user32-rawinput-hid/definition b/patches/user32-rawinput-hid/definition new file mode 100644 index 00000000..f07c03fe --- /dev/null +++ b/patches/user32-rawinput-hid/definition @@ -0,0 +1 @@ +Depends: user32-rawinput-nolegacy diff --git a/patches/user32-rawinput-keyboard/0001-dinput-Add-DIERR_INPUTLOST-error-code-support-for-DI.patch b/patches/user32-rawinput-keyboard/0001-dinput-Add-DIERR_INPUTLOST-error-code-support-for-DI.patch new file mode 100644 index 00000000..8310230e --- /dev/null +++ b/patches/user32-rawinput-keyboard/0001-dinput-Add-DIERR_INPUTLOST-error-code-support-for-DI.patch @@ -0,0 +1,82 @@ +From 3f8031f89ca79ef5c4dd46666cda2304aa647083 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Mon, 4 Nov 2019 23:33:09 +0100 +Subject: [PATCH 1/4] dinput: Add DIERR_INPUTLOST error code support for + DISCL_FOREGROUND cooperative level. + +--- + dlls/dinput/device.c | 2 ++ + dlls/dinput/device_private.h | 1 + + dlls/dinput/keyboard.c | 6 ++++++ + dlls/dinput/mouse.c | 6 ++++++ + 4 files changed, 15 insertions(+) + +diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c +index df7a22a303b..51a536f0892 100644 +--- a/dlls/dinput/device.c ++++ b/dlls/dinput/device.c +@@ -1087,6 +1087,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_Acquire(LPDIRECTINPUTDEVICE8W iface) + EnterCriticalSection(&This->crit); + res = This->acquired ? S_FALSE : DI_OK; + This->acquired = 1; ++ This->inputlost = 0; + LeaveCriticalSection(&This->crit); + if (res == DI_OK) + check_dinput_hooks(iface, TRUE); +@@ -1115,6 +1116,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface) + EnterCriticalSection(&This->crit); + res = !This->acquired ? DI_NOEFFECT : DI_OK; + This->acquired = 0; ++ This->inputlost = 0; + LeaveCriticalSection(&This->crit); + if (res == DI_OK) + check_dinput_hooks(iface, FALSE); +diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h +index 9116aaeab66..70b4ae1ef69 100644 +--- a/dlls/dinput/device_private.h ++++ b/dlls/dinput/device_private.h +@@ -68,6 +68,7 @@ struct IDirectInputDeviceImpl + DWORD dwCoopLevel; + HWND win; + int acquired; ++ int inputlost; + DI_EVENT_PROC event_proc; /* function to receive mouse & keyboard events */ + + BOOL use_raw_input; /* use raw input instead of low-level messages */ +diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c +index 1ec8003897a..2c62d3eab09 100644 +--- a/dlls/dinput/keyboard.c ++++ b/dlls/dinput/keyboard.c +@@ -371,6 +371,12 @@ static HRESULT WINAPI SysKeyboardWImpl_GetDeviceState(LPDIRECTINPUTDEVICE8W ifac + + check_dinput_events(); + ++ if ((This->base.dwCoopLevel & DISCL_FOREGROUND) && This->base.win != GetForegroundWindow()) ++ { ++ This->base.acquired = 0; ++ return DIERR_INPUTLOST; ++ } ++ + EnterCriticalSection(&This->base.crit); + + if (TRACE_ON(dinput)) { +diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c +index b8b88f38c15..06cf78de13a 100644 +--- a/dlls/dinput/mouse.c ++++ b/dlls/dinput/mouse.c +@@ -672,6 +672,12 @@ static HRESULT WINAPI SysMouseWImpl_GetDeviceState(LPDIRECTINPUTDEVICE8W iface, + + check_dinput_events(); + ++ if ((This->base.dwCoopLevel & DISCL_FOREGROUND) && This->base.win != GetForegroundWindow()) ++ { ++ This->base.acquired = 0; ++ return DIERR_INPUTLOST; ++ } ++ + EnterCriticalSection(&This->base.crit); + _dump_mouse_state(&This->m_state); + +-- +2.24.1 + diff --git a/patches/user32-rawinput-keyboard/0002-dinput8-Use-raw-input-interface-for-dinput8-keyboard.patch b/patches/user32-rawinput-keyboard/0002-dinput8-Use-raw-input-interface-for-dinput8-keyboard.patch new file mode 100644 index 00000000..fcc259d0 --- /dev/null +++ b/patches/user32-rawinput-keyboard/0002-dinput8-Use-raw-input-interface-for-dinput8-keyboard.patch @@ -0,0 +1,146 @@ +From 87087e7d92d5cbbaf8e63cdfadead60701d0b360 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Mon, 26 Aug 2019 15:32:07 +0200 +Subject: [PATCH 2/4] dinput8: Use raw input interface for dinput8 keyboard + device. + +--- + dlls/dinput/keyboard.c | 69 +++++++++++++++++++++++++++++++++---- + dlls/dinput8/tests/device.c | 7 ---- + 2 files changed, 62 insertions(+), 14 deletions(-) + +diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c +index 2c62d3eab09..fb0f273bdbe 100644 +--- a/dlls/dinput/keyboard.c ++++ b/dlls/dinput/keyboard.c +@@ -107,17 +107,65 @@ static int KeyboardCallback( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM + { + SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface); + int dik_code, ret = This->base.dwCoopLevel & DISCL_EXCLUSIVE; +- KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; + BYTE new_diks; ++ DWORD vkey_code, scan_code; ++ BOOL is_key_ext, is_key_up; + + if (wparam != WM_KEYDOWN && wparam != WM_KEYUP && +- wparam != WM_SYSKEYDOWN && wparam != WM_SYSKEYUP) ++ wparam != WM_SYSKEYDOWN && wparam != WM_SYSKEYUP && ++ wparam != RIM_INPUT && wparam != RIM_INPUTSINK) + return 0; + ++ if (wparam == RIM_INPUT || wparam == RIM_INPUTSINK) ++ { ++ RAWINPUTHEADER raw_header; ++ RAWINPUT raw_input; ++ UINT size; ++ ++ TRACE("(%p) wp %08lx, lp %08lx\n", iface, wparam, lparam); ++ ++ size = sizeof(raw_header); ++ if (GetRawInputData( (HRAWINPUT)lparam, RID_HEADER, &raw_header, &size, sizeof(RAWINPUTHEADER) ) != sizeof(raw_header)) ++ { ++ WARN( "Unable to read raw input data header\n" ); ++ return 0; ++ } ++ ++ if (raw_header.dwType != RIM_TYPEKEYBOARD) ++ return 0; ++ ++ if (raw_header.dwSize > sizeof(raw_input)) ++ { ++ WARN( "Unexpected size for keyboard raw input data\n" ); ++ return 0; ++ } ++ ++ size = raw_header.dwSize; ++ if (GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, &raw_input, &size, sizeof(RAWINPUTHEADER) ) != raw_header.dwSize ) ++ { ++ WARN( "Unable to read raw input data\n" ); ++ return 0; ++ } ++ ++ vkey_code = raw_input.data.keyboard.VKey; ++ scan_code = raw_input.data.keyboard.MakeCode; ++ is_key_ext = (raw_input.data.keyboard.Flags & RI_KEY_E0); ++ is_key_up = (raw_input.data.keyboard.Flags & RI_KEY_BREAK); ++ } ++ else ++ { ++ KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; ++ ++ vkey_code = hook->vkCode; ++ scan_code = hook->scanCode; ++ is_key_ext = (hook->flags & LLKHF_EXTENDED); ++ is_key_up = (hook->flags & LLKHF_UP); ++ } ++ + TRACE("(%p) wp %08lx, lp %08lx, vk %02x, scan %02x\n", +- iface, wparam, lparam, hook->vkCode, hook->scanCode); ++ iface, wparam, lparam, vkey_code, scan_code); + +- switch (hook->vkCode) ++ switch (vkey_code) + { + /* R-Shift is special - it is an extended key with separate scan code */ + case VK_RSHIFT : dik_code = DIK_RSHIFT; break; +@@ -125,10 +173,10 @@ static int KeyboardCallback( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM + case VK_NUMLOCK : dik_code = DIK_NUMLOCK; break; + case VK_SUBTRACT: dik_code = DIK_SUBTRACT; break; + default: +- dik_code = map_dik_code(hook->scanCode & 0xff, hook->vkCode, This->subtype); +- if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80; ++ dik_code = map_dik_code(scan_code & 0xff, vkey_code, This->subtype); ++ if (is_key_ext) dik_code |= 0x80; + } +- new_diks = hook->flags & LLKHF_UP ? 0 : 0x80; ++ new_diks = is_key_up ? 0 : 0x80; + + /* returns now if key event already known */ + if (new_diks == This->DInputKeyState[dik_code]) +@@ -295,6 +343,13 @@ static SysKeyboardImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput) + list_add_tail(&dinput->devices_list, &newDevice->base.entry); + LeaveCriticalSection(&dinput->crit); + ++ if (dinput->dwVersion >= 0x800) ++ { ++ newDevice->base.use_raw_input = TRUE; ++ newDevice->base.raw_device.usUsagePage = 1; /* HID generic device page */ ++ newDevice->base.raw_device.usUsage = 6; /* HID generic keyboard */ ++ } ++ + return newDevice; + + failed: +diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c +index 31220db220a..8a6d1997b67 100644 +--- a/dlls/dinput8/tests/device.c ++++ b/dlls/dinput8/tests/device.c +@@ -659,15 +659,10 @@ static void test_mouse_keyboard(void) + raw_devices_count = ARRAY_SIZE(raw_devices); + memset(raw_devices, 0, sizeof(raw_devices)); + hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); +- todo_wine + ok(hr == 1, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); +- todo_wine + ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); +- todo_wine + ok(raw_devices[0].usUsage == 6, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); +- todo_wine + ok(raw_devices[0].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); +- todo_wine + ok(raw_devices[0].hwndTarget != NULL, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); + hr = IDirectInputDevice8_Unacquire(di_keyboard); + ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); +@@ -746,9 +741,7 @@ static void test_mouse_keyboard(void) + ok(raw_devices[1].hwndTarget == hwnd, "Unexpected raw device target: %p\n", raw_devices[1].hwndTarget); + ok(raw_devices[2].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[1].usUsagePage); + ok(raw_devices[2].usUsage == 6, "Unexpected raw device usage: %x\n", raw_devices[1].usUsage); +- todo_wine + ok(raw_devices[2].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[1].dwFlags); +- todo_wine + ok(raw_devices[2].hwndTarget == di_hwnd, "Unexpected raw device target: %p\n", raw_devices[1].hwndTarget); + hr = IDirectInputDevice8_Unacquire(di_keyboard); + ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); +-- +2.24.1 + diff --git a/patches/user32-rawinput-keyboard/0003-user32-Add-support-for-RIDEV_INPUTSINK-flag-in-Regis.patch b/patches/user32-rawinput-keyboard/0003-user32-Add-support-for-RIDEV_INPUTSINK-flag-in-Regis.patch new file mode 100644 index 00000000..46c758b1 --- /dev/null +++ b/patches/user32-rawinput-keyboard/0003-user32-Add-support-for-RIDEV_INPUTSINK-flag-in-Regis.patch @@ -0,0 +1,95 @@ +From 31d4d9619c14a37522b99917deae40273f6e3654 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Sat, 7 Sep 2019 09:41:59 +0200 +Subject: [PATCH 3/4] user32: Add support for RIDEV_INPUTSINK flag in + RegisterRawInputDevices. + +This flag allows applications to receive rawinput messages while in +background. They have to specify a target hwnd in which queue to receive +them and the messages will carry a RIM_INPUTSINK wparam in this case. +--- + dlls/user32/rawinput.c | 9 ++++++++- + dlls/user32/tests/input.c | 2 -- + server/queue.c | 9 ++++++--- + 3 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c +index 72ae91cfcb5..5a238928b24 100644 +--- a/dlls/user32/rawinput.c ++++ b/dlls/user32/rawinput.c +@@ -304,6 +304,13 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U + + for (i = 0; i < device_count; ++i) + { ++ if ((devices[i].dwFlags & RIDEV_INPUTSINK) && ++ (devices[i].hwndTarget == NULL)) ++ { ++ SetLastError(ERROR_INVALID_PARAMETER); ++ return FALSE; ++ } ++ + if ((devices[i].dwFlags & RIDEV_REMOVE) && + (devices[i].hwndTarget != NULL)) + { +@@ -319,7 +326,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U + TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n", + i, devices[i].usUsagePage, devices[i].usUsage, + devices[i].dwFlags, devices[i].hwndTarget); +- if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY)) ++ if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY|RIDEV_INPUTSINK)) + FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i); + + d[i].usage_page = devices[i].usUsagePage; +diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c +index a1f983f1960..68d6731551a 100644 +--- a/dlls/user32/tests/input.c ++++ b/dlls/user32/tests/input.c +@@ -1812,9 +1812,7 @@ static void test_RegisterRawInputDevices(void) + + SetLastError(0xdeadbeef); + res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); +- todo_wine + ok(res == FALSE, "RegisterRawInputDevices failed\n"); +- todo_wine + ok(GetLastError() == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned %08x\n", GetLastError()); + + raw_devices[0].hwndTarget = hwnd; +diff --git a/server/queue.c b/server/queue.c +index 85aa896c7bd..145b9c110b1 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -1758,6 +1758,7 @@ static int queue_rawinput_message( struct process* process, void* user ) + struct thread *thread = NULL, *foreground = NULL; + struct message *msg; + struct hardware_msg_data *msg_data; ++ int wparam = RIM_INPUT; + + if (raw_msg->data.rawinput.type == RIM_TYPEMOUSE) + device = process->rawinput_mouse; +@@ -1777,10 +1778,12 @@ static int queue_rawinput_message( struct process* process, void* user ) + process != thread->process) + goto done; + +- /* FIXME: Implement RIDEV_INPUTSINK */ + if (!(foreground = get_window_thread( desktop->foreground_input->active )) || + thread->process != foreground->process) +- goto done; ++ { ++ if (!(device->flags & RIDEV_INPUTSINK)) goto done; ++ wparam = RIM_INPUTSINK; ++ } + + if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time, raw_msg->extra_len ))) + goto done; +@@ -1788,7 +1791,7 @@ static int queue_rawinput_message( struct process* process, void* user ) + + msg->win = device->target; + msg->msg = WM_INPUT; +- msg->wparam = RIM_INPUT; ++ msg->wparam = wparam; + msg->lparam = 0; + + memcpy( msg_data, &raw_msg->data, sizeof(*msg_data) ); +-- +2.24.1 + diff --git a/patches/user32-rawinput-keyboard/0004-winex11.drv-Listen-to-RawKey-events-in-the-desktop-t.patch b/patches/user32-rawinput-keyboard/0004-winex11.drv-Listen-to-RawKey-events-in-the-desktop-t.patch new file mode 100644 index 00000000..da4133ad --- /dev/null +++ b/patches/user32-rawinput-keyboard/0004-winex11.drv-Listen-to-RawKey-events-in-the-desktop-t.patch @@ -0,0 +1,119 @@ +From 18e2112beb69c8499cdd90b133348ec52502dc6d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 21 Aug 2019 16:37:57 +0200 +Subject: [PATCH] winex11.drv: Listen to RawKey* events in the desktop thread. + +This adds keyboard input support while Wine windows are in background, +so the events can be translated to raw input messages as on Windows, +which are required to keep dinput8 keyboard state up-to-date when +Alt+Tab is used to switch to a non-Wine window. +--- + dlls/winex11.drv/keyboard.c | 40 ++++++++++++++++++++++++++++++++++++- + dlls/winex11.drv/mouse.c | 6 ++++++ + dlls/winex11.drv/x11drv.h | 1 + + 3 files changed, 46 insertions(+), 1 deletion(-) + +diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c +index 37c96c926f4..4d113d8c184 100644 +--- a/dlls/winex11.drv/keyboard.c ++++ b/dlls/winex11.drv/keyboard.c +@@ -33,6 +33,9 @@ + #ifdef HAVE_X11_XKBLIB_H + #include + #endif ++#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H ++#include ++#endif + + #include + #include +@@ -1148,7 +1151,7 @@ static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD f + input.u.ki.time = time; + input.u.ki.dwExtraInfo = 0; + +- __wine_send_input( hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); ++ __wine_send_input( hwnd, &input, SEND_HWMSG_WINDOW ); + } + + +@@ -1417,6 +1420,41 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) + return TRUE; + } + ++#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H ++/*********************************************************************** ++ * X11DRV_KeyEvent ++ * ++ * Handle a raw XInput2 key event for background windows ++ */ ++BOOL X11DRV_RawKeyEvent( XGenericEventCookie *cookie ) ++{ ++ XIRawEvent *event = cookie->data; ++ DWORD flags; ++ WORD vkey, scan; ++ INPUT input; ++ ++ vkey = keyc2vkey[event->detail]; ++ scan = keyc2scan[event->detail]; ++ ++ flags = 0; ++ if ( event->evtype == XI_RawKeyRelease ) flags |= KEYEVENTF_KEYUP; ++ if ( vkey & 0x100 ) flags |= KEYEVENTF_EXTENDEDKEY; ++ ++ TRACE_(key)( "vkey=%04x scan=%04x flags=%04x\n", vkey, scan, flags ); ++ ++ input.type = INPUT_KEYBOARD; ++ input.u.ki.wVk = vkey & 0xff; ++ input.u.ki.wScan = scan & 0xff; ++ input.u.ki.dwFlags = flags; ++ input.u.ki.time = EVENT_x11_time_to_win32_time(event->time); ++ input.u.ki.dwExtraInfo = 0; ++ ++ __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT ); ++ ++ return TRUE; ++} ++#endif ++ + /********************************************************************** + * X11DRV_KEYBOARD_DetectLayout + * +diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c +index bc23b9cbba1..2e9b39fcff7 100644 +--- a/dlls/winex11.drv/mouse.c ++++ b/dlls/winex11.drv/mouse.c +@@ -406,6 +406,8 @@ void X11DRV_XInput2_Enable(void) + { + XISetMask( mask_bits, XI_RawButtonPress ); + XISetMask( mask_bits, XI_RawButtonRelease ); ++ XISetMask( mask_bits, XI_RawKeyPress ); ++ XISetMask( mask_bits, XI_RawKeyRelease ); + data->xi2_rawinput_only = TRUE; + } + else +@@ -2038,6 +2040,10 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev ) + case XI_RawButtonRelease: + ret = X11DRV_RawButtonEvent( event ); + break; ++ case XI_RawKeyPress: ++ case XI_RawKeyRelease: ++ ret = X11DRV_RawKeyEvent( event ); ++ break; + + default: + TRACE( "Unhandled event %#x\n", event->evtype ); +diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h +index c843cd74ace..f89538a1755 100644 +--- a/dlls/winex11.drv/x11drv.h ++++ b/dlls/winex11.drv/x11drv.h +@@ -518,6 +518,7 @@ extern BOOL X11DRV_ButtonRelease( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN; + extern BOOL X11DRV_MotionNotify( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN; + extern BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN; + extern BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN; ++extern BOOL X11DRV_RawKeyEvent( XGenericEventCookie *cookie ) DECLSPEC_HIDDEN; + extern BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN; + extern BOOL X11DRV_DestroyNotify( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN; + extern BOOL X11DRV_SelectionRequest( HWND hWnd, XEvent *event ) DECLSPEC_HIDDEN; +-- +2.24.0 + diff --git a/patches/user32-rawinput-keyboard/definition b/patches/user32-rawinput-keyboard/definition new file mode 100644 index 00000000..bb0e4a0f --- /dev/null +++ b/patches/user32-rawinput-keyboard/definition @@ -0,0 +1 @@ +Depends: user32-rawinput-hid diff --git a/patches/user32-rawinput-mouse-experimental/0001-winex11.drv-Add-support-for-absolute-RawMotion-event.patch b/patches/user32-rawinput-mouse-experimental/0001-winex11.drv-Add-support-for-absolute-RawMotion-event.patch new file mode 100644 index 00000000..2f8583d5 --- /dev/null +++ b/patches/user32-rawinput-mouse-experimental/0001-winex11.drv-Add-support-for-absolute-RawMotion-event.patch @@ -0,0 +1,277 @@ +From c227552d313a51f625b741c330ce4509dff99cb5 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Tue, 25 Jun 2019 22:37:34 -0400 +Subject: [PATCH 1/4] winex11.drv: Add support for absolute RawMotion events. + +When running Xwayland, or using pointing devices, the valuators may +provide absolute values only. In which case, we should translate the +events to the corresponding absolute rawinput messages. + +The server side was trying to convert all rawinput messages to relative +positions, but it may not be correct as the desktop cursor position may +not be initialized yet. Keeping the values absolute if we received them +this way seems more reliable. + +Note that we cannot really trust valuator names, as it is possible to +configure a pointing device to work in relative mode - wacom tablets for +example - while their axis valuators keep their "Abs X/Y" name. We can +however use the valuator mode to distinguish between relative movements +and absolute position events. +--- + dlls/user32/message.c | 7 ++- + dlls/winex11.drv/mouse.c | 96 +++++++++++++++++++++------------- + dlls/winex11.drv/x11drv.h | 18 +++---- + dlls/winex11.drv/x11drv_main.c | 2 + + server/queue.c | 4 +- + 5 files changed, 79 insertions(+), 48 deletions(-) + +diff --git a/dlls/user32/message.c b/dlls/user32/message.c +index cc25d2f6c2f..26c3aa91421 100644 +--- a/dlls/user32/message.c ++++ b/dlls/user32/message.c +@@ -2311,7 +2311,12 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data * + rawinput->header.hDevice = WINE_MOUSE_HANDLE; + rawinput->header.wParam = 0; + +- rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE; ++ if (msg_data->flags & MOUSEEVENTF_ABSOLUTE) ++ rawinput->data.mouse.usFlags = MOUSE_MOVE_ABSOLUTE; ++ else ++ rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE; ++ if (msg_data->flags & MOUSEEVENTF_VIRTUALDESK) ++ rawinput->data.mouse.usFlags |= MOUSE_VIRTUAL_DESKTOP; + rawinput->data.mouse.u.s.usButtonFlags = 0; + rawinput->data.mouse.u.s.usButtonData = 0; + for (i = 1; i < ARRAY_SIZE(button_flags); ++i) +diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c +index d331ed5aef8..3474a176003 100644 +--- a/dlls/winex11.drv/mouse.c ++++ b/dlls/winex11.drv/mouse.c +@@ -333,32 +333,40 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator + struct x11drv_thread_data *thread_data = x11drv_thread_data(); + int i; + +- thread_data->x_rel_valuator.number = -1; +- thread_data->y_rel_valuator.number = -1; ++ thread_data->x_pos_valuator.number = -1; ++ thread_data->y_pos_valuator.number = -1; + + for (i = 0; i < n_valuators; i++) + { + XIValuatorClassInfo *class = (XIValuatorClassInfo *)valuators[i]; +- struct x11drv_valuator_data *valuator_data = NULL; + +- if (valuators[i]->type != XIValuatorClass) continue; +- if (class->label == x11drv_atom( Rel_X ) || +- (!class->label && class->number == 0 && class->mode == XIModeRelative)) +- { +- valuator_data = &thread_data->x_rel_valuator; +- } ++ if (valuators[i]->type != XIValuatorClass) ++ continue; ++ else if (class->label == x11drv_atom( Rel_X ) || ++ class->label == x11drv_atom( Abs_X ) || ++ (!class->label && class->number == 0)) ++ thread_data->x_pos_valuator = *class; + else if (class->label == x11drv_atom( Rel_Y ) || +- (!class->label && class->number == 1 && class->mode == XIModeRelative)) +- { +- valuator_data = &thread_data->y_rel_valuator; +- } ++ class->label == x11drv_atom( Abs_Y ) || ++ (!class->label && class->number == 1)) ++ thread_data->y_pos_valuator = *class; ++ } + +- if (valuator_data) { +- valuator_data->number = class->number; +- valuator_data->min = class->min; +- valuator_data->max = class->max; +- } ++ if (thread_data->x_pos_valuator.number < 0 || thread_data->y_pos_valuator.number < 0) ++ { ++ WARN("Only one X/Y axis found, ignoring RawMotion events\n"); ++ } ++ else if (thread_data->x_pos_valuator.mode != thread_data->y_pos_valuator.mode) ++ { ++ WARN("Relative/Absolute mismatch between X/Y axis, ignoring RawMotion events\n"); ++ thread_data->y_pos_valuator.number = -1; ++ thread_data->y_pos_valuator.number = -1; + } ++ ++ if (thread_data->x_pos_valuator.min >= thread_data->x_pos_valuator.max) ++ thread_data->x_pos_valuator.min = thread_data->x_pos_valuator.max = 0; ++ if (thread_data->y_pos_valuator.min >= thread_data->y_pos_valuator.max) ++ thread_data->y_pos_valuator.min = thread_data->y_pos_valuator.max = 0; + } + #endif + +@@ -443,8 +451,8 @@ void X11DRV_XInput2_Disable(void) + mask.deviceid = XIAllMasterDevices; + + pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); +- data->x_rel_valuator.number = -1; +- data->y_rel_valuator.number = -1; ++ data->x_pos_valuator.number = -1; ++ data->y_pos_valuator.number = -1; + data->xi2_core_pointer = 0; + #endif + } +@@ -1895,16 +1903,22 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + INPUT input; + int i; + double dx = 0, dy = 0, val; ++ double x_scale = 1, y_scale = 1; + struct x11drv_thread_data *thread_data = x11drv_thread_data(); +- struct x11drv_valuator_data *x_rel, *y_rel; ++ XIValuatorClassInfo *x_pos, *y_pos; + +- if (thread_data->x_rel_valuator.number < 0 || thread_data->y_rel_valuator.number < 0) return FALSE; ++ if (thread_data->x_pos_valuator.number < 0 || thread_data->y_pos_valuator.number < 0) return FALSE; ++ if (thread_data->x_pos_valuator.mode != thread_data->y_pos_valuator.mode) ++ { ++ FIXME("Unsupported relative/absolute X/Y axis mismatch\n."); ++ return FALSE; ++ } + if (!event->valuators.mask_len) return FALSE; + if (thread_data->xi2_state != xi_enabled) return FALSE; + if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; + +- x_rel = &thread_data->x_rel_valuator; +- y_rel = &thread_data->y_rel_valuator; ++ x_pos = &thread_data->x_pos_valuator; ++ y_pos = &thread_data->y_pos_valuator; + + input.type = INPUT_MOUSE; + input.u.mi.mouseData = 0; +@@ -1915,24 +1929,34 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + input.u.mi.dy = 0; + + virtual_rect = get_virtual_screen_rect(); +- +- for (i = 0; i <= max ( x_rel->number, y_rel->number ); i++) ++ if (x_pos->min < x_pos->max) ++ x_scale = (x_pos->mode == XIModeAbsolute ? 65535 : (virtual_rect.right - virtual_rect.left)) / ++ (x_pos->max - x_pos->min); ++ if (y_pos->min < y_pos->max) ++ y_scale = (y_pos->mode == XIModeAbsolute ? 65535 : (virtual_rect.bottom - virtual_rect.top)) / ++ (y_pos->max - y_pos->min); ++ ++ for (i = 0; i <= max( x_pos->number, y_pos->number ); i++) + { + if (!XIMaskIsSet( event->valuators.mask, i )) continue; + val = *values++; +- if (i == x_rel->number) ++ if (i == x_pos->number) + { +- input.u.mi.dx = dx = val; +- if (x_rel->min < x_rel->max) +- input.u.mi.dx = val * (virtual_rect.right - virtual_rect.left) +- / (x_rel->max - x_rel->min); ++ dx = val; ++ input.u.mi.dwFlags |= (x_pos->mode == XIModeAbsolute ? MOUSEEVENTF_ABSOLUTE : 0); ++ if (x_pos->mode == XIModeAbsolute) ++ input.u.mi.dx = (dx - x_pos->min) * x_scale; ++ else ++ input.u.mi.dx = dx * x_scale; + } +- if (i == y_rel->number) ++ if (i == y_pos->number) + { +- input.u.mi.dy = dy = val; +- if (y_rel->min < y_rel->max) +- input.u.mi.dy = val * (virtual_rect.bottom - virtual_rect.top) +- / (y_rel->max - y_rel->min); ++ dy = val; ++ input.u.mi.dwFlags |= (y_pos->mode == XIModeAbsolute ? MOUSEEVENTF_ABSOLUTE : 0); ++ if (y_pos->mode == XIModeAbsolute) ++ input.u.mi.dy = (dy - y_pos->min) * y_scale; ++ else ++ input.u.mi.dy = dy * y_scale; + } + } + +diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h +index 4a7cab67ada..c4218699034 100644 +--- a/dlls/winex11.drv/x11drv.h ++++ b/dlls/winex11.drv/x11drv.h +@@ -32,6 +32,9 @@ + #include + #include + #include ++#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H ++#include ++#endif + + #define BOOL X_BOOL + #define BYTE X_BYTE +@@ -318,13 +321,6 @@ struct x11drv_escape_flush_gl_drawable + * X11 USER driver + */ + +-struct x11drv_valuator_data +-{ +- double min; +- double max; +- int number; +-}; +- + struct x11drv_thread_data + { + Display *display; +@@ -341,11 +337,13 @@ struct x11drv_thread_data + HWND clip_hwnd; /* message window stored in desktop while clipping is active */ + DWORD clip_reset; /* time when clipping was last reset */ + HKL kbd_layout; /* active keyboard layout */ ++#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ +- struct x11drv_valuator_data x_rel_valuator; +- struct x11drv_valuator_data y_rel_valuator; ++ XIValuatorClassInfo x_pos_valuator; ++ XIValuatorClassInfo y_pos_valuator; + int xi2_core_pointer; /* XInput2 core pointer id */ + int xi2_rawinput_only; ++#endif + }; + + extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; +@@ -431,6 +429,8 @@ enum x11drv_atoms + XATOM_RAW_CAP_HEIGHT, + XATOM_Rel_X, + XATOM_Rel_Y, ++ XATOM_Abs_X, ++ XATOM_Abs_Y, + XATOM_WM_PROTOCOLS, + XATOM_WM_DELETE_WINDOW, + XATOM_WM_STATE, +diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c +index f33a79d98bf..3e8dd82654a 100644 +--- a/dlls/winex11.drv/x11drv_main.c ++++ b/dlls/winex11.drv/x11drv_main.c +@@ -144,6 +144,8 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = + "RAW_CAP_HEIGHT", + "Rel X", + "Rel Y", ++ "Abs X", ++ "Abs Y", + "WM_PROTOCOLS", + "WM_DELETE_WINDOW", + "WM_STATE", +diff --git a/server/queue.c b/server/queue.c +index f5dc06100d1..b369f0cdb78 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -1858,8 +1858,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons + msg_data->info = input->mouse.info; + msg_data->flags = flags; + msg_data->rawinput.type = RIM_TYPEMOUSE; +- msg_data->rawinput.mouse.x = x - desktop->cursor.x; +- msg_data->rawinput.mouse.y = y - desktop->cursor.y; ++ msg_data->rawinput.mouse.x = input->mouse.x; ++ msg_data->rawinput.mouse.y = input->mouse.y; + msg_data->rawinput.mouse.data = input->mouse.data; + + if (req_flags == SEND_HWMSG_RAWINPUT) +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse-experimental/0002-winex11.drv-Send-relative-RawMotion-events-unprocess.patch b/patches/user32-rawinput-mouse-experimental/0002-winex11.drv-Send-relative-RawMotion-events-unprocess.patch new file mode 100644 index 00000000..5a7f3667 --- /dev/null +++ b/patches/user32-rawinput-mouse-experimental/0002-winex11.drv-Send-relative-RawMotion-events-unprocess.patch @@ -0,0 +1,86 @@ +From 108f1467e2d2712b5fb8956e69d481a033cbcbfe Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 10 Sep 2019 12:24:22 +0200 +Subject: [PATCH 2/4] winex11.drv: Send relative RawMotion events unprocessed. + +This makes relative raw input independent from cursor speed, as it is +the case on Windows. Absolute raw input is already translated to +virtual desktop space, and cursor speed is meaningless in this case. + +This does not support mixed relative/absolute X/Y axis. +--- + dlls/winex11.drv/mouse.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c +index 3474a176003..a2310297ff9 100644 +--- a/dlls/winex11.drv/mouse.c ++++ b/dlls/winex11.drv/mouse.c +@@ -1899,20 +1899,17 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + { + XIRawEvent *event = xev->data; + const double *values = event->valuators.values; ++ const double *raw_values = event->raw_values; + RECT virtual_rect; + INPUT input; + int i; + double dx = 0, dy = 0, val; ++ double raw_dx = 0, raw_dy = 0, raw_val; + double x_scale = 1, y_scale = 1; + struct x11drv_thread_data *thread_data = x11drv_thread_data(); + XIValuatorClassInfo *x_pos, *y_pos; + + if (thread_data->x_pos_valuator.number < 0 || thread_data->y_pos_valuator.number < 0) return FALSE; +- if (thread_data->x_pos_valuator.mode != thread_data->y_pos_valuator.mode) +- { +- FIXME("Unsupported relative/absolute X/Y axis mismatch\n."); +- return FALSE; +- } + if (!event->valuators.mask_len) return FALSE; + if (thread_data->xi2_state != xi_enabled) return FALSE; + if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; +@@ -1940,9 +1937,11 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + { + if (!XIMaskIsSet( event->valuators.mask, i )) continue; + val = *values++; ++ raw_val = *raw_values++; + if (i == x_pos->number) + { + dx = val; ++ raw_dx = raw_val; + input.u.mi.dwFlags |= (x_pos->mode == XIModeAbsolute ? MOUSEEVENTF_ABSOLUTE : 0); + if (x_pos->mode == XIModeAbsolute) + input.u.mi.dx = (dx - x_pos->min) * x_scale; +@@ -1952,6 +1951,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + if (i == y_pos->number) + { + dy = val; ++ raw_dy = raw_val; + input.u.mi.dwFlags |= (y_pos->mode == XIModeAbsolute ? MOUSEEVENTF_ABSOLUTE : 0); + if (y_pos->mode == XIModeAbsolute) + input.u.mi.dy = (dy - y_pos->min) * y_scale; +@@ -1966,13 +1966,20 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + return FALSE; + } + +- if (!thread_data->xi2_rawinput_only) ++ if (x_pos->mode == XIModeAbsolute) ++ { ++ TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); ++ __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT ); ++ } ++ else if (!thread_data->xi2_rawinput_only) + { + TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); + __wine_send_input( 0, &input, SEND_HWMSG_WINDOW ); + } + else + { ++ input.u.mi.dx = raw_dx; ++ input.u.mi.dy = raw_dy; + TRACE( "raw pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); + __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT ); + } +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse-experimental/0003-winex11.drv-Implement-relative-wheel-input-from-RawM.patch b/patches/user32-rawinput-mouse-experimental/0003-winex11.drv-Implement-relative-wheel-input-from-RawM.patch new file mode 100644 index 00000000..b3644c06 --- /dev/null +++ b/patches/user32-rawinput-mouse-experimental/0003-winex11.drv-Implement-relative-wheel-input-from-RawM.patch @@ -0,0 +1,166 @@ +From f4b6ceb3c008b73dfdb89acc601da3be83c47f86 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Fri, 26 Jul 2019 17:37:19 -0400 +Subject: [PATCH 3/4] winex11.drv: Implement relative wheel input from + RawMotion events. + +--- + dlls/winex11.drv/mouse.c | 33 +++++++++++++++++++++++++++------ + dlls/winex11.drv/x11drv.h | 3 +++ + dlls/winex11.drv/x11drv_main.c | 1 + + 3 files changed, 31 insertions(+), 6 deletions(-) + +diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c +index a2310297ff9..49734ba195b 100644 +--- a/dlls/winex11.drv/mouse.c ++++ b/dlls/winex11.drv/mouse.c +@@ -335,11 +335,17 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator + + thread_data->x_pos_valuator.number = -1; + thread_data->y_pos_valuator.number = -1; ++ thread_data->wheel_valuator.number = -1; ++ thread_data->wheel_scale = 1; + + for (i = 0; i < n_valuators; i++) + { + XIValuatorClassInfo *class = (XIValuatorClassInfo *)valuators[i]; ++ XIScrollClassInfo *scroll_class = (XIScrollClassInfo *)valuators[i]; + ++ if (valuators[i]->type == XIScrollClass && ++ scroll_class->scroll_type == XIScrollTypeVertical) ++ thread_data->wheel_scale = WHEEL_DELTA / scroll_class->increment; + if (valuators[i]->type != XIValuatorClass) + continue; + else if (class->label == x11drv_atom( Rel_X ) || +@@ -350,6 +356,9 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator + class->label == x11drv_atom( Abs_Y ) || + (!class->label && class->number == 1)) + thread_data->y_pos_valuator = *class; ++ else if (class->label == x11drv_atom( Rel_Vert_Scroll ) || ++ (!class->label && class->number == 3 && class->mode == XIModeRelative)) ++ thread_data->wheel_valuator = *class; + } + + if (thread_data->x_pos_valuator.number < 0 || thread_data->y_pos_valuator.number < 0) +@@ -453,6 +462,8 @@ void X11DRV_XInput2_Disable(void) + pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); + data->x_pos_valuator.number = -1; + data->y_pos_valuator.number = -1; ++ data->wheel_valuator.number = -1; ++ data->wheel_scale = 1; + data->xi2_core_pointer = 0; + #endif + } +@@ -1903,11 +1914,11 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + RECT virtual_rect; + INPUT input; + int i; +- double dx = 0, dy = 0, val; ++ double dx = 0, dy = 0, dw = 0, val; + double raw_dx = 0, raw_dy = 0, raw_val; + double x_scale = 1, y_scale = 1; + struct x11drv_thread_data *thread_data = x11drv_thread_data(); +- XIValuatorClassInfo *x_pos, *y_pos; ++ XIValuatorClassInfo *x_pos, *y_pos, *wheel; + + if (thread_data->x_pos_valuator.number < 0 || thread_data->y_pos_valuator.number < 0) return FALSE; + if (!event->valuators.mask_len) return FALSE; +@@ -1916,6 +1927,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + + x_pos = &thread_data->x_pos_valuator; + y_pos = &thread_data->y_pos_valuator; ++ wheel = &thread_data->wheel_valuator; + + input.type = INPUT_MOUSE; + input.u.mi.mouseData = 0; +@@ -1933,7 +1945,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + y_scale = (y_pos->mode == XIModeAbsolute ? 65535 : (virtual_rect.bottom - virtual_rect.top)) / + (y_pos->max - y_pos->min); + +- for (i = 0; i <= max( x_pos->number, y_pos->number ); i++) ++ for (i = 0; i <= max( max( x_pos->number, y_pos->number ), wheel->number ); i++) + { + if (!XIMaskIsSet( event->valuators.mask, i )) continue; + val = *values++; +@@ -1958,6 +1970,12 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + else + input.u.mi.dy = dy * y_scale; + } ++ if (i == wheel->number) ++ { ++ dw = val; ++ input.u.mi.dwFlags |= MOUSEEVENTF_WHEEL; ++ input.u.mi.mouseData = dw * thread_data->wheel_scale; ++ } + } + + if (broken_rawevents && is_old_motion_event( xev->serial )) +@@ -1968,19 +1986,19 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + + if (x_pos->mode == XIModeAbsolute) + { +- TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); ++ TRACE( "pos %d,%d w:%d (event %f,%f,%f)\n", input.u.mi.dx, input.u.mi.dy, input.u.mi.mouseData, dx, dy, dw ); + __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT ); + } + else if (!thread_data->xi2_rawinput_only) + { +- TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); ++ TRACE( "pos %d,%d w:%d (event %f,%f,%f)\n", input.u.mi.dx, input.u.mi.dy, input.u.mi.mouseData, dx, dy, dw ); + __wine_send_input( 0, &input, SEND_HWMSG_WINDOW ); + } + else + { + input.u.mi.dx = raw_dx; + input.u.mi.dy = raw_dy; +- TRACE( "raw pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); ++ TRACE( "raw pos %d,%d w:%d (event %f,%f,%f)\n", input.u.mi.dx, input.u.mi.dy, input.u.mi.mouseData, raw_dx, raw_dy, dw ); + __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT ); + } + return TRUE; +@@ -2009,6 +2027,9 @@ static BOOL X11DRV_RawButtonEvent( XGenericEventCookie *cookie ) + if (thread_data->xi2_state != xi_enabled) return FALSE; + if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; + ++ /* mouse wheel is already handled by RawMotion events */ ++ if (button == 3 || button == 4) return TRUE; ++ + TRACE( "raw button %u (raw: %u) %s\n", button, event->detail, event->evtype == XI_RawButtonRelease ? "up" : "down" ); + + input.type = INPUT_MOUSE; +diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h +index c4218699034..47c19a83175 100644 +--- a/dlls/winex11.drv/x11drv.h ++++ b/dlls/winex11.drv/x11drv.h +@@ -341,6 +341,8 @@ struct x11drv_thread_data + enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ + XIValuatorClassInfo x_pos_valuator; + XIValuatorClassInfo y_pos_valuator; ++ XIValuatorClassInfo wheel_valuator; ++ double wheel_scale; + int xi2_core_pointer; /* XInput2 core pointer id */ + int xi2_rawinput_only; + #endif +@@ -429,6 +431,7 @@ enum x11drv_atoms + XATOM_RAW_CAP_HEIGHT, + XATOM_Rel_X, + XATOM_Rel_Y, ++ XATOM_Rel_Vert_Scroll, + XATOM_Abs_X, + XATOM_Abs_Y, + XATOM_WM_PROTOCOLS, +diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c +index 3e8dd82654a..3ed8058fc50 100644 +--- a/dlls/winex11.drv/x11drv_main.c ++++ b/dlls/winex11.drv/x11drv_main.c +@@ -144,6 +144,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = + "RAW_CAP_HEIGHT", + "Rel X", + "Rel Y", ++ "Rel Vert Scroll", + "Abs X", + "Abs Y", + "WM_PROTOCOLS", +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse-experimental/0004-winex11.drv-Accumulate-mouse-movement-to-avoid-round.patch b/patches/user32-rawinput-mouse-experimental/0004-winex11.drv-Accumulate-mouse-movement-to-avoid-round.patch new file mode 100644 index 00000000..4c2b0c80 --- /dev/null +++ b/patches/user32-rawinput-mouse-experimental/0004-winex11.drv-Accumulate-mouse-movement-to-avoid-round.patch @@ -0,0 +1,121 @@ +From cf8668ffad406a26dde59993b81619c966446975 Mon Sep 17 00:00:00 2001 +From: Jordan Galby +Date: Tue, 16 Jul 2019 00:34:38 -0400 +Subject: [PATCH 4/4] winex11.drv: Accumulate mouse movement to avoid rounding + losses. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=42631 +From: Jordan Galby +--- + dlls/winex11.drv/mouse.c | 44 +++++++++++++++++++++++++++++++++------- + 1 file changed, 37 insertions(+), 7 deletions(-) + +diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c +index 49734ba195b..b5cba492d7e 100644 +--- a/dlls/winex11.drv/mouse.c ++++ b/dlls/winex11.drv/mouse.c +@@ -376,6 +376,10 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator + thread_data->x_pos_valuator.min = thread_data->x_pos_valuator.max = 0; + if (thread_data->y_pos_valuator.min >= thread_data->y_pos_valuator.max) + thread_data->y_pos_valuator.min = thread_data->y_pos_valuator.max = 0; ++ ++ thread_data->x_pos_valuator.value = 0; ++ thread_data->y_pos_valuator.value = 0; ++ thread_data->wheel_valuator.value = 0; + } + #endif + +@@ -1917,6 +1921,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + double dx = 0, dy = 0, dw = 0, val; + double raw_dx = 0, raw_dy = 0, raw_val; + double x_scale = 1, y_scale = 1; ++ double x_accum = 0, y_accum = 0, w_accum = 0; + struct x11drv_thread_data *thread_data = x11drv_thread_data(); + XIValuatorClassInfo *x_pos, *y_pos, *wheel; + +@@ -1929,6 +1934,10 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + y_pos = &thread_data->y_pos_valuator; + wheel = &thread_data->wheel_valuator; + ++ x_accum = x_pos->value; ++ y_accum = y_pos->value; ++ w_accum = wheel->value; ++ + input.type = INPUT_MOUSE; + input.u.mi.mouseData = 0; + input.u.mi.dwFlags = MOUSEEVENTF_MOVE; +@@ -1956,9 +1965,9 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + raw_dx = raw_val; + input.u.mi.dwFlags |= (x_pos->mode == XIModeAbsolute ? MOUSEEVENTF_ABSOLUTE : 0); + if (x_pos->mode == XIModeAbsolute) +- input.u.mi.dx = (dx - x_pos->min) * x_scale; ++ x_accum = (dx - x_pos->min) * x_scale; + else +- input.u.mi.dx = dx * x_scale; ++ x_accum += dx * x_scale; + } + if (i == y_pos->number) + { +@@ -1966,24 +1975,38 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + raw_dy = raw_val; + input.u.mi.dwFlags |= (y_pos->mode == XIModeAbsolute ? MOUSEEVENTF_ABSOLUTE : 0); + if (y_pos->mode == XIModeAbsolute) +- input.u.mi.dy = (dy - y_pos->min) * y_scale; ++ y_accum = (dy - y_pos->min) * y_scale; + else +- input.u.mi.dy = dy * y_scale; ++ y_accum += dy * y_scale; + } + if (i == wheel->number) + { + dw = val; + input.u.mi.dwFlags |= MOUSEEVENTF_WHEEL; +- input.u.mi.mouseData = dw * thread_data->wheel_scale; ++ w_accum += dw * thread_data->wheel_scale; + } + } + ++ /* Accumulate the fractional parts so they aren't lost after casting ++ * successive motion values to integral fields. ++ * ++ * Note: It looks like raw_dx, raw_dy and raw_dw are already ++ * integral values but that may be wrong. ++ */ ++ input.u.mi.dx = (LONG)x_accum; ++ input.u.mi.dy = (LONG)y_accum; ++ input.u.mi.mouseData = (DWORD)w_accum; ++ + if (broken_rawevents && is_old_motion_event( xev->serial )) + { + TRACE( "pos %d,%d old serial %lu, ignoring\n", input.u.mi.dx, input.u.mi.dy, xev->serial ); + return FALSE; + } + ++ x_pos->value = x_accum - input.u.mi.dx; ++ y_pos->value = y_accum - input.u.mi.dy; ++ wheel->value = w_accum - input.u.mi.mouseData; ++ + if (x_pos->mode == XIModeAbsolute) + { + TRACE( "pos %d,%d w:%d (event %f,%f,%f)\n", input.u.mi.dx, input.u.mi.dy, input.u.mi.mouseData, dx, dy, dw ); +@@ -1991,8 +2014,15 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + } + else if (!thread_data->xi2_rawinput_only) + { +- TRACE( "pos %d,%d w:%d (event %f,%f,%f)\n", input.u.mi.dx, input.u.mi.dy, input.u.mi.mouseData, dx, dy, dw ); +- __wine_send_input( 0, &input, SEND_HWMSG_WINDOW ); ++ if ((dy || dy || dw) && !(input.u.mi.dx || input.u.mi.dy || input.u.mi.mouseData)) ++ { ++ TRACE( "accumulating raw motion (event %f,%f,%f accum %f,%f,%f)\n", dx, dy, dw, x_pos->value, y_pos->value, wheel->value ); ++ } ++ else ++ { ++ TRACE( "pos %d,%d w:%d (event %f,%f,%f)\n", input.u.mi.dx, input.u.mi.dy, input.u.mi.mouseData, dx, dy, dw ); ++ __wine_send_input( 0, &input, SEND_HWMSG_WINDOW ); ++ } + } + else + { +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse-experimental/definition b/patches/user32-rawinput-mouse-experimental/definition new file mode 100644 index 00000000..c5756c1f --- /dev/null +++ b/patches/user32-rawinput-mouse-experimental/definition @@ -0,0 +1,2 @@ +Fixes: [45882] - Raw Input should use untransformed mouse values (affects Overwatch, several Source games). +Depends: user32-rawinput-nolegacy diff --git a/patches/user32-rawinput-mouse/0001-user32-tests-Add-rawinput-test-for-ClipCursor-intera.patch b/patches/user32-rawinput-mouse/0001-user32-tests-Add-rawinput-test-for-ClipCursor-intera.patch new file mode 100644 index 00000000..cf1728f3 --- /dev/null +++ b/patches/user32-rawinput-mouse/0001-user32-tests-Add-rawinput-test-for-ClipCursor-intera.patch @@ -0,0 +1,262 @@ +From fe1ae8a2e1ee05143a9a0b7248420edada9bc09d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 14 Nov 2019 16:41:43 +0100 +Subject: [PATCH 01/12] user32/tests: Add rawinput test for ClipCursor + interactions. + +This shows unexpected rawinput messages triggered from cursor clipping. + +The sleeps are required to let native cursor clipping time to activate. +We also repeat the clipping multiple times to be increase the chances +that the counts will be wrong as it doesn't always trigger. +--- + dlls/user32/tests/input.c | 226 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 226 insertions(+) + +diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c +index 478c269017a..bf9d19906a8 100644 +--- a/dlls/user32/tests/input.c ++++ b/dlls/user32/tests/input.c +@@ -1826,6 +1826,231 @@ static void test_RegisterRawInputDevices(void) + DestroyWindow(hwnd); + } + ++static int rawinput_received; ++static int rawinput_received_foreground; ++static int rawinput_motion_x; ++static int rawinput_motion_y; ++static HANDLE rawinput_wndproc_done; ++ ++static LRESULT CALLBACK rawinput_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) ++{ ++ UINT ret, raw_size; ++ RAWINPUT raw; ++ ++ if (msg == WM_INPUT) ++ { ++ rawinput_received++; ++ ++ ok(wparam == RIM_INPUT || wparam == RIM_INPUTSINK, "Unexpected wparam: %lu\n", wparam); ++ if (wparam == RIM_INPUT) ++ rawinput_received_foreground++; ++ ++ ret = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &raw_size, sizeof(RAWINPUTHEADER)); ++ ok(ret == 0, "GetRawInputData failed\n"); ++ ok(raw_size <= sizeof(raw), "Unexpected rawinput data size: %u", raw_size); ++ ++ if (raw_size <= sizeof(raw)) ++ { ++ ret = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &raw, &raw_size, sizeof(RAWINPUTHEADER)); ++ ok(ret > 0 && ret != (UINT)-1, "GetRawInputData failed\n"); ++ ok(raw.header.dwType == RIM_TYPEMOUSE, "Unexpected rawinput type: %u\n", raw.header.dwType); ++ ++ if (raw.header.dwType == RIM_TYPEMOUSE) ++ { ++ ok(!(raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE), "Unexpected absolute rawinput motion\n"); ++ ok(!(raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP), "Unexpected virtual desktop rawinput motion\n"); ++ rawinput_motion_x += raw.data.mouse.lLastX; ++ rawinput_motion_y += raw.data.mouse.lLastY; ++ } ++ } ++ } ++ ++ if (msg == WM_USER) ++ SetEvent(rawinput_wndproc_done); ++ ++ return DefWindowProcA(hwnd, msg, wparam, lparam); ++} ++ ++struct rawinput_mouse_thread_params ++{ ++ int step; ++ HWND window; ++ HANDLE ready; ++ HANDLE start; ++}; ++ ++static DWORD WINAPI rawinput_mouse_thread(void *arg) ++{ ++ struct rawinput_mouse_thread_params *params = arg; ++ RECT rect_105 = { 105, 105, 105, 105 }; ++ RECT rect_110 = { 110, 110, 110, 110 }; ++ int i; ++ ++ while (WaitForSingleObject(params->ready, INFINITE) == 0) ++ { ++ ResetEvent(params->ready); ++ SetEvent(params->start); ++ ++ switch (params->step) ++ { ++ case 0: ++ case 1: ++ case 2: ++ mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0); ++ mouse_event(MOUSEEVENTF_MOVE, 0, -1, 0, 0); ++ break; ++ case 3: ++ for (i = 0; i < 10; ++i) ++ { ++ ClipCursor(&rect_105); ++ Sleep(5); ++ ClipCursor(&rect_110); ++ Sleep(5); ++ ClipCursor(NULL); ++ Sleep(5); ++ } ++ break; ++ case 4: ++ for (i = 0; i < 10; ++i) ++ { ++ ClipCursor(&rect_110); ++ Sleep(5); ++ mouse_event(MOUSEEVENTF_MOVE, 1, 1, 0, 0); ++ ClipCursor(NULL); ++ Sleep(5); ++ mouse_event(MOUSEEVENTF_MOVE, 1, 1, 0, 0); ++ ClipCursor(&rect_110); ++ ClipCursor(NULL); ++ Sleep(5); ++ } ++ break; ++ default: ++ return 0; ++ } ++ ++ PostMessageA(params->window, WM_USER, 0, 0); ++ } ++ ++ return 0; ++} ++ ++struct rawinput_mouse_test ++{ ++ BOOL register_device; ++ BOOL register_window; ++ DWORD register_flags; ++ int expect_received; ++ int expect_received_foreground; ++ int expect_motion_x; ++ int expect_motion_y; ++ BOOL todo; ++}; ++ ++static void test_rawinput_mouse(void) ++{ ++ struct rawinput_mouse_thread_params params; ++ RAWINPUTDEVICE raw_devices[1]; ++ HANDLE thread; ++ DWORD ret; ++ int i; ++ ++ struct rawinput_mouse_test tests[] = ++ { ++ { FALSE, FALSE, 0, 0, 0, 0, 0, FALSE }, ++ { TRUE, FALSE, 0, 2, 2, -1, -1, FALSE }, ++ { TRUE, TRUE, 0, 2, 2, -1, -1, FALSE }, ++ { TRUE, TRUE, 0, 0, 0, 0, 0, TRUE }, ++ { TRUE, TRUE, 0, 20, 20, 20, 20, TRUE }, ++ }; ++ ++ mouse_event(MOUSEEVENTF_ABSOLUTE, 100, 100, 0, 0); ++ SetCursorPos(100, 100); ++ ++ rawinput_wndproc_done = CreateEventA(NULL, FALSE, FALSE, NULL); ++ ok(rawinput_wndproc_done != NULL, "CreateEvent failed\n"); ++ ++ params.window = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, 100, 100, 100, 100, 0, NULL, NULL, NULL); ++ ok(params.window != 0, "CreateWindow failed\n"); ++ ++ ShowWindow(params.window, SW_SHOW); ++ SetWindowPos(params.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); ++ SetForegroundWindow(params.window); ++ UpdateWindow(params.window); ++ empty_message_queue(); ++ ++ SetWindowLongPtrA(params.window, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc); ++ ++ params.step = 0; ++ params.ready = CreateEventA(NULL, FALSE, FALSE, NULL); ++ ok(params.ready != NULL, "CreateEvent failed\n"); ++ ++ params.start = CreateEventA(NULL, FALSE, FALSE, NULL); ++ ok(params.start != NULL, "CreateEvent failed\n"); ++ ++ thread = CreateThread(NULL, 0, rawinput_mouse_thread, ¶ms, 0, NULL); ++ ok(thread != NULL, "CreateThread failed\n"); ++ ++ for (i = 0; i < ARRAY_SIZE(tests); ++i) ++ { ++ rawinput_received = 0; ++ rawinput_received_foreground = 0; ++ rawinput_motion_x = 0; ++ rawinput_motion_y = 0; ++ ++ raw_devices[0].usUsagePage = 0x01; ++ raw_devices[0].usUsage = 0x02; ++ raw_devices[0].dwFlags = tests[i].register_flags; ++ raw_devices[0].hwndTarget = tests[i].register_window ? params.window : 0; ++ ++ if (tests[i].register_device) ++ { ++ SetLastError(0xdeadbeef); ++ ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); ++ ok(ret, "%d: RegisterRawInputDevices failed\n", i); ++ ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08x\n", i, GetLastError()); ++ } ++ ++ params.step = i; ++ SetEvent(params.ready); ++ ++ WaitForSingleObject(params.start, INFINITE); ++ ResetEvent(params.start); ++ ++ while (MsgWaitForMultipleObjects(1, &rawinput_wndproc_done, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0) ++ empty_message_queue(); ++ ResetEvent(rawinput_wndproc_done); ++ ++ /* Wine is sometimes passing some of the conditions, but not always, let's test ++ * all at once in the todo block, there should be at least one that fails. */ ++ todo_wine_if(tests[i].todo) ++ ok(rawinput_received == tests[i].expect_received && ++ rawinput_received_foreground == tests[i].expect_received_foreground && ++ rawinput_motion_x == tests[i].expect_motion_x && ++ rawinput_motion_y == tests[i].expect_motion_y, ++ "%d: Unexpected rawinput results: received %d, %d in foreground, motion is %dx%d\n", ++ i, rawinput_received, rawinput_received_foreground, rawinput_motion_x, rawinput_motion_y); ++ ++ if (tests[i].register_device) ++ { ++ raw_devices[0].dwFlags = RIDEV_REMOVE; ++ raw_devices[0].hwndTarget = 0; ++ ++ SetLastError(0xdeadbeef); ++ ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); ++ ok(ret, "%d: RegisterRawInputDevices failed\n", i); ++ ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08x\n", i, GetLastError()); ++ } ++ } ++ ++ params.step = -1; ++ SetEvent(params.ready); ++ WaitForSingleObject(thread, INFINITE); ++ ++ CloseHandle(params.start); ++ CloseHandle(params.ready); ++ CloseHandle(thread); ++} ++ + static void test_key_map(void) + { + HKL kl = GetKeyboardLayout(0); +@@ -3326,6 +3551,7 @@ START_TEST(input) + test_GetRawInputData(); + test_GetKeyboardLayoutList(); + test_RegisterRawInputDevices(); ++ test_rawinput_mouse(); + + if(pGetMouseMovePointsEx) + test_GetMouseMovePointsEx(); +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse/0002-user32-tests-Add-rawinput-test-for-cross-thread-inte.patch b/patches/user32-rawinput-mouse/0002-user32-tests-Add-rawinput-test-for-cross-thread-inte.patch new file mode 100644 index 00000000..74cb79c9 --- /dev/null +++ b/patches/user32-rawinput-mouse/0002-user32-tests-Add-rawinput-test-for-cross-thread-inte.patch @@ -0,0 +1,70 @@ +From d407a40a11f0cbf3e61faded5e6e7e1e2e63ef9c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 14 Nov 2019 17:03:38 +0100 +Subject: [PATCH 02/12] user32/tests: Add rawinput test for cross-thread + interactions. + +The rawinput messages are received on the target window if is from the +same process as the foreground window, it doesn't need to be the +foreground window itself. +--- + dlls/user32/tests/input.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c +index bf9d19906a8..bdcc6834d9d 100644 +--- a/dlls/user32/tests/input.c ++++ b/dlls/user32/tests/input.c +@@ -1884,6 +1884,7 @@ static DWORD WINAPI rawinput_mouse_thread(void *arg) + struct rawinput_mouse_thread_params *params = arg; + RECT rect_105 = { 105, 105, 105, 105 }; + RECT rect_110 = { 110, 110, 110, 110 }; ++ HWND window; + int i; + + while (WaitForSingleObject(params->ready, INFINITE) == 0) +@@ -1924,6 +1925,26 @@ static DWORD WINAPI rawinput_mouse_thread(void *arg) + Sleep(5); + } + break; ++ case 5: ++ case 6: ++ window = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, 100, 100, 100, 100, 0, NULL, NULL, NULL); ++ ok(window != 0, "%d: CreateWindow failed\n", params->step); ++ ++ ShowWindow(window, SW_SHOW); ++ SetWindowPos(window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); ++ SetForegroundWindow(window); ++ UpdateWindow(window); ++ empty_message_queue(); ++ ++ mouse_event(MOUSEEVENTF_MOVE, 1, 1, 0, 0); ++ SendMessageA(GetForegroundWindow(), WM_USER, 0, 0); ++ mouse_event(MOUSEEVENTF_MOVE, -1, -1, 0, 0); ++ SendMessageA(GetForegroundWindow(), WM_USER, 0, 0); ++ ++ empty_message_queue(); ++ ++ DestroyWindow(window); ++ break; + default: + return 0; + } +@@ -1959,8 +1980,14 @@ static void test_rawinput_mouse(void) + { FALSE, FALSE, 0, 0, 0, 0, 0, FALSE }, + { TRUE, FALSE, 0, 2, 2, -1, -1, FALSE }, + { TRUE, TRUE, 0, 2, 2, -1, -1, FALSE }, ++ ++ /* clip cursor tests */ + { TRUE, TRUE, 0, 0, 0, 0, 0, TRUE }, + { TRUE, TRUE, 0, 20, 20, 20, 20, TRUE }, ++ ++ /* same-process foreground tests */ ++ { TRUE, TRUE, 0, 2, 2, 0, 0, TRUE }, ++ { TRUE, TRUE, RIDEV_INPUTSINK, 2, 2, 0, 0, TRUE }, + }; + + mouse_event(MOUSEEVENTF_ABSOLUTE, 100, 100, 0, 0); +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse/0003-user32-tests-Add-rawinput-test-for-cross-process-int.patch b/patches/user32-rawinput-mouse/0003-user32-tests-Add-rawinput-test-for-cross-process-int.patch new file mode 100644 index 00000000..05e1d75a --- /dev/null +++ b/patches/user32-rawinput-mouse/0003-user32-tests-Add-rawinput-test-for-cross-process-int.patch @@ -0,0 +1,173 @@ +From 35e259f69a7c5a6a065833eaeaca28d92591056b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 14 Nov 2019 18:44:28 +0100 +Subject: [PATCH 03/12] user32/tests: Add rawinput test for cross-process + interactions. + +Validating the rest of the assumption, rawinput messages are not +received anymore if the foreground window is from another process. +--- + dlls/user32/tests/input.c | 86 ++++++++++++++++++++++++++++++++++++++- + 1 file changed, 84 insertions(+), 2 deletions(-) + +diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c +index bdcc6834d9d..cc7babd1af4 100644 +--- a/dlls/user32/tests/input.c ++++ b/dlls/user32/tests/input.c +@@ -49,6 +49,7 @@ + #define _WIN32_IE 0x0500 + + #include ++#include + #include + + #include "windef.h" +@@ -1877,8 +1878,36 @@ struct rawinput_mouse_thread_params + HWND window; + HANDLE ready; + HANDLE start; ++ const char *argv0; + }; + ++static void rawinput_mouse_process(void) ++{ ++ HWND window; ++ HANDLE start_event, stop_event; ++ ++ start_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "test_rawinput_mouse_start"); ++ ok(start_event != 0, "OpenEventA failed, error: %u\n", GetLastError()); ++ ++ stop_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "test_rawinput_mouse_stop"); ++ ok(stop_event != 0, "OpenEventA failed, error: %u\n", GetLastError()); ++ ++ window = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, 200, 100, 100, 100, 0, NULL, NULL, NULL); ++ ok(window != 0, "CreateWindow failed\n"); ++ ++ ShowWindow(window, SW_SHOW); ++ SetWindowPos(window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); ++ SetForegroundWindow(window); ++ UpdateWindow(window); ++ empty_message_queue(); ++ ++ SetEvent(start_event); ++ while (MsgWaitForMultipleObjects(1, &stop_event, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0) ++ empty_message_queue(); ++ ++ DestroyWindow(window); ++} ++ + static DWORD WINAPI rawinput_mouse_thread(void *arg) + { + struct rawinput_mouse_thread_params *params = arg; +@@ -1886,6 +1915,11 @@ static DWORD WINAPI rawinput_mouse_thread(void *arg) + RECT rect_110 = { 110, 110, 110, 110 }; + HWND window; + int i; ++ char path[MAX_PATH]; ++ PROCESS_INFORMATION process_info; ++ STARTUPINFOA startup_info; ++ HANDLE start_event, stop_event; ++ BOOL ret; + + while (WaitForSingleObject(params->ready, INFINITE) == 0) + { +@@ -1945,6 +1979,39 @@ static DWORD WINAPI rawinput_mouse_thread(void *arg) + + DestroyWindow(window); + break; ++ case 7: ++ case 8: ++ start_event = CreateEventA(NULL, 0, 0, "test_rawinput_mouse_start"); ++ ok(start_event != 0, "%d: CreateEventA failed, error %u\n", params->step, GetLastError()); ++ ++ stop_event = CreateEventA(NULL, 0, 0, "test_rawinput_mouse_stop"); ++ ok(stop_event != 0, "%d: CreateEventA failed, error %u\n", params->step, GetLastError()); ++ ++ memset(&startup_info, 0, sizeof(startup_info)); ++ startup_info.cb = sizeof(startup_info); ++ startup_info.dwFlags = STARTF_USESHOWWINDOW; ++ startup_info.wShowWindow = SW_SHOWNORMAL; ++ ++ sprintf(path, "%s input test_rawinput_mouse", params->argv0); ++ ret = CreateProcessA(NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info ); ++ ok(ret, "%d: CreateProcess '%s' failed err %u.\n", params->step, path, GetLastError()); ++ ++ ret = WaitForSingleObject(start_event, 5000); ++ ok(ret == WAIT_OBJECT_0, "%d: WaitForSingleObject failed\n", params->step); ++ ++ mouse_event(MOUSEEVENTF_MOVE, 1, 1, 0, 0); ++ SendMessageA(GetForegroundWindow(), WM_USER, 0, 0); ++ mouse_event(MOUSEEVENTF_MOVE, -1, -1, 0, 0); ++ SendMessageA(GetForegroundWindow(), WM_USER, 0, 0); ++ ++ SetEvent(stop_event); ++ ++ winetest_wait_child_process(process_info.hProcess); ++ CloseHandle(process_info.hProcess); ++ CloseHandle(process_info.hThread); ++ CloseHandle(start_event); ++ CloseHandle(stop_event); ++ break; + default: + return 0; + } +@@ -1967,7 +2034,7 @@ struct rawinput_mouse_test + BOOL todo; + }; + +-static void test_rawinput_mouse(void) ++static void test_rawinput_mouse(const char *argv0) + { + struct rawinput_mouse_thread_params params; + RAWINPUTDEVICE raw_devices[1]; +@@ -1988,11 +2055,17 @@ static void test_rawinput_mouse(void) + /* same-process foreground tests */ + { TRUE, TRUE, 0, 2, 2, 0, 0, TRUE }, + { TRUE, TRUE, RIDEV_INPUTSINK, 2, 2, 0, 0, TRUE }, ++ ++ /* cross-process foreground tests */ ++ { TRUE, TRUE, 0, 0, 0, 0, 0, TRUE }, ++ { TRUE, TRUE, RIDEV_INPUTSINK, 2, 0, 0, 0, TRUE }, + }; + + mouse_event(MOUSEEVENTF_ABSOLUTE, 100, 100, 0, 0); + SetCursorPos(100, 100); + ++ params.argv0 = argv0; ++ + rawinput_wndproc_done = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(rawinput_wndproc_done != NULL, "CreateEvent failed\n"); + +@@ -3555,11 +3628,20 @@ static void test_GetKeyboardLayoutList(void) + + START_TEST(input) + { ++ char **argv; ++ int argc; + POINT pos; + + init_function_pointers(); + GetCursorPos( &pos ); + ++ argc = winetest_get_mainargs(&argv); ++ if (argc >= 3 && strcmp(argv[2], "test_rawinput_mouse") == 0) ++ { ++ rawinput_mouse_process(); ++ return; ++ } ++ + test_Input_blackbox(); + test_Input_whitebox(); + test_Input_unicode(); +@@ -3578,7 +3660,7 @@ START_TEST(input) + test_GetRawInputData(); + test_GetKeyboardLayoutList(); + test_RegisterRawInputDevices(); +- test_rawinput_mouse(); ++ test_rawinput_mouse(argv[0]); + + if(pGetMouseMovePointsEx) + test_GetMouseMovePointsEx(); +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse/0004-server-Add-send_hardware_message-flags-for-rawinput-.patch b/patches/user32-rawinput-mouse/0004-server-Add-send_hardware_message-flags-for-rawinput-.patch new file mode 100644 index 00000000..6770f20a --- /dev/null +++ b/patches/user32-rawinput-mouse/0004-server-Add-send_hardware_message-flags-for-rawinput-.patch @@ -0,0 +1,128 @@ +From 430580824e975bbda41884affd3e5fbf104ac6fe Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Mon, 26 Aug 2019 14:37:20 +0200 +Subject: [PATCH 04/12] server: Add send_hardware_message flags for rawinput + translation. + +--- + dlls/user32/input.c | 6 +++--- + server/protocol.def | 2 ++ + server/queue.c | 20 ++++++++++++++------ + 3 files changed, 19 insertions(+), 9 deletions(-) + +diff --git a/dlls/user32/input.c b/dlls/user32/input.c +index 340d20e58f9..7d947a98d0f 100644 +--- a/dlls/user32/input.c ++++ b/dlls/user32/input.c +@@ -124,7 +124,7 @@ BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) + */ + BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input ) + { +- NTSTATUS status = send_hardware_message( hwnd, input, 0 ); ++ NTSTATUS status = send_hardware_message( hwnd, input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); + if (status) SetLastError( RtlNtStatusToDosError(status) ); + return !status; + } +@@ -192,9 +192,9 @@ UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size ) + /* we need to update the coordinates to what the server expects */ + INPUT input = inputs[i]; + update_mouse_coords( &input ); +- status = send_hardware_message( 0, &input, SEND_HWMSG_INJECTED ); ++ status = send_hardware_message( 0, &input, SEND_HWMSG_INJECTED|SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); + } +- else status = send_hardware_message( 0, &inputs[i], SEND_HWMSG_INJECTED ); ++ else status = send_hardware_message( 0, &inputs[i], SEND_HWMSG_INJECTED|SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); + + if (status) + { +diff --git a/server/protocol.def b/server/protocol.def +index ae3702b150f..9f9f9197134 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -2370,6 +2370,8 @@ enum message_type + VARARG(keystate,bytes); /* global state array for all the keys */ + @END + #define SEND_HWMSG_INJECTED 0x01 ++#define SEND_HWMSG_RAWINPUT 0x02 ++#define SEND_HWMSG_WINDOW 0x04 + + + /* Get a message from the current queue */ +diff --git a/server/queue.c b/server/queue.c +index af65b5f6b4c..9528453b190 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -1736,7 +1736,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa + + /* queue a hardware message for a mouse event */ + static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, +- unsigned int origin, struct msg_queue *sender ) ++ unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) + { + const struct rawinput_device *device; + struct hardware_msg_data *msg_data; +@@ -1789,7 +1789,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons + y = desktop->cursor.y; + } + +- if ((device = current->process->rawinput_mouse)) ++ if ((device = current->process->rawinput_mouse) && ++ (req_flags & SEND_HWMSG_RAWINPUT)) + { + if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0; + msg_data = msg->data; +@@ -1808,6 +1809,9 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons + queue_hardware_message( desktop, msg, 0 ); + } + ++ if (!(req_flags & SEND_HWMSG_WINDOW)) ++ return 0; ++ + for (i = 0; i < ARRAY_SIZE( messages ); i++) + { + if (!messages[i]) continue; +@@ -1839,7 +1843,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons + + /* queue a hardware message for a keyboard event */ + static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, +- unsigned int origin, struct msg_queue *sender ) ++ unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) + { + struct hw_msg_source source = { IMDT_KEYBOARD, origin }; + const struct rawinput_device *device; +@@ -1915,7 +1919,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c + break; + } + +- if ((device = current->process->rawinput_kbd)) ++ if ((device = current->process->rawinput_kbd) && ++ (req_flags & SEND_HWMSG_RAWINPUT)) + { + if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; + msg_data = msg->data; +@@ -1933,6 +1938,9 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c + queue_hardware_message( desktop, msg, 0 ); + } + ++ if (!(req_flags & SEND_HWMSG_WINDOW)) ++ return 0; ++ + if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; + msg_data = msg->data; + +@@ -2494,10 +2502,10 @@ DECL_HANDLER(send_hardware_message) + switch (req->input.type) + { + case INPUT_MOUSE: +- reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender ); ++ reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender, req->flags ); + break; + case INPUT_KEYBOARD: +- reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender ); ++ reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender, req->flags ); + break; + case INPUT_HARDWARE: + queue_custom_hardware_message( desktop, req->win, origin, &req->input ); +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse/0005-server-Broadcast-rawinput-message-if-request-flag-is.patch b/patches/user32-rawinput-mouse/0005-server-Broadcast-rawinput-message-if-request-flag-is.patch new file mode 100644 index 00000000..c7216c53 --- /dev/null +++ b/patches/user32-rawinput-mouse/0005-server-Broadcast-rawinput-message-if-request-flag-is.patch @@ -0,0 +1,182 @@ +From 9a0c9443ada9bccc1d10270398dbf9bddb483d53 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 12 Nov 2019 12:41:55 +0100 +Subject: [PATCH 05/12] server: Broadcast rawinput message if request flag is + SEND_HWMSG_RAWINPUT. + +If the request flag is equal to SEND_HWMSG_RAWINPUT, we broadcast the +message to all listening processes -or at least to the foreground +process until RIDEV_INPUTSINK is supported. +--- + dlls/user32/tests/input.c | 2 +- + server/queue.c | 98 ++++++++++++++++++++++++++++++--------- + 2 files changed, 78 insertions(+), 22 deletions(-) + +diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c +index cc7babd1af4..d18ccfebcaf 100644 +--- a/dlls/user32/tests/input.c ++++ b/dlls/user32/tests/input.c +@@ -2057,7 +2057,7 @@ static void test_rawinput_mouse(const char *argv0) + { TRUE, TRUE, RIDEV_INPUTSINK, 2, 2, 0, 0, TRUE }, + + /* cross-process foreground tests */ +- { TRUE, TRUE, 0, 0, 0, 0, 0, TRUE }, ++ { TRUE, TRUE, 0, 0, 0, 0, 0, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, 2, 0, 0, 0, TRUE }, + }; + +diff --git a/server/queue.c b/server/queue.c +index 9528453b190..2bdd099d1bb 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -1734,12 +1734,67 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa + return 1; + } + ++struct rawinput_message ++{ ++ struct desktop *desktop; ++ struct hw_msg_source source; ++ unsigned int time; ++ struct hardware_msg_data data; ++}; ++ ++static int queue_rawinput_message( struct process* process, void* user ) ++{ ++ const struct rawinput_message* raw_msg = user; ++ const struct rawinput_device *device = NULL; ++ struct desktop *desktop = NULL; ++ struct thread *thread = NULL, *foreground = NULL; ++ struct message *msg; ++ ++ if (raw_msg->data.rawinput.type == RIM_TYPEMOUSE) ++ device = process->rawinput_mouse; ++ else if (raw_msg->data.rawinput.type == RIM_TYPEKEYBOARD) ++ device = process->rawinput_kbd; ++ ++ if (!device) ++ goto done; ++ ++ if (!(desktop = get_desktop_obj( process, process->desktop, 0 )) || ++ (raw_msg->desktop && desktop != raw_msg->desktop)) ++ goto done; ++ ++ if (!(thread = get_window_thread( device->target ? device->target : desktop->foreground_input->active )) || ++ process != thread->process) ++ goto done; ++ ++ /* FIXME: Implement RIDEV_INPUTSINK */ ++ if (!(foreground = get_window_thread( desktop->foreground_input->active )) || ++ thread->process != foreground->process) ++ goto done; ++ ++ if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time ))) ++ goto done; ++ ++ msg->win = device->target; ++ msg->msg = WM_INPUT; ++ msg->wparam = RIM_INPUT; ++ msg->lparam = 0; ++ memcpy( msg->data, &raw_msg->data, sizeof(raw_msg->data) ); ++ ++ queue_hardware_message( desktop, msg, 0 ); ++ ++done: ++ if (foreground) release_object( foreground ); ++ if (thread) release_object( thread ); ++ if (desktop) release_object( desktop ); ++ return 0; ++} ++ + /* queue a hardware message for a mouse event */ + static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, + unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) + { +- const struct rawinput_device *device; + struct hardware_msg_data *msg_data; ++ struct rawinput_message raw_msg; + struct message *msg; + unsigned int i, time, flags; + struct hw_msg_source source = { IMDT_MOUSE, origin }; +@@ -1789,24 +1844,24 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons + y = desktop->cursor.y; + } + +- if ((device = current->process->rawinput_mouse) && +- (req_flags & SEND_HWMSG_RAWINPUT)) ++ if (req_flags & SEND_HWMSG_RAWINPUT) + { +- if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0; +- msg_data = msg->data; +- +- msg->win = device->target; +- msg->msg = WM_INPUT; +- msg->wparam = RIM_INPUT; +- msg->lparam = 0; ++ raw_msg.desktop = desktop; ++ raw_msg.source = source; ++ raw_msg.time = time; + ++ msg_data = &raw_msg.data; ++ msg_data->info = input->mouse.info; + msg_data->flags = flags; + msg_data->rawinput.type = RIM_TYPEMOUSE; + msg_data->rawinput.mouse.x = x - desktop->cursor.x; + msg_data->rawinput.mouse.y = y - desktop->cursor.y; + msg_data->rawinput.mouse.data = input->mouse.data; + +- queue_hardware_message( desktop, msg, 0 ); ++ if (req_flags == SEND_HWMSG_RAWINPUT) ++ enum_processes( queue_rawinput_message, &raw_msg ); ++ else ++ queue_rawinput_message( current->process, &raw_msg ); + } + + if (!(req_flags & SEND_HWMSG_WINDOW)) +@@ -1846,8 +1901,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c + unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) + { + struct hw_msg_source source = { IMDT_KEYBOARD, origin }; +- const struct rawinput_device *device; + struct hardware_msg_data *msg_data; ++ struct rawinput_message raw_msg; + struct message *msg; + unsigned char vkey = input->kbd.vkey; + unsigned int message_code, time; +@@ -1919,23 +1974,24 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c + break; + } + +- if ((device = current->process->rawinput_kbd) && +- (req_flags & SEND_HWMSG_RAWINPUT)) ++ if (req_flags & SEND_HWMSG_RAWINPUT) + { +- if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; +- msg_data = msg->data; +- +- msg->win = device->target; +- msg->msg = WM_INPUT; +- msg->wparam = RIM_INPUT; ++ raw_msg.desktop = desktop; ++ raw_msg.source = source; ++ raw_msg.time = time; + ++ msg_data = &raw_msg.data; ++ msg_data->info = input->kbd.info; + msg_data->flags = input->kbd.flags; + msg_data->rawinput.type = RIM_TYPEKEYBOARD; + msg_data->rawinput.kbd.message = message_code; + msg_data->rawinput.kbd.vkey = vkey; + msg_data->rawinput.kbd.scan = input->kbd.scan; + +- queue_hardware_message( desktop, msg, 0 ); ++ if (req_flags == SEND_HWMSG_RAWINPUT) ++ enum_processes( queue_rawinput_message, &raw_msg ); ++ else ++ queue_rawinput_message( current->process, &raw_msg ); + } + + if (!(req_flags & SEND_HWMSG_WINDOW)) +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse/0006-user32-Add-__wine_send_input-flags-to-hint-raw-input.patch b/patches/user32-rawinput-mouse/0006-user32-Add-__wine_send_input-flags-to-hint-raw-input.patch new file mode 100644 index 00000000..1d18abe6 --- /dev/null +++ b/patches/user32-rawinput-mouse/0006-user32-Add-__wine_send_input-flags-to-hint-raw-input.patch @@ -0,0 +1,193 @@ +From 8304a54fbb8d34bf4278155624464d2b47ce37cf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Mon, 26 Aug 2019 15:20:32 +0200 +Subject: [PATCH 06/12] user32: Add __wine_send_input flags to hint raw input + translation. + +--- + dlls/user32/input.c | 4 ++-- + dlls/user32/user32.spec | 2 +- + dlls/wineandroid.drv/keyboard.c | 2 +- + dlls/wineandroid.drv/window.c | 4 ++-- + dlls/winemac.drv/ime.c | 4 ++-- + dlls/winemac.drv/keyboard.c | 2 +- + dlls/winemac.drv/mouse.c | 2 +- + dlls/winex11.drv/keyboard.c | 2 +- + dlls/winex11.drv/mouse.c | 8 ++++---- + include/winuser.h | 2 +- + 10 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/dlls/user32/input.c b/dlls/user32/input.c +index 7d947a98d0f..97a5ada922e 100644 +--- a/dlls/user32/input.c ++++ b/dlls/user32/input.c +@@ -122,9 +122,9 @@ BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) + * + * Internal SendInput function to allow the graphics driver to inject real events. + */ +-BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input ) ++BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, UINT flags ) + { +- NTSTATUS status = send_hardware_message( hwnd, input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); ++ NTSTATUS status = send_hardware_message( hwnd, input, flags ); + if (status) SetLastError( RtlNtStatusToDosError(status) ); + return !status; + } +diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec +index c08ad5ff4f9..b59ba381334 100644 +--- a/dlls/user32/user32.spec ++++ b/dlls/user32/user32.spec +@@ -833,5 +833,5 @@ + # All functions must be prefixed with '__wine_' (for internal functions) + # or 'wine_' (for user-visible functions) to avoid namespace conflicts. + # +-@ cdecl __wine_send_input(long ptr) ++@ cdecl __wine_send_input(long ptr long) + @ cdecl __wine_set_pixel_format(long long) +diff --git a/dlls/wineandroid.drv/keyboard.c b/dlls/wineandroid.drv/keyboard.c +index a0f3257f74b..1af8a98f1f9 100644 +--- a/dlls/wineandroid.drv/keyboard.c ++++ b/dlls/wineandroid.drv/keyboard.c +@@ -680,7 +680,7 @@ static void send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags ) + input.u.ki.time = 0; + input.u.ki.dwExtraInfo = 0; + +- __wine_send_input( hwnd, &input ); ++ __wine_send_input( hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); + } + + /*********************************************************************** +diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c +index 2fc258dfd90..d96f001432d 100644 +--- a/dlls/wineandroid.drv/window.c ++++ b/dlls/wineandroid.drv/window.c +@@ -524,7 +524,7 @@ static int process_events( DWORD mask ) + } + SERVER_END_REQ; + } +- __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input ); ++ __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); + } + break; + +@@ -538,7 +538,7 @@ static int process_events( DWORD mask ) + event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wVk, + event->data.kbd.input.u.ki.wScan ); + update_keyboard_lock_state( event->data.kbd.input.u.ki.wVk, event->data.kbd.lock_state ); +- __wine_send_input( 0, &event->data.kbd.input ); ++ __wine_send_input( 0, &event->data.kbd.input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); + break; + + default: +diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c +index dabe6654f98..2ed6e6f66a3 100644 +--- a/dlls/winemac.drv/ime.c ++++ b/dlls/winemac.drv/ime.c +@@ -1427,10 +1427,10 @@ void macdrv_im_set_text(const macdrv_event *event) + { + input.ki.wScan = chars[i]; + input.ki.dwFlags = KEYEVENTF_UNICODE; +- __wine_send_input(hwnd, &input); ++ __wine_send_input(hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW); + + input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; +- __wine_send_input(hwnd, &input); ++ __wine_send_input(hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW); + } + } + +diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c +index bb408cb20c5..41919baafc7 100644 +--- a/dlls/winemac.drv/keyboard.c ++++ b/dlls/winemac.drv/keyboard.c +@@ -929,7 +929,7 @@ static void macdrv_send_keyboard_input(HWND hwnd, WORD vkey, WORD scan, DWORD fl + input.ki.time = time; + input.ki.dwExtraInfo = 0; + +- __wine_send_input(hwnd, &input); ++ __wine_send_input(hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW); + } + + +diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c +index dd6443fe1ba..91cafdf1362 100644 +--- a/dlls/winemac.drv/mouse.c ++++ b/dlls/winemac.drv/mouse.c +@@ -165,7 +165,7 @@ static void send_mouse_input(HWND hwnd, macdrv_window cocoa_window, UINT flags, + input.mi.time = time; + input.mi.dwExtraInfo = 0; + +- __wine_send_input(top_level_hwnd, &input); ++ __wine_send_input(top_level_hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW); + } + + +diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c +index 3c38784ebf9..7856b04c8f5 100644 +--- a/dlls/winex11.drv/keyboard.c ++++ b/dlls/winex11.drv/keyboard.c +@@ -1149,7 +1149,7 @@ static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD f + input.u.ki.time = time; + input.u.ki.dwExtraInfo = 0; + +- __wine_send_input( hwnd, &input ); ++ __wine_send_input( hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); + } + + +diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c +index 8e1eb6d5e0e..96e04509e73 100644 +--- a/dlls/winex11.drv/mouse.c ++++ b/dlls/winex11.drv/mouse.c +@@ -659,7 +659,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU + } + input->u.mi.dx += clip_rect.left; + input->u.mi.dy += clip_rect.top; +- __wine_send_input( hwnd, input ); ++ __wine_send_input( hwnd, input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); + return; + } + +@@ -699,7 +699,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU + SERVER_END_REQ; + } + +- __wine_send_input( hwnd, input ); ++ __wine_send_input( hwnd, input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); + } + + #ifdef SONAME_LIBXCURSOR +@@ -1645,7 +1645,7 @@ void move_resize_window( HWND hwnd, int dir ) + input.u.mi.dwFlags = button_up_flags[button - 1] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; + input.u.mi.time = GetTickCount(); + input.u.mi.dwExtraInfo = 0; +- __wine_send_input( hwnd, &input ); ++ __wine_send_input( hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); + } + + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) +@@ -1884,7 +1884,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); + + input.type = INPUT_MOUSE; +- __wine_send_input( 0, &input ); ++ __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); + return TRUE; + } + +diff --git a/include/winuser.h b/include/winuser.h +index 51c73d25c2f..10cebfa97d0 100644 +--- a/include/winuser.h ++++ b/include/winuser.h +@@ -4389,7 +4389,7 @@ static inline BOOL WINAPI SetRectEmpty(LPRECT rect) + WORD WINAPI SYSTEM_KillSystemTimer( WORD ); + + #ifdef __WINESRC__ +-WINUSERAPI BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input ); ++WINUSERAPI BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, UINT flags ); + #endif + + #ifdef __cplusplus +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse/0007-winex11.drv-Advertise-XInput2-version-2.1-support.patch b/patches/user32-rawinput-mouse/0007-winex11.drv-Advertise-XInput2-version-2.1-support.patch new file mode 100644 index 00000000..54b9508d --- /dev/null +++ b/patches/user32-rawinput-mouse/0007-winex11.drv-Advertise-XInput2-version-2.1-support.patch @@ -0,0 +1,146 @@ +From 9038e4871284e636f277be8fc8a2a901049bcaf6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 2 Aug 2019 02:24:32 -0400 +Subject: [PATCH 07/12] winex11.drv: Advertise XInput2 version 2.1 support. + +Under XInput2 protocol version < 2.1, RawEvents are not supposed to be +sent if a pointer grab is active. However slave device events are still +received regardless of this specification and Wine implemented a +workaround to receive RawEvents during pointer grabs by listening to +these slave device events. Then, as soon as a mouse button is pressed +only the grabbing client will receive the raw motion events. + +By advertising the support of XInput2 version >= 2.1, where RawEvents +are sent even during pointer grabs, we ensure to receive the RawMotion +events from the desktop window thread, even if a mouse grab is active. + +It is now also possible to simplify the code by listening to master +device events only and get rid of slave device id tracking. +--- + dlls/winex11.drv/mouse.c | 49 ++++++++------------------------------- + dlls/winex11.drv/x11drv.h | 3 --- + 2 files changed, 10 insertions(+), 42 deletions(-) + +diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c +index 96e04509e73..105db08a78a 100644 +--- a/dlls/winex11.drv/mouse.c ++++ b/dlls/winex11.drv/mouse.c +@@ -304,12 +304,16 @@ static void enable_xinput2(void) + + if (data->xi2_state == xi_unknown) + { +- int major = 2, minor = 0; +- if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled; ++ int major = 2, minor = 1; ++ if (!pXIQueryVersion( data->display, &major, &minor ) && major == 2 && minor > 0) ++ { ++ TRACE( "XInput2 v%d.%d available\n", major, minor ); ++ data->xi2_state = xi_disabled; ++ } + else + { + data->xi2_state = xi_unavailable; +- WARN( "X Input 2 not available\n" ); ++ WARN( "XInput v2.1 not available\n" ); + } + } + if (data->xi2_state == xi_unavailable) return; +@@ -317,7 +321,7 @@ static void enable_xinput2(void) + + mask.mask = mask_bits; + mask.mask_len = sizeof(mask_bits); +- mask.deviceid = XIAllDevices; ++ mask.deviceid = XIAllMasterDevices; + memset( mask_bits, 0, sizeof(mask_bits) ); + XISetMask( mask_bits, XI_DeviceChanged ); + XISetMask( mask_bits, XI_RawMotion ); +@@ -329,16 +333,6 @@ static void enable_xinput2(void) + update_relative_valuators( pointer_info->classes, pointer_info->num_classes ); + pXIFreeDeviceInfo( pointer_info ); + +- /* This device info list is only used to find the initial current slave if +- * no XI_DeviceChanged events happened. If any hierarchy change occurred that +- * might be relevant here (eg. user switching mice after (un)plugging), a +- * XI_DeviceChanged event will point us to the right slave. So this list is +- * safe to be obtained statically at enable_xinput2() time. +- */ +- if (data->xi2_devices) pXIFreeDeviceInfo( data->xi2_devices ); +- data->xi2_devices = pXIQueryDevice( data->display, XIAllDevices, &data->xi2_device_count ); +- data->xi2_current_slave = 0; +- + data->xi2_state = xi_enabled; + #endif + } +@@ -359,15 +353,12 @@ static void disable_xinput2(void) + + mask.mask = NULL; + mask.mask_len = 0; +- mask.deviceid = XIAllDevices; ++ mask.deviceid = XIAllMasterDevices; + + pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); +- pXIFreeDeviceInfo( data->xi2_devices ); + data->x_rel_valuator.number = -1; + data->y_rel_valuator.number = -1; +- data->xi2_devices = NULL; + data->xi2_core_pointer = 0; +- data->xi2_current_slave = 0; + #endif + } + +@@ -1801,7 +1792,6 @@ static BOOL X11DRV_DeviceChanged( XGenericEventCookie *xev ) + if (event->reason != XISlaveSwitch) return FALSE; + + update_relative_valuators( event->classes, event->num_classes ); +- data->xi2_current_slave = event->sourceid; + return TRUE; + } + +@@ -1822,26 +1812,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + if (thread_data->x_rel_valuator.number < 0 || thread_data->y_rel_valuator.number < 0) return FALSE; + if (!event->valuators.mask_len) return FALSE; + if (thread_data->xi2_state != xi_enabled) return FALSE; +- +- /* If there is no slave currently detected, no previous motion nor device +- * change events were received. Look it up now on the device list in this +- * case. +- */ +- if (!thread_data->xi2_current_slave) +- { +- XIDeviceInfo *devices = thread_data->xi2_devices; +- +- for (i = 0; i < thread_data->xi2_device_count; i++) +- { +- if (devices[i].use != XISlavePointer) continue; +- if (devices[i].deviceid != event->deviceid) continue; +- if (devices[i].attachment != thread_data->xi2_core_pointer) continue; +- thread_data->xi2_current_slave = event->deviceid; +- break; +- } +- } +- +- if (event->deviceid != thread_data->xi2_current_slave) return FALSE; ++ if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; + + x_rel = &thread_data->x_rel_valuator; + y_rel = &thread_data->y_rel_valuator; +diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h +index cca87433264..432dd5909ca 100644 +--- a/dlls/winex11.drv/x11drv.h ++++ b/dlls/winex11.drv/x11drv.h +@@ -340,12 +340,9 @@ struct x11drv_thread_data + DWORD clip_reset; /* time when clipping was last reset */ + HKL kbd_layout; /* active keyboard layout */ + enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ +- void *xi2_devices; /* list of XInput2 devices (valid when state is enabled) */ +- int xi2_device_count; + struct x11drv_valuator_data x_rel_valuator; + struct x11drv_valuator_data y_rel_valuator; + int xi2_core_pointer; /* XInput2 core pointer id */ +- int xi2_current_slave; /* Current slave driving the Core pointer */ + }; + + extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse/0008-winex11.drv-Keep-track-of-pointer-and-device-button-.patch b/patches/user32-rawinput-mouse/0008-winex11.drv-Keep-track-of-pointer-and-device-button-.patch new file mode 100644 index 00000000..3ff2d5e9 --- /dev/null +++ b/patches/user32-rawinput-mouse/0008-winex11.drv-Keep-track-of-pointer-and-device-button-.patch @@ -0,0 +1,224 @@ +From ef0b82046445fe430ab85bb8069f3e4536b11f7a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 19 Dec 2019 22:34:44 +0100 +Subject: [PATCH 08/12] winex11.drv: Keep track of pointer and device button + mappings. + +We are going to receive raw button events and we will need to apply the +correct button mappings ourselves. + +Original patch by Andrew Eikum . +--- + dlls/winex11.drv/keyboard.c | 23 ++++++--- + dlls/winex11.drv/mouse.c | 89 +++++++++++++++++++++++++++++++++- + dlls/winex11.drv/x11drv.h | 1 + + dlls/winex11.drv/x11drv_main.c | 1 + + 4 files changed, 106 insertions(+), 8 deletions(-) + +diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c +index 7856b04c8f5..3f5d76be57b 100644 +--- a/dlls/winex11.drv/keyboard.c ++++ b/dlls/winex11.drv/keyboard.c +@@ -2010,13 +2010,24 @@ BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event ) + { + HWND hwnd; + +- XRefreshKeyboardMapping(&event->xmapping); +- X11DRV_InitKeyboard( event->xmapping.display ); ++ switch (event->xmapping.request) ++ { ++ case MappingModifier: ++ case MappingKeyboard: ++ XRefreshKeyboardMapping( &event->xmapping ); ++ X11DRV_InitKeyboard( event->xmapping.display ); ++ ++ hwnd = GetFocus(); ++ if (!hwnd) hwnd = GetActiveWindow(); ++ PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST, ++ 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0)); ++ break; ++ ++ case MappingPointer: ++ X11DRV_InitMouse( event->xmapping.display ); ++ break; ++ } + +- hwnd = GetFocus(); +- if (!hwnd) hwnd = GetActiveWindow(); +- PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST, +- 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0)); + return TRUE; + } + +diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c +index 105db08a78a..19ed2a29287 100644 +--- a/dlls/winex11.drv/mouse.c ++++ b/dlls/winex11.drv/mouse.c +@@ -25,6 +25,9 @@ + #include + #include + #include ++#ifdef HAVE_X11_EXTENSIONS_XINPUT_H ++#include ++#endif + #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + #include + #endif +@@ -143,6 +146,14 @@ MAKE_FUNCPTR(XISelectEvents); + #undef MAKE_FUNCPTR + #endif + ++#ifdef HAVE_X11_EXTENSIONS_XINPUT_H ++#define MAKE_FUNCPTR(f) static typeof(f) * p##f ++MAKE_FUNCPTR(XOpenDevice); ++MAKE_FUNCPTR(XCloseDevice); ++MAKE_FUNCPTR(XGetDeviceButtonMapping); ++#undef MAKE_FUNCPTR ++#endif ++ + /*********************************************************************** + * X11DRV_Xcursor_Init + * +@@ -249,6 +260,70 @@ void sync_window_cursor( Window window ) + set_window_cursor( window, cursor ); + } + ++struct mouse_button_mapping ++{ ++ int deviceid; ++ unsigned int button_count; ++ unsigned char buttons[256]; ++}; ++ ++static struct mouse_button_mapping *pointer_mapping; ++static struct mouse_button_mapping *device_mapping; ++ ++static void update_pointer_mapping( Display *display ) ++{ ++ struct mouse_button_mapping *tmp; ++ ++ if (!(tmp = HeapAlloc( GetProcessHeap(), 0, sizeof(*tmp) ))) ++ { ++ WARN("Unable to allocate device mapping.\n"); ++ return; ++ } ++ ++ tmp->button_count = ARRAY_SIZE( tmp->buttons ); ++ tmp->button_count = XGetPointerMapping( display, tmp->buttons, tmp->button_count ); ++ ++ tmp = InterlockedExchangePointer( (void**)&pointer_mapping, tmp ); ++ ++ HeapFree( GetProcessHeap(), 0, tmp ); ++} ++ ++static void update_device_mapping( Display *display, int deviceid ) ++{ ++#ifdef HAVE_X11_EXTENSIONS_XINPUT_H ++ struct mouse_button_mapping *tmp; ++ XDevice *device; ++ ++ if (!(device = pXOpenDevice( display, deviceid ))) ++ { ++ WARN( "Unable to open cursor device %d\n", deviceid ); ++ return; ++ } ++ ++ if (!(tmp = HeapAlloc( GetProcessHeap(), 0, sizeof(*tmp) ))) ++ { ++ WARN( "Unable to allocate device mapping.\n" ); ++ pXCloseDevice( display, device ); ++ return; ++ } ++ ++ tmp->deviceid = deviceid; ++ tmp->button_count = ARRAY_SIZE( tmp->buttons ); ++ tmp->button_count = pXGetDeviceButtonMapping( display, device, tmp->buttons, tmp->button_count ); ++ ++ tmp = InterlockedExchangePointer( (void**)&device_mapping, tmp ); ++ ++ HeapFree( GetProcessHeap(), 0, tmp ); ++ ++ pXCloseDevice( display, device ); ++#endif ++} ++ ++void X11DRV_InitMouse( Display *display ) ++{ ++ update_pointer_mapping( display ); ++} ++ + #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + /*********************************************************************** + * update_relative_valuators +@@ -1792,6 +1867,8 @@ static BOOL X11DRV_DeviceChanged( XGenericEventCookie *xev ) + if (event->reason != XISlaveSwitch) return FALSE; + + update_relative_valuators( event->classes, event->num_classes ); ++ update_device_mapping( event->display, event->sourceid ); ++ + return TRUE; + } + +@@ -1861,13 +1938,12 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + + #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ + +- + /*********************************************************************** + * X11DRV_XInput2_Init + */ + void X11DRV_XInput2_Init(void) + { +-#if defined(SONAME_LIBXI) && defined(HAVE_X11_EXTENSIONS_XINPUT2_H) ++#if defined(SONAME_LIBXI) + int event, error; + void *libxi_handle = wine_dlopen( SONAME_LIBXI, RTLD_NOW, NULL, 0 ); + +@@ -1883,11 +1959,20 @@ void X11DRV_XInput2_Init(void) + return; \ + } + ++#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + LOAD_FUNCPTR(XIGetClientPointer); + LOAD_FUNCPTR(XIFreeDeviceInfo); + LOAD_FUNCPTR(XIQueryDevice); + LOAD_FUNCPTR(XIQueryVersion); + LOAD_FUNCPTR(XISelectEvents); ++#endif ++ ++#ifdef HAVE_X11_EXTENSIONS_XINPUT_H ++ LOAD_FUNCPTR(XOpenDevice); ++ LOAD_FUNCPTR(XCloseDevice); ++ LOAD_FUNCPTR(XGetDeviceButtonMapping); ++#endif ++ + #undef LOAD_FUNCPTR + + xinput2_available = XQueryExtension( gdi_display, "XInputExtension", &xinput2_opcode, &event, &error ); +diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h +index 432dd5909ca..7145fec74e7 100644 +--- a/dlls/winex11.drv/x11drv.h ++++ b/dlls/winex11.drv/x11drv.h +@@ -632,6 +632,7 @@ extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; + extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; + extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; + extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN; ++extern void X11DRV_InitMouse( Display *display ) DECLSPEC_HIDDEN; + extern DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout, + DWORD mask, DWORD flags ) DECLSPEC_HIDDEN; + +diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c +index 11e4ee29155..ff9185a523c 100644 +--- a/dlls/winex11.drv/x11drv_main.c ++++ b/dlls/winex11.drv/x11drv_main.c +@@ -623,6 +623,7 @@ static BOOL process_attach(void) + if (use_xkb) use_xkb = XkbUseExtension( gdi_display, NULL, NULL ); + #endif + X11DRV_InitKeyboard( gdi_display ); ++ X11DRV_InitMouse( gdi_display ); + if (use_xim) use_xim = X11DRV_InitXIM( input_style ); + + X11DRV_DisplayDevices_Init(FALSE); +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse/0009-winex11.drv-Listen-to-RawMotion-and-RawButton-events.patch b/patches/user32-rawinput-mouse/0009-winex11.drv-Listen-to-RawMotion-and-RawButton-events.patch new file mode 100644 index 00000000..45554b38 --- /dev/null +++ b/patches/user32-rawinput-mouse/0009-winex11.drv-Listen-to-RawMotion-and-RawButton-events.patch @@ -0,0 +1,304 @@ +From e8b90f221774d70fb9510b6de18378ab3abdcad2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 11 Sep 2019 10:15:20 +0200 +Subject: [PATCH 09/12] winex11.drv: Listen to RawMotion and RawButton* events + in the desktop thread. + +We still need to send "normal" input from the clipping window thread +to trigger low-level hooks callbacks when clipping cursor. This is for +instance used in our dinput implementation. +--- + dlls/user32/tests/input.c | 8 ++-- + dlls/winex11.drv/event.c | 10 +++- + dlls/winex11.drv/mouse.c | 88 ++++++++++++++++++++++++++++------ + dlls/winex11.drv/x11drv.h | 3 ++ + dlls/winex11.drv/x11drv_main.c | 4 ++ + 5 files changed, 93 insertions(+), 20 deletions(-) + +diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c +index d18ccfebcaf..a1f983f1960 100644 +--- a/dlls/user32/tests/input.c ++++ b/dlls/user32/tests/input.c +@@ -2049,12 +2049,12 @@ static void test_rawinput_mouse(const char *argv0) + { TRUE, TRUE, 0, 2, 2, -1, -1, FALSE }, + + /* clip cursor tests */ +- { TRUE, TRUE, 0, 0, 0, 0, 0, TRUE }, +- { TRUE, TRUE, 0, 20, 20, 20, 20, TRUE }, ++ { TRUE, TRUE, 0, 0, 0, 0, 0, FALSE }, ++ { TRUE, TRUE, 0, 20, 20, 20, 20, FALSE }, + + /* same-process foreground tests */ +- { TRUE, TRUE, 0, 2, 2, 0, 0, TRUE }, +- { TRUE, TRUE, RIDEV_INPUTSINK, 2, 2, 0, 0, TRUE }, ++ { TRUE, TRUE, 0, 2, 2, 0, 0, FALSE }, ++ { TRUE, TRUE, RIDEV_INPUTSINK, 2, 2, 0, 0, FALSE }, + + /* cross-process foreground tests */ + { TRUE, TRUE, 0, 0, 0, 0, 0, FALSE }, +diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c +index 87ba808956f..b3faf3f7cc5 100644 +--- a/dlls/winex11.drv/event.c ++++ b/dlls/winex11.drv/event.c +@@ -321,6 +321,10 @@ static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawE + */ + static enum event_merge_action merge_events( XEvent *prev, XEvent *next ) + { ++#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H ++ struct x11drv_thread_data *thread_data = x11drv_thread_data(); ++#endif ++ + switch (prev->type) + { + case ConfigureNotify: +@@ -352,19 +356,21 @@ static enum event_merge_action merge_events( XEvent *prev, XEvent *next ) + case GenericEvent: + if (next->xcookie.extension != xinput2_opcode) break; + if (next->xcookie.evtype != XI_RawMotion) break; +- if (x11drv_thread_data()->warp_serial) break; ++ if (thread_data->xi2_rawinput_only) break; ++ if (thread_data->warp_serial) break; + return MERGE_KEEP; + } + break; + case GenericEvent: + if (prev->xcookie.extension != xinput2_opcode) break; + if (prev->xcookie.evtype != XI_RawMotion) break; ++ if (thread_data->xi2_rawinput_only) break; + switch (next->type) + { + case GenericEvent: + if (next->xcookie.extension != xinput2_opcode) break; + if (next->xcookie.evtype != XI_RawMotion) break; +- if (x11drv_thread_data()->warp_serial) break; ++ if (thread_data->warp_serial) break; + return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data ); + #endif + } +diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c +index 19ed2a29287..d331ed5aef8 100644 +--- a/dlls/winex11.drv/mouse.c ++++ b/dlls/winex11.drv/mouse.c +@@ -364,9 +364,9 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator + + + /*********************************************************************** +- * enable_xinput2 ++ * X11DRV_XInput2_Enable + */ +-static void enable_xinput2(void) ++void X11DRV_XInput2_Enable(void) + { + #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + struct x11drv_thread_data *data = x11drv_thread_data(); +@@ -398,9 +398,21 @@ static void enable_xinput2(void) + mask.mask_len = sizeof(mask_bits); + mask.deviceid = XIAllMasterDevices; + memset( mask_bits, 0, sizeof(mask_bits) ); ++ + XISetMask( mask_bits, XI_DeviceChanged ); + XISetMask( mask_bits, XI_RawMotion ); +- XISetMask( mask_bits, XI_ButtonPress ); ++ ++ if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId()) ++ { ++ XISetMask( mask_bits, XI_RawButtonPress ); ++ XISetMask( mask_bits, XI_RawButtonRelease ); ++ data->xi2_rawinput_only = TRUE; ++ } ++ else ++ { ++ XISetMask( mask_bits, XI_ButtonPress ); ++ data->xi2_rawinput_only = FALSE; ++ } + + pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); + +@@ -413,9 +425,9 @@ static void enable_xinput2(void) + } + + /*********************************************************************** +- * disable_xinput2 ++ * X11DRV_XInput2_Disable + */ +-static void disable_xinput2(void) ++void X11DRV_XInput2_Disable(void) + { + #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + struct x11drv_thread_data *data = x11drv_thread_data(); +@@ -475,7 +487,7 @@ static BOOL grab_clipping_window( const RECT *clip ) + } + + /* enable XInput2 unless we are already clipping */ +- if (!data->clip_hwnd) enable_xinput2(); ++ if (!data->clip_hwnd) X11DRV_XInput2_Enable(); + + if (data->xi2_state != xi_enabled) + { +@@ -505,7 +517,7 @@ static BOOL grab_clipping_window( const RECT *clip ) + + if (!clipping_cursor) + { +- disable_xinput2(); ++ X11DRV_XInput2_Disable(); + DestroyWindow( msg_hwnd ); + return FALSE; + } +@@ -586,7 +598,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) + TRACE( "clip hwnd reset from %p\n", hwnd ); + data->clip_hwnd = 0; + data->clip_reset = GetTickCount(); +- disable_xinput2(); ++ X11DRV_XInput2_Disable(); + DestroyWindow( hwnd ); + } + else if (hwnd == GetForegroundWindow()) /* request to clip */ +@@ -725,7 +737,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU + } + input->u.mi.dx += clip_rect.left; + input->u.mi.dy += clip_rect.top; +- __wine_send_input( hwnd, input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); ++ __wine_send_input( hwnd, input, SEND_HWMSG_WINDOW ); + return; + } + +@@ -765,7 +777,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU + SERVER_END_REQ; + } + +- __wine_send_input( hwnd, input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); ++ __wine_send_input( hwnd, input, SEND_HWMSG_WINDOW ); + } + + #ifdef SONAME_LIBXCURSOR +@@ -1711,7 +1723,7 @@ void move_resize_window( HWND hwnd, int dir ) + input.u.mi.dwFlags = button_up_flags[button - 1] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; + input.u.mi.time = GetTickCount(); + input.u.mi.dwExtraInfo = 0; +- __wine_send_input( hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); ++ __wine_send_input( hwnd, &input, SEND_HWMSG_WINDOW ); + } + + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) +@@ -1894,6 +1906,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + x_rel = &thread_data->x_rel_valuator; + y_rel = &thread_data->y_rel_valuator; + ++ input.type = INPUT_MOUSE; + input.u.mi.mouseData = 0; + input.u.mi.dwFlags = MOUSEEVENTF_MOVE; + input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); +@@ -1929,10 +1942,53 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) + return FALSE; + } + +- TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); ++ if (!thread_data->xi2_rawinput_only) ++ { ++ TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); ++ __wine_send_input( 0, &input, SEND_HWMSG_WINDOW ); ++ } ++ else ++ { ++ TRACE( "raw pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); ++ __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT ); ++ } ++ return TRUE; ++} + +- input.type = INPUT_MOUSE; +- __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); ++/*********************************************************************** ++ * X11DRV_RawButtonEvent ++ */ ++static BOOL X11DRV_RawButtonEvent( XGenericEventCookie *cookie ) ++{ ++ struct x11drv_thread_data *thread_data = x11drv_thread_data(); ++ XIRawEvent *event = cookie->data; ++ int button = event->detail - 1; ++ INPUT input; ++ ++ if (!device_mapping || device_mapping->deviceid != event->sourceid) ++ update_device_mapping( event->display, event->sourceid ); ++ ++ if (button >= 0 && device_mapping) ++ button = device_mapping->buttons[button] - 1; ++ ++ if (button >= 0 && pointer_mapping) ++ button = pointer_mapping->buttons[button] - 1; ++ ++ if (button < 0 || button >= NB_BUTTONS) return FALSE; ++ if (thread_data->xi2_state != xi_enabled) return FALSE; ++ if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; ++ ++ TRACE( "raw button %u (raw: %u) %s\n", button, event->detail, event->evtype == XI_RawButtonRelease ? "up" : "down" ); ++ ++ input.type = INPUT_MOUSE; ++ input.u.mi.dx = 0; ++ input.u.mi.dy = 0; ++ input.u.mi.mouseData = event->evtype == XI_RawButtonRelease ? button_up_data[button] : button_down_data[button]; ++ input.u.mi.dwFlags = event->evtype == XI_RawButtonRelease ? button_up_flags[button] : button_down_flags[button]; ++ input.u.mi.time = EVENT_x11_time_to_win32_time(event->time); ++ input.u.mi.dwExtraInfo = 0; ++ ++ __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT ); + return TRUE; + } + +@@ -2008,6 +2064,10 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev ) + case XI_RawMotion: + ret = X11DRV_RawMotion( event ); + break; ++ case XI_RawButtonPress: ++ case XI_RawButtonRelease: ++ ret = X11DRV_RawButtonEvent( event ); ++ break; + + default: + TRACE( "Unhandled event %#x\n", event->evtype ); +diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h +index 7145fec74e7..4a7cab67ada 100644 +--- a/dlls/winex11.drv/x11drv.h ++++ b/dlls/winex11.drv/x11drv.h +@@ -196,6 +196,8 @@ extern BOOL CDECL X11DRV_UnrealizePalette( HPALETTE hpal ) DECLSPEC_HIDDEN; + + extern void X11DRV_Xcursor_Init(void) DECLSPEC_HIDDEN; + extern void X11DRV_XInput2_Init(void) DECLSPEC_HIDDEN; ++extern void X11DRV_XInput2_Enable(void) DECLSPEC_HIDDEN; ++extern void X11DRV_XInput2_Disable(void) DECLSPEC_HIDDEN; + + extern DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image, + const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits, +@@ -343,6 +345,7 @@ struct x11drv_thread_data + struct x11drv_valuator_data x_rel_valuator; + struct x11drv_valuator_data y_rel_valuator; + int xi2_core_pointer; /* XInput2 core pointer id */ ++ int xi2_rawinput_only; + }; + + extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; +diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c +index ff9185a523c..f33a79d98bf 100644 +--- a/dlls/winex11.drv/x11drv_main.c ++++ b/dlls/winex11.drv/x11drv_main.c +@@ -640,6 +640,8 @@ void CDECL X11DRV_ThreadDetach(void) + + if (data) + { ++ if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId()) ++ X11DRV_XInput2_Disable(); + if (data->xim) XCloseIM( data->xim ); + if (data->font_set) XFreeFontSet( data->display, data->font_set ); + XCloseDisplay( data->display ); +@@ -712,6 +714,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) + TlsSetValue( thread_data_tls_index, data ); + + if (use_xim) X11DRV_SetupXIM(); ++ if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId()) ++ X11DRV_XInput2_Enable(); + + return data; + } +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse/0010-user32-Implement-GetRegisteredRawInputDevices.patch b/patches/user32-rawinput-mouse/0010-user32-Implement-GetRegisteredRawInputDevices.patch new file mode 100644 index 00000000..6a82f3cc --- /dev/null +++ b/patches/user32-rawinput-mouse/0010-user32-Implement-GetRegisteredRawInputDevices.patch @@ -0,0 +1,204 @@ +From d4dd0d48cec74bd2185eae5a6020c026040c1319 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Mon, 26 Aug 2019 16:06:58 +0200 +Subject: [PATCH 10/12] user32: Implement GetRegisteredRawInputDevices. + +--- + dlls/dinput8/tests/device.c | 13 --------- + dlls/user32/rawinput.c | 55 +++++++++++++++++++++++++++++++++++-- + server/protocol.def | 6 ++++ + server/queue.c | 24 ++++++++++++++++ + 4 files changed, 83 insertions(+), 15 deletions(-) + +diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c +index bec2a6b863c..45fc2889066 100644 +--- a/dlls/dinput8/tests/device.c ++++ b/dlls/dinput8/tests/device.c +@@ -652,7 +652,6 @@ static void test_mouse_keyboard(void) + + raw_devices_count = ARRAY_SIZE(raw_devices); + GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); +- todo_wine + ok(raw_devices_count == 0, "Unexpected raw devices registered: %d\n", raw_devices_count); + + hr = IDirectInputDevice8_Acquire(di_keyboard); +@@ -674,7 +673,6 @@ static void test_mouse_keyboard(void) + ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); + raw_devices_count = ARRAY_SIZE(raw_devices); + GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); +- todo_wine + ok(raw_devices_count == 0, "Unexpected raw devices registered: %d\n", raw_devices_count); + + if (raw_devices[0].hwndTarget != NULL) +@@ -712,7 +710,6 @@ static void test_mouse_keyboard(void) + ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); + raw_devices_count = ARRAY_SIZE(raw_devices); + GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); +- todo_wine + ok(raw_devices_count == 0, "Unexpected raw devices registered: %d\n", raw_devices_count); + + /* expect dinput8 to take over any activated raw input devices */ +@@ -739,26 +736,18 @@ static void test_mouse_keyboard(void) + raw_devices_count = ARRAY_SIZE(raw_devices); + memset(raw_devices, 0, sizeof(raw_devices)); + hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); +- todo_wine + ok(hr == 3, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); +- todo_wine + ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); +- todo_wine + ok(raw_devices[0].usUsage == 2, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); + todo_wine + ok(raw_devices[0].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); + todo_wine + ok(raw_devices[0].hwndTarget == di_hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); +- todo_wine + ok(raw_devices[1].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[1].usUsagePage); +- todo_wine + ok(raw_devices[1].usUsage == 5, "Unexpected raw device usage: %x\n", raw_devices[1].usUsage); + ok(raw_devices[1].dwFlags == 0, "Unexpected raw device flags: %x\n", raw_devices[1].dwFlags); +- todo_wine + ok(raw_devices[1].hwndTarget == hwnd, "Unexpected raw device target: %p\n", raw_devices[1].hwndTarget); +- todo_wine + ok(raw_devices[2].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[1].usUsagePage); +- todo_wine + ok(raw_devices[2].usUsage == 6, "Unexpected raw device usage: %x\n", raw_devices[1].usUsage); + todo_wine + ok(raw_devices[2].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[1].dwFlags); +@@ -777,12 +766,10 @@ static void test_mouse_keyboard(void) + hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); + todo_wine + ok(hr == 1, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); +- todo_wine + ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); + todo_wine + ok(raw_devices[0].usUsage == 5, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); + ok(raw_devices[0].dwFlags == 0, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); +- todo_wine + ok(raw_devices[0].hwndTarget == hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); + + IDirectInputDevice8_Release(di_mouse); +diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c +index 85ff0c5e809..3792360b057 100644 +--- a/dlls/user32/rawinput.c ++++ b/dlls/user32/rawinput.c +@@ -501,14 +501,65 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE device, UINT command, void *data, UINT + return *data_size; + } + ++static int compare_raw_input_devices(const void *ap, const void *bp) ++{ ++ const RAWINPUTDEVICE a = *(const RAWINPUTDEVICE *)ap; ++ const RAWINPUTDEVICE b = *(const RAWINPUTDEVICE *)bp; ++ ++ if (a.usUsagePage != b.usUsagePage) return a.usUsagePage - b.usUsagePage; ++ if (a.usUsage != b.usUsage) return a.usUsage - b.usUsage; ++ return 0; ++} ++ + /*********************************************************************** + * GetRegisteredRawInputDevices (USER32.@) + */ + UINT WINAPI DECLSPEC_HOTPATCH GetRegisteredRawInputDevices(RAWINPUTDEVICE *devices, UINT *device_count, UINT size) + { +- FIXME("devices %p, device_count %p, size %u stub!\n", devices, device_count, size); ++ struct rawinput_device *d = NULL; ++ unsigned int count = ~0U; + +- return 0; ++ TRACE("devices %p, device_count %p, size %u\n", devices, device_count, size); ++ ++ if (!device_count) ++ { ++ SetLastError(ERROR_INVALID_PARAMETER); ++ return ~0U; ++ } ++ ++ if (devices && !(d = HeapAlloc( GetProcessHeap(), 0, *device_count * sizeof(*d) ))) ++ return ~0U; ++ ++ SERVER_START_REQ( get_rawinput_devices ) ++ { ++ if (d) ++ wine_server_set_reply( req, d, *device_count * sizeof(*d) ); ++ ++ if (wine_server_call( req )) ++ goto done; ++ ++ if (!d || reply->device_count > *device_count) ++ { ++ *device_count = reply->device_count; ++ SetLastError( ERROR_INSUFFICIENT_BUFFER ); ++ goto done; ++ } ++ ++ for (count = 0; count < reply->device_count; ++count) ++ { ++ devices[count].usUsagePage = d[count].usage_page; ++ devices[count].usUsage = d[count].usage; ++ devices[count].dwFlags = d[count].flags; ++ devices[count].hwndTarget = wine_server_ptr_handle(d[count].target); ++ } ++ } ++ SERVER_END_REQ; ++ ++ qsort(devices, count, sizeof(*devices), compare_raw_input_devices); ++ ++done: ++ if (d) HeapFree( GetProcessHeap(), 0, d ); ++ return count; + } + + +diff --git a/server/protocol.def b/server/protocol.def +index 9f9f9197134..d37dceba40c 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3986,6 +3986,12 @@ struct handle_info + VARARG(devices,rawinput_devices); + @END + ++/* Retrieve the list of registered rawinput devices */ ++@REQ(get_rawinput_devices) ++@REPLY ++ unsigned int device_count; ++ VARARG(devices,rawinput_devices); ++@END + + /* Retrieve the suspended context of a thread */ + @REQ(get_suspend_context) +diff --git a/server/queue.c b/server/queue.c +index 2bdd099d1bb..8a1bbfff5aa 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -3382,3 +3382,27 @@ DECL_HANDLER(esync_msgwait) + if (current->process->idle_event && !(queue->wake_mask & QS_SMRESULT)) + set_event( current->process->idle_event ); + } ++ ++DECL_HANDLER(get_rawinput_devices) ++{ ++ unsigned int device_count = list_count(¤t->process->rawinput_devices); ++ struct rawinput_device *devices; ++ struct rawinput_device_entry *e; ++ unsigned int i; ++ ++ reply->device_count = device_count; ++ if (get_reply_max_size() / sizeof (*devices) < device_count) ++ return; ++ ++ if (!(devices = mem_alloc( device_count * sizeof (*devices) ))) ++ { ++ set_error( STATUS_NO_MEMORY ); ++ return; ++ } ++ ++ i = 0; ++ LIST_FOR_EACH_ENTRY( e, ¤t->process->rawinput_devices, struct rawinput_device_entry, entry ) ++ devices[i++] = e->device; ++ ++ set_reply_data_ptr( devices, device_count * sizeof (*devices) ); ++} +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse/0011-dinput8-Add-support-for-dinput-devices-that-use-raw-.patch b/patches/user32-rawinput-mouse/0011-dinput8-Add-support-for-dinput-devices-that-use-raw-.patch new file mode 100644 index 00000000..30409d35 --- /dev/null +++ b/patches/user32-rawinput-mouse/0011-dinput8-Add-support-for-dinput-devices-that-use-raw-.patch @@ -0,0 +1,174 @@ +From 7f814cd77f1766b98318bbc8ea5fff241c20ec4b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Mon, 26 Aug 2019 16:06:59 +0200 +Subject: [PATCH 11/12] dinput8: Add support for dinput devices that use raw + input interface. + +This adds a global message window that will receive WM_INPUT messages, +dispatched to every raw input device event_proc. + +Devices that use raw input interface will not register low-level hooks +anymore. They will also conflict with any raw input device registered +outside of dinput, as exposed by the unit tests. +--- + dlls/dinput/device_private.h | 3 ++ + dlls/dinput/dinput_main.c | 84 +++++++++++++++++++++++++++++++++++- + 2 files changed, 86 insertions(+), 1 deletion(-) + +diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h +index 114e3971ed8..9116aaeab66 100644 +--- a/dlls/dinput/device_private.h ++++ b/dlls/dinput/device_private.h +@@ -70,6 +70,9 @@ struct IDirectInputDeviceImpl + int acquired; + DI_EVENT_PROC event_proc; /* function to receive mouse & keyboard events */ + ++ BOOL use_raw_input; /* use raw input instead of low-level messages */ ++ RAWINPUTDEVICE raw_device; /* raw device to (un)register */ ++ + LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */ + int queue_len; /* size of the queue - set in 'SetProperty' */ + int queue_head; /* position to write new event into queue */ +diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c +index 4d2d4afe106..9e3b9f48250 100644 +--- a/dlls/dinput/dinput_main.c ++++ b/dlls/dinput/dinput_main.c +@@ -98,6 +98,10 @@ static const struct dinput_device *dinput_devices[] = + + HINSTANCE DINPUT_instance; + ++static ATOM di_em_win_class; ++static const WCHAR di_em_winW[] = {'D','I','E','m','W','i','n',0}; ++static HWND di_em_win; ++ + static BOOL check_hook_thread(void); + static CRITICAL_SECTION dinput_hook_crit; + static struct list direct_input_list = LIST_INIT( direct_input_list ); +@@ -626,6 +630,59 @@ static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, RE + return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj ); + } + ++static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) ++{ ++ IDirectInputImpl *dinput; ++ ++ TRACE( "%p %d %lx %lx\n", hwnd, msg, wparam, lparam ); ++ ++ if (msg == WM_INPUT) ++ { ++ EnterCriticalSection( &dinput_hook_crit ); ++ LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry ) ++ { ++ IDirectInputDeviceImpl *dev; ++ ++ EnterCriticalSection( &dinput->crit ); ++ LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry ) ++ { ++ if (dev->acquired && dev->event_proc && dev->use_raw_input) ++ { ++ TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam); ++ dev->event_proc( &dev->IDirectInputDevice8A_iface, GET_RAWINPUT_CODE_WPARAM(wparam), lparam ); ++ } ++ } ++ LeaveCriticalSection( &dinput->crit ); ++ } ++ LeaveCriticalSection( &dinput_hook_crit ); ++ } ++ ++ return DefWindowProcW(hwnd, msg, wparam, lparam); ++} ++ ++static void register_di_em_win_class(void) ++{ ++ static WNDCLASSEXW class; ++ ++ ZeroMemory(&class, sizeof(class)); ++ class.cbSize = sizeof(class); ++ class.lpfnWndProc = di_em_win_wndproc; ++ class.hInstance = DINPUT_instance; ++ class.lpszClassName = di_em_winW; ++ ++ if (!(di_em_win_class = RegisterClassExW( &class ))) ++ WARN( "Unable to register message window class\n" ); ++} ++ ++static void unregister_di_em_win_class(void) ++{ ++ if (!di_em_win_class) ++ return; ++ ++ if (!UnregisterClassW( MAKEINTRESOURCEW( di_em_win_class ), DINPUT_instance )) ++ WARN( "Unable to unregister message window class\n" ); ++} ++ + static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion) + { + if (!This->initialized) +@@ -1695,7 +1752,7 @@ static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam ) + + EnterCriticalSection( &dinput->crit ); + LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry ) +- if (dev->acquired && dev->event_proc) ++ if (dev->acquired && dev->event_proc && !dev->use_raw_input) + { + TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam); + skip |= dev->event_proc( &dev->IDirectInputDevice8A_iface, wparam, lparam ); +@@ -1748,6 +1805,9 @@ static DWORD WINAPI hook_thread_proc(void *param) + static HHOOK kbd_hook, mouse_hook; + MSG msg; + ++ di_em_win = CreateWindowW( MAKEINTRESOURCEW(di_em_win_class), di_em_winW, ++ 0, 0, 0, 0, 0, HWND_MESSAGE, 0, DINPUT_instance, NULL ); ++ + /* Force creation of the message queue */ + PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ); + SetEvent(param); +@@ -1812,6 +1872,9 @@ static DWORD WINAPI hook_thread_proc(void *param) + DispatchMessageW(&msg); + } + ++ DestroyWindow( di_em_win ); ++ di_em_win = NULL; ++ + FreeLibraryAndExitThread(DINPUT_instance, 0); + } + +@@ -1893,6 +1956,23 @@ void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface, BOOL acquired) + hook_thread_event = NULL; + } + ++ if (dev->use_raw_input) ++ { ++ if (acquired) ++ { ++ dev->raw_device.dwFlags = RIDEV_INPUTSINK; ++ dev->raw_device.hwndTarget = di_em_win; ++ } ++ else ++ { ++ dev->raw_device.dwFlags = RIDEV_REMOVE; ++ dev->raw_device.hwndTarget = NULL; ++ } ++ ++ if (!RegisterRawInputDevices( &dev->raw_device, 1, sizeof(RAWINPUTDEVICE) )) ++ WARN( "Unable to (un)register raw device %x:%x\n", dev->raw_device.usUsagePage, dev->raw_device.usUsage ); ++ } ++ + PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, 0 ); + + LeaveCriticalSection(&dinput_hook_crit); +@@ -1919,9 +1999,11 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved) + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(inst); + DINPUT_instance = inst; ++ register_di_em_win_class(); + break; + case DLL_PROCESS_DETACH: + if (reserved) break; ++ unregister_di_em_win_class(); + DeleteCriticalSection(&dinput_hook_crit); + break; + } +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse/0012-dinput8-Use-raw-input-interface-for-dinput8-mouse-de.patch b/patches/user32-rawinput-mouse/0012-dinput8-Use-raw-input-interface-for-dinput8-mouse-de.patch new file mode 100644 index 00000000..c45633eb --- /dev/null +++ b/patches/user32-rawinput-mouse/0012-dinput8-Use-raw-input-interface-for-dinput8-mouse-de.patch @@ -0,0 +1,195 @@ +From 4994e308b4f1e21c0d84de23df8c655c4bc5bf9f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Mon, 26 Aug 2019 14:08:20 +0200 +Subject: [PATCH 12/12] dinput8: Use raw input interface for dinput8 mouse + device. + +--- + dlls/dinput/mouse.c | 117 +++++++++++++++++++++++++++++++++++- + dlls/dinput8/tests/device.c | 10 +-- + 2 files changed, 119 insertions(+), 8 deletions(-) + +diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c +index 2e0101facec..b8b88f38c15 100644 +--- a/dlls/dinput/mouse.c ++++ b/dlls/dinput/mouse.c +@@ -246,6 +246,13 @@ static SysMouseImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput) + list_add_tail(&dinput->devices_list, &newDevice->base.entry); + LeaveCriticalSection(&dinput->crit); + ++ if (dinput->dwVersion >= 0x0800) ++ { ++ newDevice->base.use_raw_input = TRUE; ++ newDevice->base.raw_device.usUsagePage = 1; /* HID generic device page */ ++ newDevice->base.raw_device.usUsage = 2; /* HID generic mouse */ ++ } ++ + return newDevice; + + failed: +@@ -318,7 +325,115 @@ static int dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM + { + MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; + SysMouseImpl* This = impl_from_IDirectInputDevice8A(iface); +- int wdata = 0, inst_id = -1, ret = 0; ++ int wdata = 0, inst_id = -1, ret = 0, i; ++ ++ if (wparam == RIM_INPUT || wparam == RIM_INPUTSINK) ++ { ++ RAWINPUTHEADER raw_header; ++ RAWINPUT raw_input; ++ UINT size; ++ POINT rel, pt; ++ ++ static const USHORT mouse_button_flags[] = ++ { ++ RI_MOUSE_BUTTON_1_DOWN, RI_MOUSE_BUTTON_1_UP, ++ RI_MOUSE_BUTTON_2_DOWN, RI_MOUSE_BUTTON_2_UP, ++ RI_MOUSE_BUTTON_3_DOWN, RI_MOUSE_BUTTON_3_UP, ++ RI_MOUSE_BUTTON_4_DOWN, RI_MOUSE_BUTTON_4_UP, ++ RI_MOUSE_BUTTON_5_DOWN, RI_MOUSE_BUTTON_5_UP ++ }; ++ ++ TRACE("(%p) wp %08lx, lp %08lx\n", iface, wparam, lparam); ++ ++ size = sizeof(raw_header); ++ if (GetRawInputData( (HRAWINPUT)lparam, RID_HEADER, &raw_header, &size, sizeof(RAWINPUTHEADER) ) != sizeof(raw_header)) ++ { ++ WARN( "Unable to read raw input data header\n" ); ++ return 0; ++ } ++ ++ if (raw_header.dwType != RIM_TYPEMOUSE) ++ return 0; ++ ++ if (raw_header.dwSize > sizeof(raw_input)) ++ { ++ WARN( "Unexpected size for mouse raw input data\n" ); ++ return 0; ++ } ++ ++ size = raw_header.dwSize; ++ if (GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, &raw_input, &size, sizeof(RAWINPUTHEADER) ) != raw_header.dwSize ) ++ { ++ WARN( "Unable to read raw input data\n" ); ++ return 0; ++ } ++ ++ if (raw_input.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) ++ FIXME( "Unimplemented MOUSE_VIRTUAL_DESKTOP flag\n" ); ++ if (raw_input.data.mouse.usFlags & MOUSE_ATTRIBUTES_CHANGED) ++ FIXME( "Unimplemented MOUSE_ATTRIBUTES_CHANGED flag\n" ); ++ ++ EnterCriticalSection(&This->base.crit); ++ ++ rel.x = raw_input.data.mouse.lLastX; ++ rel.y = raw_input.data.mouse.lLastY; ++ if (raw_input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) ++ { ++ GetCursorPos(&pt); ++ rel.x -= pt.x; ++ rel.y -= pt.y; ++ } ++ ++ This->m_state.lX += rel.x; ++ This->m_state.lY += rel.y; ++ ++ if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS) ++ { ++ pt.x = This->m_state.lX; ++ pt.y = This->m_state.lY; ++ } ++ else ++ { ++ pt = rel; ++ } ++ ++ if (rel.x) ++ queue_event(iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, ++ pt.x, GetCurrentTime(), This->base.dinput->evsequence); ++ ++ if (rel.y) ++ queue_event(iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, ++ pt.y, GetCurrentTime(), This->base.dinput->evsequence); ++ ++ if (rel.x || rel.y) ++ { ++ if ((This->warp_override == WARP_FORCE_ON) || ++ (This->warp_override != WARP_DISABLE && (This->base.dwCoopLevel & DISCL_EXCLUSIVE))) ++ This->need_warp = TRUE; ++ } ++ ++ if (raw_input.data.mouse.usButtonFlags & RI_MOUSE_WHEEL) ++ { ++ This->m_state.lZ += (wdata = (SHORT)raw_input.data.mouse.usButtonData); ++ queue_event(iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS, ++ wdata, GetCurrentTime(), This->base.dinput->evsequence); ++ ret = This->clipped; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(mouse_button_flags); ++i) ++ { ++ if (raw_input.data.mouse.usButtonFlags & mouse_button_flags[i]) ++ { ++ This->m_state.rgbButtons[i / 2] = 0x80 - (i % 2) * 0x80; ++ queue_event(iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + (i / 2)) | DIDFT_PSHBUTTON, ++ This->m_state.rgbButtons[i / 2], GetCurrentTime(), This->base.dinput->evsequence); ++ } ++ } ++ ++ LeaveCriticalSection(&This->base.crit); ++ ++ return ret; ++ } + + TRACE("msg %lx @ (%d %d)\n", wparam, hook->pt.x, hook->pt.y); + +diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c +index 45fc2889066..42ba78707c6 100644 +--- a/dlls/dinput8/tests/device.c ++++ b/dlls/dinput8/tests/device.c +@@ -696,13 +696,9 @@ static void test_mouse_keyboard(void) + raw_devices_count = ARRAY_SIZE(raw_devices); + memset(raw_devices, 0, sizeof(raw_devices)); + hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); +- todo_wine + ok(hr == 1, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); +- todo_wine + ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); +- todo_wine + ok(raw_devices[0].usUsage == 2, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); +- todo_wine + ok(raw_devices[0].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); + todo_wine + ok(raw_devices[0].hwndTarget == di_hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); +@@ -712,6 +708,9 @@ static void test_mouse_keyboard(void) + GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); + ok(raw_devices_count == 0, "Unexpected raw devices registered: %d\n", raw_devices_count); + ++ if (raw_devices[0].hwndTarget != NULL) ++ di_hwnd = raw_devices[0].hwndTarget; ++ + /* expect dinput8 to take over any activated raw input devices */ + raw_devices[0].usUsagePage = 0x01; + raw_devices[0].usUsage = 0x05; +@@ -739,9 +738,7 @@ static void test_mouse_keyboard(void) + ok(hr == 3, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); + ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); + ok(raw_devices[0].usUsage == 2, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); +- todo_wine + ok(raw_devices[0].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); +- todo_wine + ok(raw_devices[0].hwndTarget == di_hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); + ok(raw_devices[1].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[1].usUsagePage); + ok(raw_devices[1].usUsage == 5, "Unexpected raw device usage: %x\n", raw_devices[1].usUsage); +@@ -767,7 +764,6 @@ static void test_mouse_keyboard(void) + todo_wine + ok(hr == 1, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); + ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); +- todo_wine + ok(raw_devices[0].usUsage == 5, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); + ok(raw_devices[0].dwFlags == 0, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); + ok(raw_devices[0].hwndTarget == hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); +-- +2.24.1 + diff --git a/patches/user32-rawinput-mouse/definition b/patches/user32-rawinput-mouse/definition new file mode 100644 index 00000000..c4766fcc --- /dev/null +++ b/patches/user32-rawinput-mouse/definition @@ -0,0 +1,2 @@ +Fixes: [42631] - user32: Add Raw Input support. +Depends: winex11.drv-mouse-coorrds diff --git a/patches/user32-rawinput-nolegacy/0001-dinput8-tests-Add-test-for-DISCL_EXCLUSIVE-flag-inte.patch b/patches/user32-rawinput-nolegacy/0001-dinput8-tests-Add-test-for-DISCL_EXCLUSIVE-flag-inte.patch new file mode 100644 index 00000000..0f0dc233 --- /dev/null +++ b/patches/user32-rawinput-nolegacy/0001-dinput8-tests-Add-test-for-DISCL_EXCLUSIVE-flag-inte.patch @@ -0,0 +1,44 @@ +From a4256a564e309ad44a8aa8e8571c69444de20bf9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 19 Dec 2019 19:00:21 +0100 +Subject: [PATCH 1/4] dinput8/tests: Add test for DISCL_EXCLUSIVE flag + interaction with rawinput. + +--- + dlls/dinput8/tests/device.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c +index 42ba78707c6..845146af023 100644 +--- a/dlls/dinput8/tests/device.c ++++ b/dlls/dinput8/tests/device.c +@@ -759,6 +759,26 @@ static void test_mouse_keyboard(void) + todo_wine + ok(raw_devices_count == 1, "Unexpected raw devices registered: %d\n", raw_devices_count); + ++ IDirectInputDevice8_SetCooperativeLevel(di_mouse, hwnd, DISCL_FOREGROUND|DISCL_EXCLUSIVE); ++ IDirectInputDevice8_SetCooperativeLevel(di_keyboard, hwnd, DISCL_FOREGROUND|DISCL_EXCLUSIVE); ++ ++ hr = IDirectInputDevice8_Acquire(di_keyboard); ++ ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); ++ hr = IDirectInputDevice8_Acquire(di_mouse); ++ ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); ++ raw_devices_count = ARRAY_SIZE(raw_devices); ++ memset(raw_devices, 0, sizeof(raw_devices)); ++ hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); ++ ok(hr == 3, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); ++ todo_wine ++ ok(raw_devices[0].dwFlags == (RIDEV_CAPTUREMOUSE|RIDEV_NOLEGACY), "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); ++ todo_wine ++ ok(raw_devices[2].dwFlags == (RIDEV_NOHOTKEYS|RIDEV_NOLEGACY), "Unexpected raw device flags: %x\n", raw_devices[1].dwFlags); ++ hr = IDirectInputDevice8_Unacquire(di_keyboard); ++ ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); ++ hr = IDirectInputDevice8_Unacquire(di_mouse); ++ ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); ++ + raw_devices_count = ARRAY_SIZE(raw_devices); + hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); + todo_wine +-- +2.24.1 + diff --git a/patches/user32-rawinput-nolegacy/0002-user32-Add-support-for-RIDEV_NOLEGACY-flag-in-Regist.patch b/patches/user32-rawinput-nolegacy/0002-user32-Add-support-for-RIDEV_NOLEGACY-flag-in-Regist.patch new file mode 100644 index 00000000..eb60f08b --- /dev/null +++ b/patches/user32-rawinput-nolegacy/0002-user32-Add-support-for-RIDEV_NOLEGACY-flag-in-Regist.patch @@ -0,0 +1,75 @@ +From c39bb27347442d2d229d6e851c17094c086411d6 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Tue, 25 Jun 2019 16:23:02 -0400 +Subject: [PATCH 2/4] user32: Add support for RIDEV_NOLEGACY flag in + RegisterRawInputDevices. + +--- + dlls/user32/rawinput.c | 2 +- + server/queue.c | 9 +++++++++ + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c +index 3792360b057..8cf9f8ebf62 100644 +--- a/dlls/user32/rawinput.c ++++ b/dlls/user32/rawinput.c +@@ -283,7 +283,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U + TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n", + i, devices[i].usUsagePage, devices[i].usUsage, + devices[i].dwFlags, devices[i].hwndTarget); +- if (devices[i].dwFlags & ~RIDEV_REMOVE) ++ if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY)) + FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i); + + d[i].usage_page = devices[i].usUsagePage; +diff --git a/server/queue.c b/server/queue.c +index 8a1bbfff5aa..f5dc06100d1 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -427,6 +427,9 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) + static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; + struct message *msg; + ++ if (current->process->rawinput_mouse && ++ current->process->rawinput_mouse->flags & RIDEV_NOLEGACY) return; ++ + if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return; + + msg->msg = WM_MOUSEMOVE; +@@ -1793,6 +1796,7 @@ done: + static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, + unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) + { ++ const struct rawinput_device *device; + struct hardware_msg_data *msg_data; + struct rawinput_message raw_msg; + struct message *msg; +@@ -1866,6 +1870,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons + + if (!(req_flags & SEND_HWMSG_WINDOW)) + return 0; ++ if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) ++ return 0; + + for (i = 0; i < ARRAY_SIZE( messages ); i++) + { +@@ -1901,6 +1907,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c + unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) + { + struct hw_msg_source source = { IMDT_KEYBOARD, origin }; ++ const struct rawinput_device *device; + struct hardware_msg_data *msg_data; + struct rawinput_message raw_msg; + struct message *msg; +@@ -1996,6 +2003,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c + + if (!(req_flags & SEND_HWMSG_WINDOW)) + return 0; ++ if ((device = current->process->rawinput_kbd) && (device->flags & RIDEV_NOLEGACY)) ++ return 0; + + if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; + msg_data = msg->data; +-- +2.24.1 + diff --git a/patches/user32-rawinput-nolegacy/0003-dinput-Set-RIDEV_INPUTSINK-flag-only-when-DISCL_BACK.patch b/patches/user32-rawinput-nolegacy/0003-dinput-Set-RIDEV_INPUTSINK-flag-only-when-DISCL_BACK.patch new file mode 100644 index 00000000..f842e575 --- /dev/null +++ b/patches/user32-rawinput-nolegacy/0003-dinput-Set-RIDEV_INPUTSINK-flag-only-when-DISCL_BACK.patch @@ -0,0 +1,28 @@ +From 1372e0e8582eeb423aa65deab17c52f4f5e153d0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 19 Dec 2019 19:00:50 +0100 +Subject: [PATCH 3/4] dinput: Set RIDEV_INPUTSINK flag only when + DISCL_BACKGROUND is requested. + +--- + dlls/dinput/dinput_main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c +index 9e3b9f48250..ef92a7d7c50 100644 +--- a/dlls/dinput/dinput_main.c ++++ b/dlls/dinput/dinput_main.c +@@ -1960,7 +1960,9 @@ void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface, BOOL acquired) + { + if (acquired) + { +- dev->raw_device.dwFlags = RIDEV_INPUTSINK; ++ dev->raw_device.dwFlags = 0; ++ if (dev->dwCoopLevel & DISCL_BACKGROUND) ++ dev->raw_device.dwFlags |= RIDEV_INPUTSINK; + dev->raw_device.hwndTarget = di_em_win; + } + else +-- +2.24.1 + diff --git a/patches/user32-rawinput-nolegacy/0004-dinput-Set-correct-rawinput-flags-for-DISCL_EXCLUSIV.patch b/patches/user32-rawinput-nolegacy/0004-dinput-Set-correct-rawinput-flags-for-DISCL_EXCLUSIV.patch new file mode 100644 index 00000000..fcd8a948 --- /dev/null +++ b/patches/user32-rawinput-nolegacy/0004-dinput-Set-correct-rawinput-flags-for-DISCL_EXCLUSIV.patch @@ -0,0 +1,40 @@ +From 68898282e49228e9a26328373b4cd661a86d7672 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 19 Dec 2019 19:30:49 +0100 +Subject: [PATCH 4/4] dinput: Set correct rawinput flags for DISCL_EXCLUSIVE. + +--- + dlls/dinput/dinput_main.c | 4 ++++ + dlls/dinput8/tests/device.c | 1 - + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c +index ef92a7d7c50..6a74b6da500 100644 +--- a/dlls/dinput/dinput_main.c ++++ b/dlls/dinput/dinput_main.c +@@ -1963,6 +1963,10 @@ void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface, BOOL acquired) + dev->raw_device.dwFlags = 0; + if (dev->dwCoopLevel & DISCL_BACKGROUND) + dev->raw_device.dwFlags |= RIDEV_INPUTSINK; ++ if ((dev->dwCoopLevel & DISCL_EXCLUSIVE) && dev->raw_device.usUsage == 2) ++ dev->raw_device.dwFlags |= (RIDEV_CAPTUREMOUSE|RIDEV_NOLEGACY); ++ if ((dev->dwCoopLevel & DISCL_EXCLUSIVE) && dev->raw_device.usUsage == 6) ++ dev->raw_device.dwFlags |= (RIDEV_NOHOTKEYS|RIDEV_NOLEGACY); + dev->raw_device.hwndTarget = di_em_win; + } + else +diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c +index 845146af023..31220db220a 100644 +--- a/dlls/dinput8/tests/device.c ++++ b/dlls/dinput8/tests/device.c +@@ -770,7 +770,6 @@ static void test_mouse_keyboard(void) + memset(raw_devices, 0, sizeof(raw_devices)); + hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); + ok(hr == 3, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); +- todo_wine + ok(raw_devices[0].dwFlags == (RIDEV_CAPTUREMOUSE|RIDEV_NOLEGACY), "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); + todo_wine + ok(raw_devices[2].dwFlags == (RIDEV_NOHOTKEYS|RIDEV_NOLEGACY), "Unexpected raw device flags: %x\n", raw_devices[1].dwFlags); +-- +2.24.1 + diff --git a/patches/user32-rawinput-nolegacy/definition b/patches/user32-rawinput-nolegacy/definition new file mode 100644 index 00000000..efc2784e --- /dev/null +++ b/patches/user32-rawinput-nolegacy/definition @@ -0,0 +1 @@ +Depends: user32-rawinput-mouse diff --git a/patches/user32-rawinput/0001-user32-Add-support-for-RIDEV_NOLEGACY-flag.patch b/patches/user32-rawinput/0001-user32-Add-support-for-RIDEV_NOLEGACY-flag.patch deleted file mode 100644 index a65b337c..00000000 --- a/patches/user32-rawinput/0001-user32-Add-support-for-RIDEV_NOLEGACY-flag.patch +++ /dev/null @@ -1,61 +0,0 @@ -From c91add917b374a1dd98f07d4d3647295d4fd7f20 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 25 Jun 2019 16:23:02 -0400 -Subject: [PATCH 01/11] user32: Add support for RIDEV_NOLEGACY flag. - -Signed-off-by: Derek Lesho ---- - dlls/user32/rawinput.c | 2 +- - server/queue.c | 9 +++++++++ - 2 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c -index 94cf7a9a5d..661a0e3b25 100644 ---- a/dlls/user32/rawinput.c -+++ b/dlls/user32/rawinput.c -@@ -282,7 +282,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U - TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n", - i, devices[i].usUsagePage, devices[i].usUsage, - devices[i].dwFlags, devices[i].hwndTarget); -- if (devices[i].dwFlags & ~RIDEV_REMOVE) -+ if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY)) - FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i); - - d[i].usage_page = devices[i].usUsagePage; -diff --git a/server/queue.c b/server/queue.c -index b5e17be18f..7c3c7e5148 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -372,6 +372,9 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) - static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; - struct message *msg; - -+ if (current->process->rawinput_mouse && -+ current->process->rawinput_mouse->flags & RIDEV_NOLEGACY) return; -+ - if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return; - - msg->msg = WM_MOUSEMOVE; -@@ -1670,6 +1673,9 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons - queue_hardware_message( desktop, msg, 0 ); - } - -+ if (device && device->flags & RIDEV_NOLEGACY) -+ return FALSE; -+ - for (i = 0; i < ARRAY_SIZE( messages ); i++) - { - if (!messages[i]) continue; -@@ -1795,6 +1801,9 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c - queue_hardware_message( desktop, msg, 0 ); - } - -+ if (device && device->flags & RIDEV_NOLEGACY) -+ return FALSE; -+ - if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; - msg_data = msg->data; - --- -2.23.0 - diff --git a/patches/user32-rawinput/0002-server-Move-mouse-raw-input-message-faking-from-user.patch b/patches/user32-rawinput/0002-server-Move-mouse-raw-input-message-faking-from-user.patch deleted file mode 100644 index 767fe77e..00000000 --- a/patches/user32-rawinput/0002-server-Move-mouse-raw-input-message-faking-from-user.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 107e1c0afb7e4a6639726891df26a724ffda5f1e Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 25 Jun 2019 20:47:20 -0400 -Subject: [PATCH 02/11] server: Move mouse raw-input message faking from user32 - to wineserver. - -Signed-off-by: Derek Lesho ---- - dlls/user32/message.c | 46 +++---------------------------------------- - server/protocol.def | 9 +++++---- - server/queue.c | 46 +++++++++++++++++++++++++++++++++++++++++-- - 3 files changed, 52 insertions(+), 49 deletions(-) - -diff --git a/dlls/user32/message.c b/dlls/user32/message.c -index 1336865112..cf0fbe2f0c 100644 ---- a/dlls/user32/message.c -+++ b/dlls/user32/message.c -@@ -2295,54 +2295,14 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data * - rawinput->header.dwType = msg_data->rawinput.type; - if (msg_data->rawinput.type == RIM_TYPEMOUSE) - { -- static const unsigned int button_flags[] = -- { -- 0, /* MOUSEEVENTF_MOVE */ -- RI_MOUSE_LEFT_BUTTON_DOWN, /* MOUSEEVENTF_LEFTDOWN */ -- RI_MOUSE_LEFT_BUTTON_UP, /* MOUSEEVENTF_LEFTUP */ -- RI_MOUSE_RIGHT_BUTTON_DOWN, /* MOUSEEVENTF_RIGHTDOWN */ -- RI_MOUSE_RIGHT_BUTTON_UP, /* MOUSEEVENTF_RIGHTUP */ -- RI_MOUSE_MIDDLE_BUTTON_DOWN, /* MOUSEEVENTF_MIDDLEDOWN */ -- RI_MOUSE_MIDDLE_BUTTON_UP, /* MOUSEEVENTF_MIDDLEUP */ -- }; -- unsigned int i; -- - rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWMOUSE); - rawinput->header.hDevice = WINE_MOUSE_HANDLE; - rawinput->header.wParam = 0; - - rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE; -- rawinput->data.mouse.u.s.usButtonFlags = 0; -- rawinput->data.mouse.u.s.usButtonData = 0; -- for (i = 1; i < ARRAY_SIZE(button_flags); ++i) -- { -- if (msg_data->flags & (1 << i)) -- rawinput->data.mouse.u.s.usButtonFlags |= button_flags[i]; -- } -- if (msg_data->flags & MOUSEEVENTF_WHEEL) -- { -- rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_WHEEL; -- rawinput->data.mouse.u.s.usButtonData = msg_data->rawinput.mouse.data; -- } -- if (msg_data->flags & MOUSEEVENTF_HWHEEL) -- { -- rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_HORIZONTAL_WHEEL; -- rawinput->data.mouse.u.s.usButtonData = msg_data->rawinput.mouse.data; -- } -- if (msg_data->flags & MOUSEEVENTF_XDOWN) -- { -- if (msg_data->rawinput.mouse.data == XBUTTON1) -- rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_BUTTON_4_DOWN; -- else if (msg_data->rawinput.mouse.data == XBUTTON2) -- rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_BUTTON_5_DOWN; -- } -- if (msg_data->flags & MOUSEEVENTF_XUP) -- { -- if (msg_data->rawinput.mouse.data == XBUTTON1) -- rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_BUTTON_4_UP; -- else if (msg_data->rawinput.mouse.data == XBUTTON2) -- rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_BUTTON_5_UP; -- } -+ -+ rawinput->data.mouse.u.s.usButtonFlags = msg_data->rawinput.mouse.button_flags; -+ rawinput->data.mouse.u.s.usButtonData = msg_data->rawinput.mouse.button_data; - - rawinput->data.mouse.ulRawButtons = 0; - rawinput->data.mouse.lLastX = msg_data->rawinput.mouse.x; -diff --git a/server/protocol.def b/server/protocol.def -index 6af0ae0cff..7346e6aa44 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -304,10 +304,11 @@ struct hardware_msg_data - } kbd; - struct - { -- int type; /* RIM_TYPEMOUSE */ -- int x; /* x coordinate */ -- int y; /* y coordinate */ -- unsigned int data; /* mouse data */ -+ int type; /* RIM_TYPEMOUSE */ -+ int x; /* x coordinate */ -+ int y; /* y coordinate */ -+ unsigned short button_flags; /* mouse button */ -+ unsigned short button_data; /* event details */ - } mouse; - } rawinput; - }; -diff --git a/server/queue.c b/server/queue.c -index 7c3c7e5148..a85bb15227 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -1627,6 +1627,16 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons - WM_MOUSEHWHEEL /* 0x1000 = MOUSEEVENTF_HWHEEL */ - }; - -+ static const unsigned int raw_button_flags[] = { -+ 0, /* 0x0001 = MOUSEEVENTF_MOVE */ -+ RI_MOUSE_LEFT_BUTTON_DOWN, /* 0x0002 = MOUSEEVENTF_LEFTDOWN */ -+ RI_MOUSE_LEFT_BUTTON_UP, /* 0x0004 = MOUSEEVENTF_LEFTUP */ -+ RI_MOUSE_RIGHT_BUTTON_DOWN, /* 0x0008 = MOUSEEVENTF_RIGHTDOWN */ -+ RI_MOUSE_RIGHT_BUTTON_UP, /* 0x0010 = MOUSEEVENTF_RIGHTUP */ -+ RI_MOUSE_MIDDLE_BUTTON_DOWN, /* 0x0020 = MOUSEEVENTF_MIDDLEDOWN */ -+ RI_MOUSE_MIDDLE_BUTTON_UP, /* 0x0040 = MOUSEEVENTF_MIDDLEUP */ -+ }; -+ - desktop->cursor.last_change = get_tick_count(); - flags = input->mouse.flags; - time = input->mouse.time; -@@ -1664,11 +1674,43 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons - msg->wparam = RIM_INPUT; - msg->lparam = 0; - -- msg_data->flags = flags; -+ msg_data->flags = 0; - msg_data->rawinput.type = RIM_TYPEMOUSE; - msg_data->rawinput.mouse.x = x - desktop->cursor.x; - msg_data->rawinput.mouse.y = y - desktop->cursor.y; -- msg_data->rawinput.mouse.data = input->mouse.data; -+ msg_data->rawinput.mouse.button_flags = 0; -+ msg_data->rawinput.mouse.button_data = 0; -+ -+ for (i = 1; i < ARRAY_SIZE(raw_button_flags); ++i) -+ { -+ if (flags & (1 << i)) -+ msg_data->rawinput.mouse.button_flags |= raw_button_flags[i]; -+ } -+ -+ if (flags & MOUSEEVENTF_WHEEL) -+ { -+ msg_data->rawinput.mouse.button_flags |= RI_MOUSE_WHEEL; -+ msg_data->rawinput.mouse.button_data = input->mouse.data; -+ } -+ if (flags & MOUSEEVENTF_HWHEEL) -+ { -+ msg_data->rawinput.mouse.button_flags |= RI_MOUSE_HORIZONTAL_WHEEL; -+ msg_data->rawinput.mouse.button_data = input->mouse.data; -+ } -+ if (flags & MOUSEEVENTF_XDOWN) -+ { -+ if (input->mouse.data == XBUTTON1) -+ msg_data->rawinput.mouse.button_flags |= RI_MOUSE_BUTTON_4_DOWN; -+ else if (input->mouse.data == XBUTTON2) -+ msg_data->rawinput.mouse.button_flags |= RI_MOUSE_BUTTON_5_DOWN; -+ } -+ if (flags & MOUSEEVENTF_XUP) -+ { -+ if (input->mouse.data == XBUTTON1) -+ msg_data->rawinput.mouse.button_flags |= RI_MOUSE_BUTTON_4_UP; -+ else if (input->mouse.data == XBUTTON2) -+ msg_data->rawinput.mouse.button_flags |= RI_MOUSE_BUTTON_5_UP; -+ } - - queue_hardware_message( desktop, msg, 0 ); - } --- -2.23.0 - diff --git a/patches/user32-rawinput/0003-server-Add-request-for-sending-native-raw-input-mess.patch b/patches/user32-rawinput/0003-server-Add-request-for-sending-native-raw-input-mess.patch deleted file mode 100644 index de596a84..00000000 --- a/patches/user32-rawinput/0003-server-Add-request-for-sending-native-raw-input-mess.patch +++ /dev/null @@ -1,210 +0,0 @@ -From 3757f19f58dcbf11648d602212f412d29dc37750 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 25 Jun 2019 21:24:12 -0400 -Subject: [PATCH 03/11] server: Add request for sending native raw-input - messages. - -Signed-off-by: Derek Lesho ---- - dlls/user32/message.c | 2 +- - server/protocol.def | 51 +++++++++++++++++++++++++++---------------- - server/queue.c | 49 +++++++++++++++++++++++++++++++++++++++++ - server/trace.c | 21 ++++++++++++++++++ - tools/make_requests | 1 + - 5 files changed, 104 insertions(+), 20 deletions(-) - -diff --git a/dlls/user32/message.c b/dlls/user32/message.c -index cf0fbe2f0c..98d2c1d2c2 100644 ---- a/dlls/user32/message.c -+++ b/dlls/user32/message.c -@@ -2299,7 +2299,7 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data * - rawinput->header.hDevice = WINE_MOUSE_HANDLE; - rawinput->header.wParam = 0; - -- rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE; -+ rawinput->data.mouse.usFlags = msg_data->rawinput.mouse.flags; - - rawinput->data.mouse.u.s.usButtonFlags = msg_data->rawinput.mouse.button_flags; - rawinput->data.mouse.u.s.usButtonData = msg_data->rawinput.mouse.button_data; -diff --git a/server/protocol.def b/server/protocol.def -index 7346e6aa44..451c9253ee 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -286,31 +286,39 @@ struct hw_msg_source - unsigned int origin; /* source origin (IMO_* values) */ - }; - -+typedef union -+{ -+ int type; -+ struct -+ { -+ int type; /* RIM_TYPEKEYBOARD */ -+ unsigned int message; /* message generated by this rawinput event */ -+ unsigned short vkey; /* virtual key code */ -+ unsigned short scan; /* scan code */ -+ } kbd; -+ struct -+ { -+ int type; /* RIM_TYPEMOUSE */ -+ unsigned short flags; /* event flags */ -+ int x; /* x coordinate */ -+ int y; /* y coordinate */ -+ unsigned short button_flags; /* mouse button */ -+ unsigned short button_data; /* event details */ -+ } mouse; -+ struct -+ { -+ int type; /* RIM_TYPEHID */ -+ /* TODO: fill this in if/when necessary */ -+ } hid; -+} hw_rawinput_t; -+ - struct hardware_msg_data - { - lparam_t info; /* extra info */ - unsigned int hw_id; /* unique id */ - unsigned int flags; /* hook flags */ - struct hw_msg_source source; /* message source */ -- union -- { -- int type; -- struct -- { -- int type; /* RIM_TYPEKEYBOARD */ -- unsigned int message; /* message generated by this rawinput event */ -- unsigned short vkey; /* virtual key code */ -- unsigned short scan; /* scan code */ -- } kbd; -- struct -- { -- int type; /* RIM_TYPEMOUSE */ -- int x; /* x coordinate */ -- int y; /* y coordinate */ -- unsigned short button_flags; /* mouse button */ -- unsigned short button_data; /* event details */ -- } mouse; -- } rawinput; -+ hw_rawinput_t rawinput; - }; - - struct callback_msg_data -@@ -2318,6 +2326,11 @@ enum message_type - #define SEND_HWMSG_INJECTED 0x01 - - -+@REQ(send_rawinput_message) -+ hw_rawinput_t input; -+@END -+ -+ - /* Get a message from the current queue */ - @REQ(get_message) - unsigned int flags; /* PM_* flags */ -diff --git a/server/queue.c b/server/queue.c -index a85bb15227..f9787933f2 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -2421,6 +2421,55 @@ DECL_HANDLER(send_hardware_message) - release_object( desktop ); - } - -+/* send a hardware rawinput message to the queue thread */ -+DECL_HANDLER(send_rawinput_message) -+{ -+ const struct rawinput_device *device; -+ struct hardware_msg_data *msg_data; -+ struct message *msg; -+ struct desktop *desktop; -+ struct hw_msg_source source = { IMDT_MOUSE, IMO_HARDWARE }; -+ -+ desktop = get_thread_desktop( current, 0 ); -+ -+ switch (req->input.type) -+ { -+ case RIM_TYPEMOUSE: -+ if ((device = current->process->rawinput_mouse)) -+ { -+ struct thread *thread = device->target ? get_window_thread( device->target ) : NULL; -+ if ((current->queue->input != desktop->foreground_input) || (thread && thread != current)) -+ goto done; -+ -+ if (!(msg = alloc_hardware_message( 0, source, 0 ))) goto done; -+ msg_data = msg->data; -+ -+ msg->win = device->target; -+ msg->msg = WM_INPUT; -+ msg->wparam = RIM_INPUT; -+ msg->lparam = 0; -+ -+ msg_data->flags = 0; -+ msg_data->rawinput.type = RIM_TYPEMOUSE; -+ msg_data->rawinput.mouse.x = req->input.mouse.x; -+ msg_data->rawinput.mouse.y = req->input.mouse.y; -+ msg_data->rawinput.mouse.button_flags = req->input.mouse.button_flags; -+ msg_data->rawinput.mouse.button_data = req->input.mouse.button_data; -+ msg_data->rawinput.mouse.flags = req->input.mouse.flags; -+ -+ queue_hardware_message( desktop, msg, 0 ); -+ -+ done: -+ if (thread) release_object( thread ); -+ } -+ break; -+ default: -+ set_error( STATUS_INVALID_PARAMETER ); -+ } -+ -+ release_object(desktop); -+} -+ - /* post a quit message to the current queue */ - DECL_HANDLER(post_quit_message) - { -diff --git a/server/trace.c b/server/trace.c -index 615542cff5..c936c7e57a 100644 ---- a/server/trace.c -+++ b/server/trace.c -@@ -405,6 +405,27 @@ static void dump_hw_input( const char *prefix, const hw_input_t *input ) - } - } - -+static void dump_hw_rawinput( const char *prefix, const hw_rawinput_t *rawinput ) -+{ -+ switch (rawinput->type) -+ { -+ case RIM_TYPEMOUSE: -+ fprintf( stderr, "%s{type=MOUSE,flags=%04hx,x=%d,y=%d,button_flags=%04hx,button_data=%04hx}", -+ prefix, rawinput->mouse.flags, rawinput->mouse.x, rawinput->mouse.y, -+ rawinput->mouse.button_flags, rawinput->mouse.button_data); -+ break; -+ case RIM_TYPEKEYBOARD: -+ fprintf( stderr, "%s{type=KEYBOARD}\n", prefix); -+ break; -+ case RIM_TYPEHID: -+ fprintf( stderr, "%s{type=HID}\n", prefix); -+ break; -+ default: -+ fprintf( stderr, "%s{type=%04x}", prefix, rawinput->type); -+ break; -+ } -+} -+ - static void dump_luid( const char *prefix, const luid_t *luid ) - { - fprintf( stderr, "%s%d.%u", prefix, luid->high_part, luid->low_part ); -diff --git a/tools/make_requests b/tools/make_requests -index faeabe5852..a6f12af041 100755 ---- a/tools/make_requests -+++ b/tools/make_requests -@@ -53,6 +53,7 @@ my %formats = - "ioctl_code_t" => [ 4, 4, "&dump_ioctl_code" ], - "client_cpu_t" => [ 4, 4, "&dump_client_cpu" ], - "hw_input_t" => [ 32, 8, "&dump_hw_input" ], -+ "hw_rawinput_t" => [ 20, 4, "&dump_hw_rawinput" ] - ); - - my @requests = (); --- -2.23.0 - diff --git a/patches/user32-rawinput/0004-user32-Add-helper-for-input-drivers-to-submit-native.patch b/patches/user32-rawinput/0004-user32-Add-helper-for-input-drivers-to-submit-native.patch deleted file mode 100644 index b3e48ae4..00000000 --- a/patches/user32-rawinput/0004-user32-Add-helper-for-input-drivers-to-submit-native.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 8e384f61c8d864ee95892f250cd0f384ac98d587 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 25 Jun 2019 21:28:54 -0400 -Subject: [PATCH 04/11] user32: Add helper for input drivers to submit native - rawinput msgs. - -Signed-off-by: Derek Lesho ---- - dlls/user32/input.c | 30 ++++++++++++++++++++++++++++++ - dlls/user32/user32.spec | 1 + - include/winuser.h | 1 + - 3 files changed, 32 insertions(+) - -diff --git a/dlls/user32/input.c b/dlls/user32/input.c -index 8b2ae805aa..9b9cc4f0d7 100644 ---- a/dlls/user32/input.c -+++ b/dlls/user32/input.c -@@ -33,6 +33,7 @@ - #include - - #define NONAMELESSUNION -+#define NONAMELESSSTRUCT - - #include "ntstatus.h" - #define WIN32_NO_STATUS -@@ -129,6 +130,35 @@ BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input ) - return !status; - } - -+BOOL CDECL __wine_send_raw_input( const RAWINPUT *raw_input ) -+{ -+ NTSTATUS status; -+ -+ SERVER_START_REQ( send_rawinput_message ) -+ { -+ req->input.type = raw_input->header.dwType; -+ switch (raw_input->header.dwType) -+ { -+ case RIM_TYPEMOUSE: -+ if (raw_input->data.mouse.ulRawButtons || -+ raw_input->data.mouse.ulExtraInformation) -+ FIXME("Unhandled parameters\n"); -+ -+ req->input.mouse.flags = raw_input->data.mouse.usFlags; -+ req->input.mouse.x = raw_input->data.mouse.lLastX; -+ req->input.mouse.y = raw_input->data.mouse.lLastY; -+ req->input.mouse.button_flags = raw_input->data.mouse.u.s.usButtonFlags; -+ req->input.mouse.button_data = raw_input->data.mouse.u.s.usButtonData; -+ break; -+ } -+ status = wine_server_call( req ); -+ } -+ SERVER_END_REQ; -+ -+ if (status) SetLastError( RtlNtStatusToDosError(status) ); -+ return !status; -+} -+ - - /*********************************************************************** - * update_mouse_coords -diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec -index f9a4ae26df..3311dcd685 100644 ---- a/dlls/user32/user32.spec -+++ b/dlls/user32/user32.spec -@@ -833,4 +833,5 @@ - # or 'wine_' (for user-visible functions) to avoid namespace conflicts. - # - @ cdecl __wine_send_input(long ptr) -+@ cdecl __wine_send_raw_input(ptr) - @ cdecl __wine_set_pixel_format(long long) -diff --git a/include/winuser.h b/include/winuser.h -index 51c73d25c2..259db275c4 100644 ---- a/include/winuser.h -+++ b/include/winuser.h -@@ -4390,6 +4390,7 @@ WORD WINAPI SYSTEM_KillSystemTimer( WORD ); - - #ifdef __WINESRC__ - WINUSERAPI BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input ); -+WINUSERAPI BOOL CDECL __wine_send_raw_input( const RAWINPUT *raw_input ); - #endif - - #ifdef __cplusplus --- -2.23.0 - diff --git a/patches/user32-rawinput/0005-server-Don-t-emulate-rawinput-mouse-events-if-native.patch b/patches/user32-rawinput/0005-server-Don-t-emulate-rawinput-mouse-events-if-native.patch deleted file mode 100644 index fb7478ce..00000000 --- a/patches/user32-rawinput/0005-server-Don-t-emulate-rawinput-mouse-events-if-native.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 45b1aba399b89c20e93bc358dfba261e40fcf30b Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 25 Jun 2019 21:58:34 -0400 -Subject: [PATCH 05/11] server: Don't emulate rawinput mouse events if native - exist. - -Signed-off-by: Derek Lesho ---- - server/queue.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/server/queue.c b/server/queue.c -index f9787933f2..060e73b819 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -1599,6 +1599,8 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa - return 1; - } - -+static int emulate_raw_mouse = 1; -+ - /* queue a hardware message for a mouse event */ - static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, - unsigned int origin, struct msg_queue *sender ) -@@ -1664,7 +1666,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons - y = desktop->cursor.y; - } - -- if ((device = current->process->rawinput_mouse)) -+ device = current->process->rawinput_mouse; -+ if (device && emulate_raw_mouse) - { - if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0; - msg_data = msg->data; -@@ -2435,6 +2438,7 @@ DECL_HANDLER(send_rawinput_message) - switch (req->input.type) - { - case RIM_TYPEMOUSE: -+ emulate_raw_mouse = 0; - if ((device = current->process->rawinput_mouse)) - { - struct thread *thread = device->target ? get_window_thread( device->target ) : NULL; --- -2.23.0 - diff --git a/patches/user32-rawinput/0006-winex11.drv-Directly-listen-to-master-XInput2-device.patch b/patches/user32-rawinput/0006-winex11.drv-Directly-listen-to-master-XInput2-device.patch deleted file mode 100644 index fc1c6fd3..00000000 --- a/patches/user32-rawinput/0006-winex11.drv-Directly-listen-to-master-XInput2-device.patch +++ /dev/null @@ -1,200 +0,0 @@ -From 73d2f9ea82a3897f7ba3f979b599ba0273d8f39d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 23 Jul 2019 14:10:44 +0200 -Subject: [PATCH 06/11] winex11.drv: Directly listen to master XInput2 devices - if supported - -Under XInput2 protocol version < 2.1, raw events should not be received -if pointer grab is active. However slave device events are still -received regardless of this specification and Wine implemented a -workaround to get raw events during pointer grabs by listening to these -slave device events. - -By advertising to support XInput2 protocol version >= 2.1, where raw -events are sent even during pointer grabs, it is possible to simplify -the code by listening to master device events only. - -Signed-off-by: Derek Lesho ---- - dlls/winex11.drv/event.c | 42 +----------------------------- - dlls/winex11.drv/mouse.c | 56 +++++++++++++++++++++++++++++----------- - 2 files changed, 42 insertions(+), 56 deletions(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 25730192d3..e31e2cc0c5 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -274,46 +274,6 @@ enum event_merge_action - MERGE_IGNORE /* ignore the new event, keep the old one */ - }; - --/*********************************************************************** -- * merge_raw_motion_events -- */ --#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H --static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent *next ) --{ -- int i, j, k; -- unsigned char mask; -- -- if (!prev->valuators.mask_len) return MERGE_HANDLE; -- if (!next->valuators.mask_len) return MERGE_HANDLE; -- -- mask = prev->valuators.mask[0] | next->valuators.mask[0]; -- if (mask == next->valuators.mask[0]) /* keep next */ -- { -- for (i = j = k = 0; i < 8; i++) -- { -- if (XIMaskIsSet( prev->valuators.mask, i )) -- next->valuators.values[j] += prev->valuators.values[k++]; -- if (XIMaskIsSet( next->valuators.mask, i )) j++; -- } -- TRACE( "merging duplicate GenericEvent\n" ); -- return MERGE_DISCARD; -- } -- if (mask == prev->valuators.mask[0]) /* keep prev */ -- { -- for (i = j = k = 0; i < 8; i++) -- { -- if (XIMaskIsSet( next->valuators.mask, i )) -- prev->valuators.values[j] += next->valuators.values[k++]; -- if (XIMaskIsSet( prev->valuators.mask, i )) j++; -- } -- TRACE( "merging duplicate GenericEvent\n" ); -- return MERGE_IGNORE; -- } -- /* can't merge events with disjoint masks */ -- return MERGE_HANDLE; --} --#endif -- - /*********************************************************************** - * merge_events - * -@@ -365,7 +325,7 @@ static enum event_merge_action merge_events( XEvent *prev, XEvent *next ) - if (next->xcookie.extension != xinput2_opcode) break; - if (next->xcookie.evtype != XI_RawMotion) break; - if (x11drv_thread_data()->warp_serial) break; -- return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data ); -+ return MERGE_HANDLE; - #endif - } - break; -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 15e5c04a41..23c7c6fb35 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -133,6 +133,8 @@ static Cursor create_cursor( HANDLE handle ); - - #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - static BOOL xinput2_available; -+static int xinput2_version_major = 2; -+static int xinput2_version_minor = 1; - static BOOL broken_rawevents; - #define MAKE_FUNCPTR(f) static typeof(f) * p##f - MAKE_FUNCPTR(XIGetClientPointer); -@@ -304,8 +306,11 @@ static void enable_xinput2(void) - - if (data->xi2_state == xi_unknown) - { -- int major = 2, minor = 0; -- if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled; -+ if (!pXIQueryVersion( data->display, &xinput2_version_major, &xinput2_version_minor )) -+ { -+ TRACE( "XInput2 v%d.%d available\n", xinput2_version_major, xinput2_version_minor ); -+ data->xi2_state = xi_disabled; -+ } - else - { - data->xi2_state = xi_unavailable; -@@ -317,11 +322,19 @@ static void enable_xinput2(void) - - mask.mask = mask_bits; - mask.mask_len = sizeof(mask_bits); -- mask.deviceid = XIAllDevices; -+ mask.deviceid = XIAllMasterDevices; - memset( mask_bits, 0, sizeof(mask_bits) ); -- XISetMask( mask_bits, XI_DeviceChanged ); - XISetMask( mask_bits, XI_RawMotion ); - XISetMask( mask_bits, XI_ButtonPress ); -+ XISetMask( mask_bits, XI_DeviceChanged ); -+ -+ /* XInput 2.0 has a problematic behavior where master pointer will -+ * not send raw events to the root window whenever a grab is active -+ */ -+ if (xinput2_version_major == 2 && xinput2_version_minor == 0) -+ { -+ mask.deviceid = XIAllDevices; -+ } - - pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); - -@@ -336,7 +349,7 @@ static void enable_xinput2(void) - * safe to be obtained statically at enable_xinput2() time. - */ - if (data->xi2_devices) pXIFreeDeviceInfo( data->xi2_devices ); -- data->xi2_devices = pXIQueryDevice( data->display, XIAllDevices, &data->xi2_device_count ); -+ data->xi2_devices = pXIQueryDevice( data->display, mask.deviceid, &data->xi2_device_count ); - data->xi2_current_slave = 0; - - data->xi2_state = xi_enabled; -@@ -359,7 +372,13 @@ static void disable_xinput2(void) - - mask.mask = NULL; - mask.mask_len = 0; -- mask.deviceid = XIAllDevices; -+ mask.deviceid = XIAllMasterDevices; -+ -+ /* XInput 2.0 has a problematic behavior where master pointer will -+ * not send raw events to the root window whenever a grab is active -+ */ -+ if (xinput2_version_major == 2 && xinput2_version_minor == 0) -+ mask.deviceid = XIAllDevices; - - pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); - pXIFreeDeviceInfo( data->xi2_devices ); -@@ -1793,25 +1812,32 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - if (!event->valuators.mask_len) return FALSE; - if (thread_data->xi2_state != xi_enabled) return FALSE; - -- /* If there is no slave currently detected, no previous motion nor device -- * change events were received. Look it up now on the device list in this -- * case. -- */ -- if (!thread_data->xi2_current_slave) -+ if (xinput2_version_major == 2 && xinput2_version_minor == 0) - { - XIDeviceInfo *devices = thread_data->xi2_devices; - -- for (i = 0; i < thread_data->xi2_device_count; i++) -+ /* If there is no slave currently detected, no previous motion nor device -+ * change events were received. Look it up now on the device list in this -+ * case. -+ */ -+ for (i = 0; !thread_data->xi2_current_slave && i < thread_data->xi2_device_count; i++) - { - if (devices[i].use != XISlavePointer) continue; - if (devices[i].deviceid != event->deviceid) continue; - if (devices[i].attachment != thread_data->xi2_core_pointer) continue; - thread_data->xi2_current_slave = event->deviceid; -- break; - } -- } - -- if (event->deviceid != thread_data->xi2_current_slave) return FALSE; -+ /* Only listen to slave device events on XInput == 2.0 */ -+ if (event->deviceid != thread_data->xi2_current_slave) -+ return FALSE; -+ } -+ else -+ { -+ /* Only listen to master device events on XInput >= 2.1 */ -+ if (event->deviceid != thread_data->xi2_core_pointer) -+ return FALSE; -+ } - - x_rel = &thread_data->x_rel_valuator; - y_rel = &thread_data->y_rel_valuator; --- -2.23.0 - diff --git a/patches/user32-rawinput/0007-winex11.drv-Implement-native-mouse-movement-raw-inpu.patch b/patches/user32-rawinput/0007-winex11.drv-Implement-native-mouse-movement-raw-inpu.patch deleted file mode 100644 index 90e6ad03..00000000 --- a/patches/user32-rawinput/0007-winex11.drv-Implement-native-mouse-movement-raw-inpu.patch +++ /dev/null @@ -1,316 +0,0 @@ -From c91c52063e8c06bc8e8788309ecb7dca70bc6b9a Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 25 Jun 2019 22:37:34 -0400 -Subject: [PATCH 07/11] winex11.drv: Implement native mouse-movement raw-input - using RawMotion. - -Signed-off-by: Derek Lesho ---- - dlls/winex11.drv/mouse.c | 102 +++++++++++++++++++++++++++------ - dlls/winex11.drv/x11drv.h | 8 ++- - dlls/winex11.drv/x11drv_main.c | 6 ++ - 3 files changed, 97 insertions(+), 19 deletions(-) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 23c7c6fb35..212511fde8 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -262,6 +262,8 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator - - thread_data->x_rel_valuator.number = -1; - thread_data->y_rel_valuator.number = -1; -+ thread_data->x_abs_valuator.number = -1; -+ thread_data->y_abs_valuator.number = -1; - - for (i = 0; i < n_valuators; i++) - { -@@ -279,6 +281,16 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator - { - valuator_data = &thread_data->y_rel_valuator; - } -+ else if (class->label == x11drv_atom( Abs_X ) || -+ (!class->label && class->number == 0 && class->mode == XIModeAbsolute)) -+ { -+ valuator_data = &thread_data->x_abs_valuator; -+ } -+ else if (class->label == x11drv_atom( Abs_Y ) || -+ (!class->label && class->number == 1 && class->mode == XIModeAbsolute)) -+ { -+ valuator_data = &thread_data->y_abs_valuator; -+ } - - if (valuator_data) { - valuator_data->number = class->number; -@@ -291,9 +303,9 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator - - - /*********************************************************************** -- * enable_xinput2 -+ * X11DRV_XInput2_Enable - */ --static void enable_xinput2(void) -+void X11DRV_XInput2_Enable(void) - { - #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - struct x11drv_thread_data *data = x11drv_thread_data(); -@@ -324,8 +336,8 @@ static void enable_xinput2(void) - mask.mask_len = sizeof(mask_bits); - mask.deviceid = XIAllMasterDevices; - memset( mask_bits, 0, sizeof(mask_bits) ); -+ XISetMask( mask_bits, XI_DeviceChanged ); - XISetMask( mask_bits, XI_RawMotion ); -- XISetMask( mask_bits, XI_ButtonPress ); - XISetMask( mask_bits, XI_DeviceChanged ); - - /* XInput 2.0 has a problematic behavior where master pointer will -@@ -357,15 +369,15 @@ static void enable_xinput2(void) - } - - /*********************************************************************** -- * disable_xinput2 -+ * X11DRV_XInput2_Disable - */ --static void disable_xinput2(void) -+void X11DRV_XInput2_Disable(void) - { - #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - struct x11drv_thread_data *data = x11drv_thread_data(); - XIEventMask mask; - -- if (data->xi2_state != xi_enabled) return; -+ if (data->xi2_state < xi_enabled) return; - - TRACE( "disabling\n" ); - data->xi2_state = xi_disabled; -@@ -390,6 +402,21 @@ static void disable_xinput2(void) - #endif - } - -+static void use_xinput2_path(void) -+{ -+ struct x11drv_thread_data *thread_data = x11drv_thread_data(); -+ -+ if (thread_data->xi2_state == xi_enabled) -+ thread_data->xi2_state = xi_extra; -+} -+ -+static void disable_xinput2_path(void) -+{ -+ struct x11drv_thread_data *thread_data = x11drv_thread_data(); -+ -+ if (thread_data->xi2_state == xi_extra) -+ thread_data->xi2_state = xi_enabled; -+} - - /*********************************************************************** - * grab_clipping_window -@@ -428,9 +455,9 @@ static BOOL grab_clipping_window( const RECT *clip ) - } - - /* enable XInput2 unless we are already clipping */ -- if (!data->clip_hwnd) enable_xinput2(); -+ if (!data->clip_hwnd) use_xinput2_path(); - -- if (data->xi2_state != xi_enabled) -+ if (data->xi2_state < xi_extra) - { - WARN( "XInput2 not supported, refusing to clip to %s\n", wine_dbgstr_rect(clip) ); - DestroyWindow( msg_hwnd ); -@@ -458,7 +485,7 @@ static BOOL grab_clipping_window( const RECT *clip ) - - if (!clipping_cursor) - { -- disable_xinput2(); -+ disable_xinput2_path(); - DestroyWindow( msg_hwnd ); - return FALSE; - } -@@ -539,7 +566,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) - TRACE( "clip hwnd reset from %p\n", hwnd ); - data->clip_hwnd = 0; - data->clip_reset = GetTickCount(); -- disable_xinput2(); -+ disable_xinput2_path(); - DestroyWindow( hwnd ); - } - else if (hwnd == GetForegroundWindow()) /* request to clip */ -@@ -1801,16 +1828,20 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - { - XIRawEvent *event = xev->data; - const double *values = event->valuators.values; -+ const double *raw_values = event->raw_values; - RECT virtual_rect; - INPUT input; -+ RAWINPUT raw_input; - int i; -- double dx = 0, dy = 0, val; -+ double dx = 0, dy = 0, raw_x = 0, raw_y = 0, val, raw_val; - struct x11drv_thread_data *thread_data = x11drv_thread_data(); -- struct x11drv_valuator_data *x_rel, *y_rel; -+ struct x11drv_valuator_data *x_rel, *y_rel, *x_abs, *y_abs; -+ -+ if ((thread_data->x_rel_valuator.number < 0 || thread_data->y_rel_valuator.number < 0) && -+ (thread_data->x_abs_valuator.number < 0 || thread_data->y_abs_valuator.number < 0) return FALSE; - -- if (thread_data->x_rel_valuator.number < 0 || thread_data->y_rel_valuator.number < 0) return FALSE; - if (!event->valuators.mask_len) return FALSE; -- if (thread_data->xi2_state != xi_enabled) return FALSE; -+ if (thread_data->xi2_state < xi_enabled) return FALSE; - - if (xinput2_version_major == 2 && xinput2_version_minor == 0) - { -@@ -1841,7 +1872,10 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - - x_rel = &thread_data->x_rel_valuator; - y_rel = &thread_data->y_rel_valuator; -+ x_abs = &thread_data->x_abs_valuator; -+ y_abs = &thread_data->y_abs_valuator; - -+ input.type = INPUT_MOUSE; - input.u.mi.mouseData = 0; - input.u.mi.dwFlags = MOUSEEVENTF_MOVE; - input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); -@@ -1849,18 +1883,31 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - input.u.mi.dx = 0; - input.u.mi.dy = 0; - -+ raw_input.header.dwType = RIM_TYPEMOUSE; -+ raw_input.data.mouse.u.usButtonFlags = 0; -+ raw_input.data.mouse.u.usButtonData = 0; -+ raw_input.data.mouse.ulExtraInformation = 0; -+ raw_input.data.mouse.ulRawButtons = 0; -+ raw_input.data.mouse.usFlags = 0; -+ raw_input.data.mouse.lLastX = 0; -+ raw_input.data.mouse.lLastY = 0; -+ - virtual_rect = get_virtual_screen_rect(); - -- for (i = 0; i <= max ( x_rel->number, y_rel->number ); i++) -+ for (i = 0; i <= max(max(max( x_abs->number, y_abs->number), x_rel->number), y_rel->number); i++) - { - if (!XIMaskIsSet( event->valuators.mask, i )) continue; - val = *values++; -+ raw_val = *raw_values++; - if (i == x_rel->number) - { - input.u.mi.dx = dx = val; - if (x_rel->min < x_rel->max) - input.u.mi.dx = val * (virtual_rect.right - virtual_rect.left) - / (x_rel->max - x_rel->min); -+ -+ raw_input.data.mouse.usFlags = MOUSE_MOVE_RELATIVE; -+ raw_input.data.mouse.lLastX = raw_x = raw_val; - } - if (i == y_rel->number) - { -@@ -1868,6 +1915,19 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - if (y_rel->min < y_rel->max) - input.u.mi.dy = val * (virtual_rect.bottom - virtual_rect.top) - / (y_rel->max - y_rel->min); -+ -+ raw_input.data.mouse.usFlags = MOUSE_MOVE_RELATIVE; -+ raw_input.data.mouse.lLastY = raw_y = raw_val; -+ } -+ if (i == x_abs->number) -+ { -+ raw_input.data.mouse.usFlags = MOUSE_MOVE_ABSOLUTE | MOUSE_VIRTUAL_DESKTOP; -+ raw_input.data.mouse.lLastX = raw_x = raw_val * (65536 / (x_abs->max - x_abs->min)); -+ } -+ if (i == y_abs->number) -+ { -+ raw_input.data.mouse.usFlags = MOUSE_MOVE_ABSOLUTE | MOUSE_VIRTUAL_DESKTOP; -+ raw_input.data.mouse.lLastY = raw_y = raw_val * (65536 / (y_abs->max - y_abs->min)); - } - } - -@@ -1877,10 +1937,16 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - return FALSE; - } - -- TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); -+ if (thread_data->xi2_state == xi_extra) -+ { -+ TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); -+ __wine_send_input( 0, &input ); -+ } -+ -+ TRACE("raw %s event %f,%f\n", -+ raw_input.data.mouse.usFlags ? "absolute" : "relative", raw_x, raw_y); -+ __wine_send_raw_input( &raw_input ); - -- input.type = INPUT_MOUSE; -- __wine_send_input( 0, &input ); - return TRUE; - } - -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 135faa8989..e9d9514ee2 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -194,6 +194,8 @@ extern BOOL CDECL X11DRV_UnrealizePalette( HPALETTE hpal ) DECLSPEC_HIDDEN; - - extern void X11DRV_Xcursor_Init(void) DECLSPEC_HIDDEN; - extern void X11DRV_XInput2_Init(void) DECLSPEC_HIDDEN; -+extern void X11DRV_XInput2_Enable(void) DECLSPEC_HIDDEN; -+extern void X11DRV_XInput2_Disable(void) DECLSPEC_HIDDEN; - - extern DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image, - const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits, -@@ -335,11 +337,13 @@ struct x11drv_thread_data - HWND clip_hwnd; /* message window stored in desktop while clipping is active */ - DWORD clip_reset; /* time when clipping was last reset */ - HKL kbd_layout; /* active keyboard layout */ -- enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ -+ enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled, xi_extra } xi2_state; /* XInput2 state */ - void *xi2_devices; /* list of XInput2 devices (valid when state is enabled) */ - int xi2_device_count; - struct x11drv_valuator_data x_rel_valuator; - struct x11drv_valuator_data y_rel_valuator; -+ struct x11drv_valuator_data x_abs_valuator; -+ struct x11drv_valuator_data y_abs_valuator; - int xi2_core_pointer; /* XInput2 core pointer id */ - int xi2_current_slave; /* Current slave driving the Core pointer */ - }; -@@ -426,6 +430,8 @@ enum x11drv_atoms - XATOM_RAW_CAP_HEIGHT, - XATOM_Rel_X, - XATOM_Rel_Y, -+ XATOM_Abs_X, -+ XATOM_Abs_Y, - XATOM_WM_PROTOCOLS, - XATOM_WM_DELETE_WINDOW, - XATOM_WM_STATE, -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index 21807af3f1..fb25a45ae2 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -120,6 +120,8 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = - "RAW_CAP_HEIGHT", - "Rel X", - "Rel Y", -+ "Abs X", -+ "Abs Y", - "WM_PROTOCOLS", - "WM_DELETE_WINDOW", - "WM_STATE", -@@ -611,6 +613,8 @@ void CDECL X11DRV_ThreadDetach(void) - - if (data) - { -+ X11DRV_XInput2_Disable(); -+ - if (data->xim) XCloseIM( data->xim ); - if (data->font_set) XFreeFontSet( data->display, data->font_set ); - XCloseDisplay( data->display ); -@@ -681,6 +685,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) - - if (use_xim) X11DRV_SetupXIM(); - -+ X11DRV_XInput2_Enable(); -+ - return data; - } - --- -2.23.0 - diff --git a/patches/user32-rawinput/0008-winex11.drv-Implement-native-mouse-button-raw-input-.patch b/patches/user32-rawinput/0008-winex11.drv-Implement-native-mouse-button-raw-input-.patch deleted file mode 100644 index e80c467d..00000000 --- a/patches/user32-rawinput/0008-winex11.drv-Implement-native-mouse-button-raw-input-.patch +++ /dev/null @@ -1,234 +0,0 @@ -From f55c05132e87dd3e9436c68920ad512bdcfb8df8 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 26 Jul 2019 17:37:19 -0400 -Subject: [PATCH 08/11] winex11.drv: Implement native mouse-button raw-input - using RawButton*. - -Signed-off-by: Derek Lesho ---- - dlls/winex11.drv/mouse.c | 97 +++++++++++++++++++++++++++++++--- - dlls/winex11.drv/x11drv.h | 3 ++ - dlls/winex11.drv/x11drv_main.c | 1 + - 3 files changed, 95 insertions(+), 6 deletions(-) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 212511fde8..1d9833b5c9 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -264,12 +264,21 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator - thread_data->y_rel_valuator.number = -1; - thread_data->x_abs_valuator.number = -1; - thread_data->y_abs_valuator.number = -1; -+ thread_data->wheel_valuator.number = -1; -+ -+ thread_data->xi2_wheel_multiplier = 0; - - for (i = 0; i < n_valuators; i++) - { - XIValuatorClassInfo *class = (XIValuatorClassInfo *)valuators[i]; -+ XIScrollClassInfo *scroll_class = (XIScrollClassInfo *)valuators[i]; - struct x11drv_valuator_data *valuator_data = NULL; - -+ if (valuators[i]->type == XIScrollClass) -+ { -+ if (scroll_class->scroll_type == XIScrollTypeVertical) -+ thread_data->xi2_wheel_multiplier = -WHEEL_DELTA / scroll_class->increment; -+ } - if (valuators[i]->type != XIValuatorClass) continue; - if (class->label == x11drv_atom( Rel_X ) || - (!class->label && class->number == 0 && class->mode == XIModeRelative)) -@@ -291,6 +300,11 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator - { - valuator_data = &thread_data->y_abs_valuator; - } -+ else if (class->label == x11drv_atom( Rel_Vert_Scroll ) || -+ (!class->label && class->number == 3 && class->mode == XIModeRelative)) -+ { -+ valuator_data = &thread_data->wheel_valuator; -+ } - - if (valuator_data) { - valuator_data->number = class->number; -@@ -339,6 +353,8 @@ void X11DRV_XInput2_Enable(void) - XISetMask( mask_bits, XI_DeviceChanged ); - XISetMask( mask_bits, XI_RawMotion ); - XISetMask( mask_bits, XI_DeviceChanged ); -+ XISetMask( mask_bits, XI_RawButtonPress ); -+ XISetMask( mask_bits, XI_RawButtonRelease ); - - /* XInput 2.0 has a problematic behavior where master pointer will - * not send raw events to the root window whenever a grab is active -@@ -396,6 +412,7 @@ void X11DRV_XInput2_Disable(void) - pXIFreeDeviceInfo( data->xi2_devices ); - data->x_rel_valuator.number = -1; - data->y_rel_valuator.number = -1; -+ data->wheel_valuator.number = -1; - data->xi2_devices = NULL; - data->xi2_core_pointer = 0; - data->xi2_current_slave = 0; -@@ -1833,12 +1850,13 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - INPUT input; - RAWINPUT raw_input; - int i; -- double dx = 0, dy = 0, raw_x = 0, raw_y = 0, val, raw_val; -+ double dx = 0, dy = 0, raw_x = 0, raw_y = 0, raw_dwheel = 0, val, raw_val; - struct x11drv_thread_data *thread_data = x11drv_thread_data(); -- struct x11drv_valuator_data *x_rel, *y_rel, *x_abs, *y_abs; -+ struct x11drv_valuator_data *x_rel, *y_rel, *x_abs, *y_abs, *wheel; - - if ((thread_data->x_rel_valuator.number < 0 || thread_data->y_rel_valuator.number < 0) && -- (thread_data->x_abs_valuator.number < 0 || thread_data->y_abs_valuator.number < 0) return FALSE; -+ (thread_data->x_abs_valuator.number < 0 || thread_data->y_abs_valuator.number < 0) && -+ thread_data->wheel_valuator.number < 0) return FALSE; - - if (!event->valuators.mask_len) return FALSE; - if (thread_data->xi2_state < xi_enabled) return FALSE; -@@ -1874,6 +1892,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - y_rel = &thread_data->y_rel_valuator; - x_abs = &thread_data->x_abs_valuator; - y_abs = &thread_data->y_abs_valuator; -+ wheel = &thread_data->wheel_valuator; - - input.type = INPUT_MOUSE; - input.u.mi.mouseData = 0; -@@ -1894,7 +1913,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - - virtual_rect = get_virtual_screen_rect(); - -- for (i = 0; i <= max(max(max( x_abs->number, y_abs->number), x_rel->number), y_rel->number); i++) -+ for (i = 0; i <= max(max(max(max(x_abs->number, y_abs->number), x_rel->number), y_rel->number), wheel->number); i++) - { - if (!XIMaskIsSet( event->valuators.mask, i )) continue; - val = *values++; -@@ -1929,6 +1948,10 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - raw_input.data.mouse.usFlags = MOUSE_MOVE_ABSOLUTE | MOUSE_VIRTUAL_DESKTOP; - raw_input.data.mouse.lLastY = raw_y = raw_val * (65536 / (y_abs->max - y_abs->min)); - } -+ if (i == wheel->number) -+ { -+ raw_dwheel = raw_val * thread_data->xi2_wheel_multiplier; -+ } - } - - if (broken_rawevents && is_old_motion_event( xev->serial )) -@@ -1943,13 +1966,70 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - __wine_send_input( 0, &input ); - } - -- TRACE("raw %s event %f,%f\n", -- raw_input.data.mouse.usFlags ? "absolute" : "relative", raw_x, raw_y); -+ if (raw_dwheel) -+ { -+ raw_input.data.mouse.u.usButtonFlags = RI_MOUSE_WHEEL; -+ raw_input.data.mouse.u.usButtonData = raw_dwheel; -+ } -+ -+ TRACE("raw %s event %f,%f + %f\n", -+ raw_input.data.mouse.usFlags ? "absolute" : "relative", raw_x, raw_y, raw_dwheel); - __wine_send_raw_input( &raw_input ); - - return TRUE; - } - -+/*********************************************************************** -+ * X11DRV_RawButton -+ */ -+static BOOL X11DRV_RawButton( XGenericEventCookie *xev ) -+{ -+ RAWINPUT ri; -+ -+ static const unsigned short raw_button_press_flags[] = { -+ 0, /* 0 = unused */ -+ RI_MOUSE_LEFT_BUTTON_DOWN, /* 1 */ -+ RI_MOUSE_MIDDLE_BUTTON_DOWN, /* 2 */ -+ RI_MOUSE_RIGHT_BUTTON_DOWN, /* 3 */ -+ 0, /* 4 = unknown */ -+ 0, /* 5 = unknown */ -+ 0, /* 6 = unknown */ -+ 0, /* 7 = unknown */ -+ RI_MOUSE_BUTTON_4_DOWN, /* 8 */ -+ RI_MOUSE_BUTTON_5_DOWN /* 9 */ -+ }; -+ -+ static const unsigned short raw_button_release_flags[] = { -+ 0, /* 0 = unused */ -+ RI_MOUSE_LEFT_BUTTON_UP, /* 1 */ -+ RI_MOUSE_MIDDLE_BUTTON_UP, /* 2 */ -+ RI_MOUSE_RIGHT_BUTTON_UP, /* 3 */ -+ 0, /* 4 = unknown */ -+ 0, /* 5 = unknown */ -+ 0, /* 6 = unknown */ -+ 0, /* 7 = unknown */ -+ RI_MOUSE_BUTTON_4_UP, /* 8 */ -+ RI_MOUSE_BUTTON_5_UP /* 9 */ -+ }; -+ -+ int detail = ((XIRawEvent*)xev->data)->detail; -+ if (detail > 9) return TRUE; -+ -+ ri.header.dwType = RIM_TYPEMOUSE; -+ ri.data.mouse.u.usButtonFlags = xev->evtype == XI_RawButtonPress ? raw_button_press_flags[detail] : raw_button_release_flags[detail] ; -+ ri.data.mouse.u.usButtonData = 0; -+ ri.data.mouse.lLastX = 0; -+ ri.data.mouse.lLastY = 0; -+ ri.data.mouse.usFlags = 0; -+ ri.data.mouse.ulRawButtons = 0; -+ ri.data.mouse.ulExtraInformation = 0; -+ -+ if (ri.data.mouse.u.usButtonFlags) -+ __wine_send_raw_input( &ri ); -+ -+ return TRUE; -+} -+ - #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ - - -@@ -2014,6 +2094,11 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev ) - case XI_RawMotion: - ret = X11DRV_RawMotion( event ); - break; -+ case XI_RawButtonPress: -+ /* fall through */ -+ case XI_RawButtonRelease: -+ ret = X11DRV_RawButton( event ); -+ break; - - default: - TRACE( "Unhandled event %#x\n", event->evtype ); -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index e9d9514ee2..599ed48154 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -344,6 +344,8 @@ struct x11drv_thread_data - struct x11drv_valuator_data y_rel_valuator; - struct x11drv_valuator_data x_abs_valuator; - struct x11drv_valuator_data y_abs_valuator; -+ struct x11drv_valuator_data wheel_valuator; -+ double xi2_wheel_multiplier; - int xi2_core_pointer; /* XInput2 core pointer id */ - int xi2_current_slave; /* Current slave driving the Core pointer */ - }; -@@ -432,6 +434,7 @@ enum x11drv_atoms - XATOM_Rel_Y, - XATOM_Abs_X, - XATOM_Abs_Y, -+ XATOM_Rel_Vert_Scroll, - XATOM_WM_PROTOCOLS, - XATOM_WM_DELETE_WINDOW, - XATOM_WM_STATE, -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index fb25a45ae2..05a445a9c1 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -122,6 +122,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = - "Rel Y", - "Abs X", - "Abs Y", -+ "Rel Vert Scroll", - "WM_PROTOCOLS", - "WM_DELETE_WINDOW", - "WM_STATE", --- -2.23.0 - diff --git a/patches/user32-rawinput/0009-winex11.drv-Don-t-react-to-small-slow-mouse-movement.patch b/patches/user32-rawinput/0009-winex11.drv-Don-t-react-to-small-slow-mouse-movement.patch deleted file mode 100644 index affc9ca7..00000000 --- a/patches/user32-rawinput/0009-winex11.drv-Don-t-react-to-small-slow-mouse-movement.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 5c4db171dc87400ecd3e57b7efff805032328b5f Mon Sep 17 00:00:00 2001 -From: Jordan Galby -Date: Tue, 16 Jul 2019 00:34:38 -0400 -Subject: [PATCH 09/11] winex11.drv: Don't react to small slow mouse movements. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=42631 -From: Jordan Galby -Signed-off-by: Derek Lesho ---- - dlls/winex11.drv/mouse.c | 51 +++++++++++++++++++++++++++++++-------- - dlls/winex11.drv/x11drv.h | 1 + - 2 files changed, 42 insertions(+), 10 deletions(-) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 1d9833b5c9..1b109c8d1a 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -266,6 +266,10 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator - thread_data->y_abs_valuator.number = -1; - thread_data->wheel_valuator.number = -1; - -+ thread_data->x_rel_valuator.accum = 0; -+ thread_data->y_rel_valuator.accum = 0; -+ thread_data->wheel_valuator.accum = 0; -+ - thread_data->xi2_wheel_multiplier = 0; - - for (i = 0; i < n_valuators; i++) -@@ -1920,9 +1924,9 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - raw_val = *raw_values++; - if (i == x_rel->number) - { -- input.u.mi.dx = dx = val; -+ dx = val; - if (x_rel->min < x_rel->max) -- input.u.mi.dx = val * (virtual_rect.right - virtual_rect.left) -+ dx = val * (virtual_rect.right - virtual_rect.left) - / (x_rel->max - x_rel->min); - - raw_input.data.mouse.usFlags = MOUSE_MOVE_RELATIVE; -@@ -1930,9 +1934,9 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - } - if (i == y_rel->number) - { -- input.u.mi.dy = dy = val; -+ dy = val; - if (y_rel->min < y_rel->max) -- input.u.mi.dy = val * (virtual_rect.bottom - virtual_rect.top) -+ dy = val * (virtual_rect.bottom - virtual_rect.top) - / (y_rel->max - y_rel->min); - - raw_input.data.mouse.usFlags = MOUSE_MOVE_RELATIVE; -@@ -1956,20 +1960,47 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - - if (broken_rawevents && is_old_motion_event( xev->serial )) - { -- TRACE( "pos %d,%d old serial %lu, ignoring\n", input.u.mi.dx, input.u.mi.dy, xev->serial ); -+ TRACE( "pos %d,%d old serial %lu, ignoring\n", (LONG) dx, (LONG) dy, xev->serial ); - return FALSE; - } - -- if (thread_data->xi2_state == xi_extra) -+ /* Accumulate the fractional parts so they aren't lost after casting -+ * successive motion values to integral fields. -+ * -+ * Note: It looks like raw_dx and raw_dy are already integral values -+ * but that may be wrong. -+ */ -+ -+ x_rel->accum += dx; -+ y_rel->accum += dy; -+ if ((dy || dy) && fabs(x_rel->accum) < 1.0 && fabs(y_rel->accum) < 1.0) -+ { -+ TRACE( "accumulating raw motion (event %f,%f, accum %f,%f)\n", dx, dy, x_rel->accum, y_rel->accum ); -+ } -+ else - { -- TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); -- __wine_send_input( 0, &input ); -+ input.u.mi.dx = x_rel->accum; -+ input.u.mi.dy = y_rel->accum; -+ x_rel->accum -= input.u.mi.dx; -+ y_rel->accum -= input.u.mi.dy; -+ -+ if (thread_data->xi2_state == xi_extra) -+ { -+ TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); -+ __wine_send_input( 0, &input ); -+ } - } - -- if (raw_dwheel) -+ wheel->accum += raw_dwheel; -+ if (raw_dwheel && fabs(wheel->accum) < 1.0) -+ { -+ TRACE("accumulating wheel motion (event %f, accum %f)\n", raw_dwheel, wheel->accum); -+ } -+ else - { - raw_input.data.mouse.u.usButtonFlags = RI_MOUSE_WHEEL; -- raw_input.data.mouse.u.usButtonData = raw_dwheel; -+ raw_input.data.mouse.u.usButtonData = wheel->accum; -+ wheel->accum -= raw_dwheel; - } - - TRACE("raw %s event %f,%f + %f\n", -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 599ed48154..005512fc4e 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -320,6 +320,7 @@ struct x11drv_valuator_data - double min; - double max; - int number; -+ double accum; - }; - - struct x11drv_thread_data --- -2.23.0 - diff --git a/patches/user32-rawinput/0010-server-Implement-RIDEV_INPUTSINK-flag.patch b/patches/user32-rawinput/0010-server-Implement-RIDEV_INPUTSINK-flag.patch deleted file mode 100644 index d021ae65..00000000 --- a/patches/user32-rawinput/0010-server-Implement-RIDEV_INPUTSINK-flag.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 97ab5ded8d021c911308f215bbfd27ebd0de4294 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Sat, 10 Aug 2019 12:20:59 -0400 -Subject: [PATCH 10/11] server: Implement RIDEV_INPUTSINK flag - -Signed-off-by: Derek Lesho ---- - dlls/user32/rawinput.c | 2 +- - server/queue.c | 4 +++- - 2 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c -index 661a0e3b25..a93dc36500 100644 ---- a/dlls/user32/rawinput.c -+++ b/dlls/user32/rawinput.c -@@ -282,7 +282,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U - TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n", - i, devices[i].usUsagePage, devices[i].usUsage, - devices[i].dwFlags, devices[i].hwndTarget); -- if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY)) -+ if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY|RIDEV_INPUTSINK)) - FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i); - - d[i].usage_page = devices[i].usUsagePage; -diff --git a/server/queue.c b/server/queue.c -index 060e73b819..0c3b5354bd 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -2442,7 +2442,9 @@ DECL_HANDLER(send_rawinput_message) - if ((device = current->process->rawinput_mouse)) - { - struct thread *thread = device->target ? get_window_thread( device->target ) : NULL; -- if ((current->queue->input != desktop->foreground_input) || (thread && thread != current)) -+ if ((current->queue->input != desktop->foreground_input && !(device->flags & RIDEV_INPUTSINK)) -+ || (thread && thread != current) -+ || (!thread && device->flags & RIDEV_INPUTSINK)) - goto done; - - if (!(msg = alloc_hardware_message( 0, source, 0 ))) goto done; --- -2.23.0 - diff --git a/patches/user32-rawinput/0011-winex11.drv-HACK-XWayland-workaround.patch b/patches/user32-rawinput/0011-winex11.drv-HACK-XWayland-workaround.patch deleted file mode 100644 index 39c7d268..00000000 --- a/patches/user32-rawinput/0011-winex11.drv-HACK-XWayland-workaround.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 1a2b1df3e51425163af922ae5181d17a7f5ad380 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 4 Sep 2019 10:07:39 -0500 -Subject: [PATCH 11/11] winex11.drv: [HACK] XWayland workaround. - ---- - dlls/winex11.drv/mouse.c | 36 ++++++++++++++++++++++++++++++++---- - 1 file changed, 32 insertions(+), 4 deletions(-) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 1b109c8d1a..b06b7dc170 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -25,6 +25,7 @@ - #include - #include - #include -+#include - #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - #include - #endif -@@ -1842,6 +1843,17 @@ static BOOL X11DRV_DeviceChanged( XGenericEventCookie *xev ) - return TRUE; - } - -+/* XWayland only reports normalized absolute values and raw relative values, -+ * all under an absolute valuator. -+ */ -+static inline int xwayland_workaround(void) -+{ -+ static int workaround = -1; -+ if (workaround != -1) return workaround; -+ workaround = !!getenv("WAYLAND_DISPLAY"); -+ return workaround; -+} -+ - /*********************************************************************** - * X11DRV_RawMotion - */ -@@ -1944,13 +1956,29 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - } - if (i == x_abs->number) - { -- raw_input.data.mouse.usFlags = MOUSE_MOVE_ABSOLUTE | MOUSE_VIRTUAL_DESKTOP; -- raw_input.data.mouse.lLastX = raw_x = raw_val * (65536 / (x_abs->max - x_abs->min)); -+ if (xwayland_workaround()) -+ { -+ raw_input.data.mouse.usFlags = MOUSE_MOVE_RELATIVE; -+ raw_input.data.mouse.lLastX = raw_x = raw_val; -+ } -+ else -+ { -+ raw_input.data.mouse.usFlags = MOUSE_MOVE_ABSOLUTE | MOUSE_VIRTUAL_DESKTOP; -+ raw_input.data.mouse.lLastX = raw_x = raw_val * (65536 / (x_abs->max - x_abs->min)); -+ } - } - if (i == y_abs->number) - { -- raw_input.data.mouse.usFlags = MOUSE_MOVE_ABSOLUTE | MOUSE_VIRTUAL_DESKTOP; -- raw_input.data.mouse.lLastY = raw_y = raw_val * (65536 / (y_abs->max - y_abs->min)); -+ if (xwayland_workaround()) -+ { -+ raw_input.data.mouse.usFlags = MOUSE_MOVE_RELATIVE; -+ raw_input.data.mouse.lLastY = raw_y = raw_val; -+ } -+ else -+ { -+ raw_input.data.mouse.usFlags = MOUSE_MOVE_ABSOLUTE | MOUSE_VIRTUAL_DESKTOP; -+ raw_input.data.mouse.lLastY = raw_y = raw_val * (65536 / (y_abs->max - y_abs->min)); -+ } - } - if (i == wheel->number) - { --- -2.23.0 - diff --git a/patches/user32-rawinput/definition b/patches/user32-rawinput/definition deleted file mode 100644 index 0a83de56..00000000 --- a/patches/user32-rawinput/definition +++ /dev/null @@ -1,5 +0,0 @@ -Fixes: [42675] - Overwatch - Phantom mouse input / view pulled up to ceiling. -Fixes: [45882] - Raw Input should use untransformed mouse values (affects Overwatch, several Source games). -Fixes: [47457] - Mouse click-click-hold is treated as double click, causing gun jam in Overwatch. -Fixes: [42631] - user32: Add Raw Input support. -Disabled: True diff --git a/patches/winex11-key_translation/0001-winex11-Match-keyboard-in-Unicode.patch b/patches/winex11-key_translation/0001-winex11-Match-keyboard-in-Unicode.patch index 359e32a9..96b0db53 100644 --- a/patches/winex11-key_translation/0001-winex11-Match-keyboard-in-Unicode.patch +++ b/patches/winex11-key_translation/0001-winex11-Match-keyboard-in-Unicode.patch @@ -1,17 +1,17 @@ -From 335a6ec241f64bf4ceffc39170cfd3ab88001cb8 Mon Sep 17 00:00:00 2001 +From 614fe3af1cabb038c779700fa18dc4992747a164 Mon Sep 17 00:00:00 2001 From: Ken Thomases Date: Tue, 11 Dec 2018 08:30:41 +1100 -Subject: [PATCH 1/2] winex11: Match keyboard in Unicode +Subject: [PATCH] winex11: Match keyboard in Unicode --- dlls/winex11.drv/keyboard.c | 163 ++++++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 65 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c -index b9b8293e4d8..3f13a7331cc 100644 +index 4d113d8c184..b16d913a4a2 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c -@@ -37,6 +37,7 @@ +@@ -40,6 +40,7 @@ #include #include #include @@ -19,7 +19,7 @@ index b9b8293e4d8..3f13a7331cc 100644 #define NONAMELESSUNION -@@ -76,7 +77,7 @@ static CRITICAL_SECTION_DEBUG critsect_debug = +@@ -79,7 +80,7 @@ static CRITICAL_SECTION_DEBUG critsect_debug = }; static CRITICAL_SECTION kbd_section = { &critsect_debug, -1, 0, 0, 0, 0 }; @@ -28,9 +28,9 @@ index b9b8293e4d8..3f13a7331cc 100644 /* Keyboard translation tables */ #define MAIN_LEN 49 -@@ -1452,6 +1453,36 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) - return TRUE; +@@ -1455,6 +1456,36 @@ BOOL X11DRV_RawKeyEvent( XGenericEventCookie *cookie ) } + #endif +static WCHAR translate_keysym( Display *display, KeySym keysym ) +{ @@ -65,7 +65,7 @@ index b9b8293e4d8..3f13a7331cc 100644 /********************************************************************** * X11DRV_KEYBOARD_DetectLayout * -@@ -1468,8 +1499,8 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) +@@ -1471,8 +1502,8 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) KeySym keysym = 0; const char (*lkey)[MAIN_LEN][4]; unsigned max_seq = 0; @@ -76,7 +76,7 @@ index b9b8293e4d8..3f13a7331cc 100644 syms = keysyms_per_keycode; if (syms > 4) { -@@ -1482,35 +1513,25 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) +@@ -1485,35 +1516,25 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) /* get data for keycode from X server */ for (i = 0; i < syms; i++) { if (!(keysym = keycode_to_keysym (display, keyc, i))) continue; @@ -120,7 +120,7 @@ index b9b8293e4d8..3f13a7331cc 100644 for (keyc = min_keycode; keyc <= max_keycode; keyc++) { if (ckey[keyc][0]) { /* search for a match in layout table */ -@@ -1519,10 +1540,13 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) +@@ -1522,10 +1543,13 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) /* the table, it's okay that the X server has "3#£", for example) */ /* however, the score will be higher for longer matches */ for (key = 0; key < MAIN_LEN; key++) { @@ -137,7 +137,7 @@ index b9b8293e4d8..3f13a7331cc 100644 ok = -1; } if (ok > 0) { -@@ -1537,11 +1561,7 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) +@@ -1540,11 +1564,7 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) if (key > pkey) seq++; pkey = key; } else { @@ -150,7 +150,7 @@ index b9b8293e4d8..3f13a7331cc 100644 mismatch++; score -= syms; } -@@ -1648,9 +1668,11 @@ void X11DRV_InitKeyboard( Display *display ) +@@ -1651,9 +1671,11 @@ void X11DRV_InitKeyboard( Display *display ) XKeyEvent e2; WORD scan, vkey; int keyc, i, keyn, syms; @@ -163,7 +163,7 @@ index b9b8293e4d8..3f13a7331cc 100644 /* Ranges of OEM, function key, and character virtual key codes. * Don't include those handled specially in X11DRV_ToUnicodeEx and -@@ -1707,7 +1729,11 @@ void X11DRV_InitKeyboard( Display *display ) +@@ -1710,7 +1732,11 @@ void X11DRV_InitKeyboard( Display *display ) /* Detect the keyboard layout */ X11DRV_KEYBOARD_DetectLayout( display ); lkey = main_key_tab[kbd_layout].key; @@ -175,7 +175,7 @@ index b9b8293e4d8..3f13a7331cc 100644 /* Now build two conversion arrays : * keycode -> vkey + scancode + extended -@@ -1748,26 +1774,14 @@ void X11DRV_InitKeyboard( Display *display ) +@@ -1751,26 +1777,14 @@ void X11DRV_InitKeyboard( Display *display ) int maxlen=0,maxval=-1,ok; for (i=0; imaxlen)) { maxlen=i; maxval=keyn; -@@ -2369,7 +2383,7 @@ INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize) +@@ -2388,7 +2402,7 @@ INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize) /*********************************************************************** * X11DRV_KEYBOARD_MapDeadKeysym */ @@ -216,7 +216,7 @@ index b9b8293e4d8..3f13a7331cc 100644 { switch (keysym) { -@@ -2379,65 +2393,84 @@ static char KEYBOARD_MapDeadKeysym(KeySym keysym) +@@ -2398,65 +2412,84 @@ static char KEYBOARD_MapDeadKeysym(KeySym keysym) #endif case 0x1000FE7E : /* Xfree's XK_Dtilde */ return '~'; /* '? */ @@ -316,7 +316,7 @@ index b9b8293e4d8..3f13a7331cc 100644 */ } TRACE("no character for dead keysym 0x%08lx\n",keysym); -@@ -2622,7 +2655,7 @@ INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState +@@ -2641,7 +2674,7 @@ INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState if (ret == 0) { @@ -325,7 +325,7 @@ index b9b8293e4d8..3f13a7331cc 100644 #ifdef XK_EuroSign /* An ugly hack for EuroSign: X can't translate it to a character -@@ -2646,7 +2679,7 @@ INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState +@@ -2665,7 +2698,7 @@ INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState dead_char = KEYBOARD_MapDeadKeysym(keysym); if (dead_char) { @@ -335,5 +335,5 @@ index b9b8293e4d8..3f13a7331cc 100644 goto found; } -- -2.19.2 +2.24.0