The major problem with adding true rawinput support is that there is no way suppress auto-generating rawinput events on normal motion events. We end up with the normal "accelerated" motion being translated to relative input and xinput2 clashing with that. We really just want the "unaccelerated" input and thus need to prevent a normal motion event from generating rawinput.
This patch set does two main things: - Add plumbing to server to allow graphics driver to prevent the server from making rawinput from INPUT_MOUSE and INPUT_KEYBOARD events so a graphics driver can inject its own INPUT_HARDWARE events with impunity. - Major refactor for x11drv xinput2 (listen for events based on focus, use raw unaccelerated values for XI_RawMotion)
I have a version of this patch that is a minimal diff to the x11drv xinput2 handler (maybe I got carried away here...), but I think it might be better to focus on the send_hardware_message() plumbing to make sure it is good for other graphics drivers.
Tested on XWayland only with MouseTester.exe (https://github.com/microe1/MouseTester/releases) and Quake Live (ported this set of patches to proton).
-- v4: x11drv: lets get raw input really working
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/message.c | 6 ++++++ server/queue.c | 3 +++ 2 files changed, 9 insertions(+)
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index d2909339983..961d2c0dc09 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3486,6 +3486,12 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r req->input.hw.rawinput.type = rawinput->header.dwType; switch (rawinput->header.dwType) { + case RIM_TYPEMOUSE: + req->input.hw.rawinput.mouse.x = rawinput->data.mouse.lLastX; + req->input.hw.rawinput.mouse.y = rawinput->data.mouse.lLastY; + req->input.hw.rawinput.mouse.data = rawinput->data.mouse.ulRawButtons; + req->input.hw.lparam = rawinput->data.mouse.usFlags; + break; case RIM_TYPEHID: req->input.hw.rawinput.hid.device = HandleToUlong( rawinput->header.hDevice ); req->input.hw.rawinput.hid.param = rawinput->header.wParam; diff --git a/server/queue.c b/server/queue.c index 0558bd111f9..f609ce4478b 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2141,6 +2141,9 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ msg_data->size = sizeof(*msg_data) + report_size; msg_data->rawinput = input->hw.rawinput;
+ if (input->hw.msg == WM_INPUT && input->hw.rawinput.type == RIM_TYPEMOUSE) + msg_data->flags = input->hw.lparam; + enum_processes( queue_rawinput_message, &raw_msg ); return; }
From: EBADBEEF errno@ebadf.com
The "noraw" flags are used to mask off the original event flags. They are applied to INPUT_MOUSE and INPUT_KEYBOARD events to prevent generating a rawinput. --- include/wine/server_protocol.h | 2 ++ server/protocol.def | 2 ++ server/queue.c | 23 +++++++++++++++++------ server/trace.c | 9 +++++---- 4 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index a392b532f4e..1ba7b3dd3c7 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -327,6 +327,7 @@ typedef union unsigned short vkey; unsigned short scan; unsigned int flags; + unsigned int noraw; unsigned int time; lparam_t info; } kbd; @@ -337,6 +338,7 @@ typedef union int y; unsigned int data; unsigned int flags; + unsigned int noraw; unsigned int time; lparam_t info; } mouse; diff --git a/server/protocol.def b/server/protocol.def index e9195df6b65..6c329c44e20 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -343,6 +343,7 @@ typedef union unsigned short vkey; /* virtual key code */ unsigned short scan; /* scan code */ unsigned int flags; /* event flags */ + unsigned int noraw; /* flags to suppress rawinput generation */ unsigned int time; /* event time */ lparam_t info; /* extra info */ } kbd; @@ -353,6 +354,7 @@ typedef union int y; unsigned int data; /* mouse data */ unsigned int flags; /* event flags */ + unsigned int noraw; /* flags to suppress rawinput generation */ unsigned int time; /* event time */ lparam_t info; /* extra info */ } mouse; diff --git a/server/queue.c b/server/queue.c index f609ce4478b..a49c47c346b 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1864,6 +1864,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons unsigned int i, time, flags; struct hw_msg_source source = { IMDT_MOUSE, origin }; int wait = 0, x, y; + unsigned int raw_flags;
static const unsigned int messages[] = { @@ -1884,6 +1885,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
desktop->cursor.last_change = get_tick_count(); flags = input->mouse.flags; + raw_flags = (input->mouse.flags & ~input->mouse.noraw); time = input->mouse.time; if (!time) time = desktop->cursor.last_change;
@@ -1896,6 +1898,10 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons if (flags & ~(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE) && x == desktop->cursor.x && y == desktop->cursor.y) flags &= ~MOUSEEVENTF_MOVE; + + /* rawinput does not currently support absolute events which + * use (65535,65535) coordinate space */ + raw_flags &= ~MOUSEEVENTF_ABSOLUTE; } else { @@ -1909,7 +1915,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons y = desktop->cursor.y; }
- if ((foreground = get_foreground_thread( desktop, win ))) + if (raw_flags && (foreground = get_foreground_thread( desktop, win ))) { memset( &raw_msg, 0, sizeof(raw_msg) ); raw_msg.foreground = foreground; @@ -1921,10 +1927,13 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons msg_data = &raw_msg.data; msg_data->info = input->mouse.info; msg_data->size = sizeof(*msg_data); - msg_data->flags = flags; + msg_data->flags = raw_flags; + if (raw_flags & MOUSEEVENTF_MOVE) + { + msg_data->rawinput.mouse.x = x - desktop->cursor.x; + msg_data->rawinput.mouse.y = y - desktop->cursor.y; + } 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;
enum_processes( queue_rawinput_message, &raw_msg ); @@ -1980,6 +1989,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c unsigned char vkey = input->kbd.vkey; unsigned int message_code, time; int wait; + unsigned int raw_flags;
if (!(time = input->kbd.time)) time = get_tick_count();
@@ -2047,7 +2057,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c break; }
- if ((foreground = get_foreground_thread( desktop, win ))) + raw_flags = (input->kbd.flags & ~input->kbd.noraw); + if (raw_flags && (foreground = get_foreground_thread( desktop, win ))) { memset( &raw_msg, 0, sizeof(raw_msg) ); raw_msg.foreground = foreground; @@ -2059,7 +2070,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c msg_data = &raw_msg.data; msg_data->info = input->kbd.info; msg_data->size = sizeof(*msg_data); - msg_data->flags = input->kbd.flags; + msg_data->flags = raw_flags; msg_data->rawinput.type = RIM_TYPEKEYBOARD; msg_data->rawinput.kbd.message = message_code; msg_data->rawinput.kbd.vkey = vkey; diff --git a/server/trace.c b/server/trace.c index 55ccefa1746..ecbd1735e62 100644 --- a/server/trace.c +++ b/server/trace.c @@ -449,15 +449,16 @@ static void dump_hw_input( const char *prefix, const hw_input_t *input ) switch (input->type) { case INPUT_MOUSE: - fprintf( stderr, "%s{type=MOUSE,x=%d,y=%d,data=%08x,flags=%08x,time=%u", + fprintf( stderr, "%s{type=MOUSE,x=%d,y=%d,data=%08x,flags=%08x,noraw=%08x,time=%u", prefix, input->mouse.x, input->mouse.y, input->mouse.data, input->mouse.flags, - input->mouse.time ); + input->mouse.noraw, input->mouse.time ); dump_uint64( ",info=", &input->mouse.info ); fputc( '}', stderr ); break; case 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 ); + fprintf( stderr, "%s{type=KEYBOARD,vkey=%04hx,scan=%04hx,flags=%08x,noraw=%08x,time=%u", + prefix, input->kbd.vkey, input->kbd.scan, input->kbd.flags, input->kbd.noraw, + input->kbd.time ); dump_uint64( ",info=", &input->kbd.info ); fputc( '}', stderr ); break;
From: EBADBEEF errno@ebadf.com
This is plumbing for a graphics driver to be responsible for rawinput events (instead of letting the server generate them). --- dlls/hidclass.sys/device.c | 2 +- dlls/hidclass.sys/pnp.c | 2 +- dlls/win32u/input.c | 7 ++++--- dlls/win32u/message.c | 4 +++- dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 2 +- dlls/wineandroid.drv/keyboard.c | 2 +- dlls/wineandroid.drv/window.c | 4 ++-- dlls/winemac.drv/keyboard.c | 2 +- dlls/winemac.drv/mouse.c | 2 +- dlls/winewayland.drv/wayland_pointer.c | 6 +++--- dlls/winex11.drv/keyboard.c | 2 +- dlls/winex11.drv/mouse.c | 8 ++++---- include/ntuser.h | 2 +- 14 files changed, 25 insertions(+), 22 deletions(-)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index d673a8c2e88..512e533c796 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -252,7 +252,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack input.hi.uMsg = WM_INPUT; input.hi.wParamH = 0; input.hi.wParamL = 0; - __wine_send_input( 0, &input, rawinput ); + __wine_send_input( 0, &input, rawinput, 0 );
free( rawinput ); } diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index ab3cd5b2cb5..c47962f676f 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -134,7 +134,7 @@ static void send_wm_input_device_change(BASE_DEVICE_EXTENSION *ext, LPARAM param input.hi.uMsg = WM_INPUT_DEVICE_CHANGE; input.hi.wParamH = 0; input.hi.wParamL = 0; - __wine_send_input(0, &input, &rawinput); + __wine_send_input(0, &input, &rawinput, 0); }
static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *bus_pdo) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 3e6e440de93..a3fd0df0c5a 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -599,10 +599,11 @@ BOOL WINAPI NtUserAttachThreadInput( DWORD from, DWORD to, BOOL attach ) * __wine_send_input (win32u.@) * * Internal SendInput function to allow the graphics driver to inject real events. + * */ -BOOL WINAPI __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput ) +BOOL WINAPI __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput, UINT noraw_flags ) { - return set_ntstatus( send_hardware_message( hwnd, input, rawinput, 0 )); + return set_ntstatus( send_hardware_message( hwnd, input, rawinput, 0, noraw_flags )); }
/*********************************************************************** @@ -684,7 +685,7 @@ UINT WINAPI NtUserSendInput( UINT count, INPUT *inputs, int size ) update_mouse_coords( &input ); /* fallthrough */ case INPUT_KEYBOARD: - status = send_hardware_message( 0, &input, NULL, SEND_HWMSG_INJECTED ); + status = send_hardware_message( 0, &input, NULL, SEND_HWMSG_INJECTED, 0 ); break; case INPUT_HARDWARE: RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 961d2c0dc09..e9a60b1c605 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3416,7 +3416,7 @@ LRESULT send_internal_message_timeout( DWORD dest_pid, DWORD dest_tid, /*********************************************************************** * send_hardware_message */ -NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput, UINT flags ) +NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput, UINT flags, UINT noraw_flags ) { struct send_message_info info; int prev_x, prev_y, new_x, new_y; @@ -3461,6 +3461,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r req->input.mouse.y = input->mi.dy; req->input.mouse.data = input->mi.mouseData; req->input.mouse.flags = input->mi.dwFlags; + req->input.mouse.noraw = noraw_flags; req->input.mouse.time = input->mi.time; req->input.mouse.info = input->mi.dwExtraInfo; affects_key_state = !!(input->mi.dwFlags & (MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP | @@ -3472,6 +3473,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r req->input.kbd.vkey = input->ki.wVk; req->input.kbd.scan = input->ki.wScan; req->input.kbd.flags = input->ki.dwFlags; + req->input.kbd.noraw = noraw_flags; req->input.kbd.time = input->ki.time; req->input.kbd.info = input->ki.dwExtraInfo; affects_key_state = TRUE; diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 24dccb6ec1d..e14f9bf4d8c 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1322,4 +1322,4 @@
@ stdcall -syscall __wine_get_icm_profile(long long ptr ptr) @ stdcall -syscall __wine_get_file_outline_text_metric(wstr ptr ptr ptr) -@ stdcall -syscall __wine_send_input(long ptr ptr) +@ stdcall -syscall __wine_send_input(long ptr ptr long) diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 6380a0808c8..1cb5a1be72b 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -132,7 +132,7 @@ extern void track_mouse_menu_bar( HWND hwnd, INT ht, int x, int y ) DECLSPEC_HID extern BOOL kill_system_timer( HWND hwnd, UINT_PTR id ) DECLSPEC_HIDDEN; extern BOOL reply_message_result( LRESULT result ) DECLSPEC_HIDDEN; extern NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput, - UINT flags ) DECLSPEC_HIDDEN; + UINT flags, UINT noraw_flags ) DECLSPEC_HIDDEN; extern LRESULT send_internal_message_timeout( DWORD dest_pid, DWORD dest_tid, UINT msg, WPARAM wparam, LPARAM lparam, UINT flags, UINT timeout, PDWORD_PTR res_ptr ) DECLSPEC_HIDDEN; diff --git a/dlls/wineandroid.drv/keyboard.c b/dlls/wineandroid.drv/keyboard.c index 9f369094949..c430d7929e1 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.ki.time = 0; input.ki.dwExtraInfo = 0;
- __wine_send_input( hwnd, &input, NULL ); + __wine_send_input( hwnd, &input, NULL, 0 ); }
/*********************************************************************** diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index d62a2c53909..20e15465f1a 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -514,7 +514,7 @@ static int process_events( DWORD mask ) } SERVER_END_REQ; } - __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input, NULL ); + __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input, NULL, 0 ); } break;
@@ -528,7 +528,7 @@ static int process_events( DWORD mask ) event->data.kbd.input.ki.wVk, event->data.kbd.input.ki.wVk, event->data.kbd.input.ki.wScan ); update_keyboard_lock_state( event->data.kbd.input.ki.wVk, event->data.kbd.lock_state ); - __wine_send_input( 0, &event->data.kbd.input, NULL ); + __wine_send_input( 0, &event->data.kbd.input, NULL, 0 ); break;
default: diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c index bf1daa7a5df..902c1280337 100644 --- a/dlls/winemac.drv/keyboard.c +++ b/dlls/winemac.drv/keyboard.c @@ -1001,7 +1001,7 @@ static void macdrv_send_keyboard_input(HWND hwnd, WORD vkey, WORD scan, unsigned input.ki.time = time; input.ki.dwExtraInfo = 0;
- __wine_send_input(hwnd, &input, NULL); + __wine_send_input(hwnd, &input, NULL, 0); }
diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c index 2f05a33a8b5..4e3b5653425 100644 --- a/dlls/winemac.drv/mouse.c +++ b/dlls/winemac.drv/mouse.c @@ -158,7 +158,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, NULL); + __wine_send_input(top_level_hwnd, &input, NULL, 0); }
diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index ff376882d73..5d6a6248e55 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -75,7 +75,7 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, hwnd, wl_fixed_to_double(sx), wl_fixed_to_double(sy), screen_x, screen_y);
- __wine_send_input(hwnd, &input, NULL); + __wine_send_input(hwnd, &input, NULL, 0); }
static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, @@ -154,7 +154,7 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
TRACE("hwnd=%p button=%#x state=%u\n", hwnd, button, state);
- __wine_send_input(hwnd, &input, NULL); + __wine_send_input(hwnd, &input, NULL, 0); }
static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, @@ -201,7 +201,7 @@ static void pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_point
TRACE("hwnd=%p axis=%u discrete=%d\n", hwnd, axis, discrete);
- __wine_send_input(hwnd, &input, NULL); + __wine_send_input(hwnd, &input, NULL, 0); }
static const struct wl_pointer_listener pointer_listener = diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 5c7f6c37276..895b106297d 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1132,7 +1132,7 @@ static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, UINT fl input.ki.time = time; input.ki.dwExtraInfo = 0;
- __wine_send_input( hwnd, &input, NULL ); + __wine_send_input( hwnd, &input, NULL, 0 ); }
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 612fff9995c..2ea007ab588 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -528,7 +528,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU { struct x11drv_thread_data *thread_data = x11drv_thread_data(); if (!thread_data->clipping_cursor || thread_data->clip_window != window) return; - __wine_send_input( hwnd, input, NULL ); + __wine_send_input( hwnd, input, NULL, 0 ); return; }
@@ -555,7 +555,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU SERVER_END_REQ; }
- __wine_send_input( hwnd, input, NULL ); + __wine_send_input( hwnd, input, NULL, 0 ); }
#ifdef SONAME_LIBXCURSOR @@ -1498,7 +1498,7 @@ void move_resize_window( HWND hwnd, int dir ) input.mi.dwFlags = button_up_flags[button - 1] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; input.mi.time = NtGetTickCount(); input.mi.dwExtraInfo = 0; - __wine_send_input( hwnd, &input, NULL ); + __wine_send_input( hwnd, &input, NULL, 0 ); }
while (NtUserPeekMessage( &msg, 0, 0, 0, PM_REMOVE )) @@ -1747,7 +1747,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) input.mi.dy = 0; if (!map_raw_event_coords( event, &input )) return FALSE;
- __wine_send_input( 0, &input, NULL ); + __wine_send_input( 0, &input, NULL, 0 ); return TRUE; }
diff --git a/include/ntuser.h b/include/ntuser.h index def89a82aff..05859762036 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -1387,6 +1387,6 @@ static inline BOOL NtUserShowOwnedPopups( HWND hwnd, BOOL show ) }
/* Wine extensions */ -W32KAPI BOOL WINAPI __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput ); +W32KAPI BOOL WINAPI __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput, UINT noraw_flags );
#endif /* _NTUSER_ */
From: EBADBEEF errno@ebadf.com
--- dlls/win32u/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index a3fd0df0c5a..2729799eeef 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -685,7 +685,7 @@ UINT WINAPI NtUserSendInput( UINT count, INPUT *inputs, int size ) update_mouse_coords( &input ); /* fallthrough */ case INPUT_KEYBOARD: - status = send_hardware_message( 0, &input, NULL, SEND_HWMSG_INJECTED, 0 ); + status = send_hardware_message( 0, &input, NULL, SEND_HWMSG_INJECTED, 0xFFFF ); break; case INPUT_HARDWARE: RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
From: EBADBEEF errno@ebadf.com
The function process_rawinput_message() can be called multiple times per event (PeekMessage and GetMessage). Re-processing the message is harmless but helps make the tracing clear. --- dlls/win32u/rawinput.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/rawinput.c b/dlls/win32u/rawinput.c index bd2e00a31c4..b271a40c8fc 100644 --- a/dlls/win32u/rawinput.c +++ b/dlls/win32u/rawinput.c @@ -128,11 +128,14 @@ static bool rawinput_from_hardware_message( RAWINPUT *rawinput, const struct har else if (msg_data->rawinput.mouse.data == XBUTTON2) rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_5_UP; } - rawinput->data.mouse.ulRawButtons = 0; rawinput->data.mouse.lLastX = msg_data->rawinput.mouse.x; rawinput->data.mouse.lLastY = msg_data->rawinput.mouse.y; rawinput->data.mouse.ulExtraInformation = msg_data->info; + + TRACE("x=%d y=%d buttons=%08x flags=%08x\n", + (int)rawinput->data.mouse.lLastX, (int)rawinput->data.mouse.lLastY, + rawinput->data.mouse.usButtonFlags, msg_data->flags); } else if (msg_data->rawinput.type == RIM_TYPEKEYBOARD) { @@ -786,7 +789,8 @@ BOOL process_rawinput_message( MSG *msg, UINT hw_id, const struct hardware_msg_d else { thread_data->buffer->header.dwSize = RAWINPUT_BUFFER_SIZE; - if (!rawinput_from_hardware_message( thread_data->buffer, msg_data )) return FALSE; + if (thread_data->hw_id != hw_id) + if (!rawinput_from_hardware_message( thread_data->buffer, msg_data )) return FALSE; thread_data->hw_id = hw_id; msg->lParam = (LPARAM)hw_id; }
From: EBADBEEF errno@ebadf.com
Major refactor of xinput2 handling.
When a window is focused, subscribe to xinput2 events. Likewise when a window is unfocused, unsubscribe from xinput2 events.
If there are any unfocused windows that want rawinput, they need to set RIDEV_INPUTSINK and wineserver will be responsible for delivering events to them.
To quote from xorg-xserver: XI 2.0: events delivered to the grabbing client (if any) OR to all root windows XI 2.1: events delivered to all root windows, regardless of grabbing state.
Using the focus/unfocus logic should hopefully still make sense. I do not think it is possible to grab a pointer from an unfocused window. However, no rawinputs would be delivered until the pointer is grabbed. For this reason I bumped the XInput2 version request to 2.1 (released Dec 2011). This could be managed another way (perhaps by setting noraw_flags based on thread_data->xi2_state). --- dlls/winex11.drv/event.c | 63 +----- dlls/winex11.drv/mouse.c | 411 ++++++++++++++------------------------ dlls/winex11.drv/x11drv.h | 11 +- 3 files changed, 150 insertions(+), 335 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 97bec34b0ea..5e024127a97 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -148,8 +148,6 @@ static const char * event_names[MAX_EVENT_HANDLERS] = /* is someone else grabbing the keyboard, for example the WM, when manipulating the window */ BOOL keyboard_grabbed = FALSE;
-int xinput2_opcode = 0; - /* return the name of an X event */ static const char *dbgstr_event( int type ) { @@ -264,46 +262,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 * @@ -338,25 +296,6 @@ static enum event_merge_action merge_events( XEvent *prev, XEvent *next ) return MERGE_DISCARD; } break; -#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - case GenericEvent: - if (next->xcookie.extension != xinput2_opcode) break; - if (next->xcookie.evtype != XI_RawMotion) break; - if (x11drv_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; - 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; - return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data ); -#endif } break; } @@ -784,6 +723,7 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE;
+ enable_xinput2(); xim_set_focus( hwnd, TRUE );
if (use_take_focus) return TRUE; @@ -807,6 +747,7 @@ static void focus_out( Display *display , HWND hwnd ) { if (xim_in_compose_mode()) return;
+ disable_xinput2(); x11drv_thread_data()->last_focus = hwnd; xim_set_focus( hwnd, FALSE );
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 2ea007ab588..0b062167d9a 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -56,6 +56,7 @@ MAKE_FUNCPTR(XcursorLibraryLoadCursor); #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(cursor); +WINE_DECLARE_DEBUG_CHANNEL(rawinput);
/**********************************************************************/
@@ -120,6 +121,8 @@ static const UINT button_up_data[NB_BUTTONS] = XBUTTON2 };
+static unsigned int noraw_flags = 0; + XContext cursor_context = 0;
static RECT clip_rect; @@ -128,10 +131,8 @@ static Cursor create_cursor( HANDLE handle ); #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H static BOOL xinput2_available; static BOOL broken_rawevents; +static int xinput2_opcode; #define MAKE_FUNCPTR(f) static typeof(f) * p##f -MAKE_FUNCPTR(XIGetClientPointer); -MAKE_FUNCPTR(XIFreeDeviceInfo); -MAKE_FUNCPTR(XIQueryDevice); MAKE_FUNCPTR(XIQueryVersion); MAKE_FUNCPTR(XISelectEvents); #undef MAKE_FUNCPTR @@ -224,121 +225,6 @@ void set_window_cursor( Window window, HCURSOR handle ) XFlush( gdi_display ); }
-#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H -/*********************************************************************** - * update_relative_valuators - */ -static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuators) -{ - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - int i; - - thread_data->x_valuator.number = -1; - thread_data->y_valuator.number = -1; - - for (i = 0; i < n_valuators; i++) - { - XIValuatorClassInfo *class = (XIValuatorClassInfo *)valuators[i]; - if (valuators[i]->type != XIValuatorClass) continue; - if (class->label == x11drv_atom( Rel_X ) || - (!class->label && class->number == 0 && class->mode == XIModeRelative)) - thread_data->x_valuator = *class; - else if (class->label == x11drv_atom( Rel_Y ) || - (!class->label && class->number == 1 && class->mode == XIModeRelative)) - thread_data->y_valuator = *class; - } - - thread_data->x_valuator.value = 0; - thread_data->y_valuator.value = 0; -} - - -/*********************************************************************** - * enable_xinput2 - */ -static void enable_xinput2(void) -{ - struct x11drv_thread_data *data = x11drv_thread_data(); - XIEventMask mask; - XIDeviceInfo *pointer_info; - unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)]; - int count; - - if (!xinput2_available) return; - - if (data->xi2_state == xi_unknown) - { - int major = 2, minor = 0; - if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled; - else - { - data->xi2_state = xi_unavailable; - WARN( "X Input 2 not available\n" ); - } - } - if (data->xi2_state == xi_unavailable) return; - if (!pXIGetClientPointer( data->display, None, &data->xi2_core_pointer )) return; - - mask.mask = mask_bits; - mask.mask_len = sizeof(mask_bits); - mask.deviceid = XIAllDevices; - memset( mask_bits, 0, sizeof(mask_bits) ); - XISetMask( mask_bits, XI_DeviceChanged ); - XISetMask( mask_bits, XI_RawMotion ); - XISetMask( mask_bits, XI_ButtonPress ); - - pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); - - pointer_info = pXIQueryDevice( data->display, data->xi2_core_pointer, &count ); - 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 - -/*********************************************************************** - * disable_xinput2 - */ -static void disable_xinput2(void) -{ -#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - struct x11drv_thread_data *data = x11drv_thread_data(); - XIEventMask mask; - - if (data->xi2_state != xi_enabled) return; - - TRACE( "disabling\n" ); - data->xi2_state = xi_disabled; - - mask.mask = NULL; - mask.mask_len = 0; - mask.deviceid = XIAllDevices; - - pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); - pXIFreeDeviceInfo( data->xi2_devices ); - data->x_valuator.number = -1; - data->y_valuator.number = -1; - data->x_valuator.value = 0; - data->y_valuator.value = 0; - data->xi2_devices = NULL; - data->xi2_core_pointer = 0; - data->xi2_current_slave = 0; -#endif -} - - /*********************************************************************** * grab_clipping_window * @@ -346,7 +232,6 @@ static void disable_xinput2(void) */ static BOOL grab_clipping_window( const RECT *clip ) { -#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H struct x11drv_thread_data *data = x11drv_thread_data(); Window clip_window; HCURSOR cursor; @@ -360,22 +245,11 @@ static BOOL grab_clipping_window( const RECT *clip ) if (!data) return FALSE; if (!(clip_window = init_clip_window())) return TRUE;
- if (keyboard_grabbed) - { + if (keyboard_grabbed) { WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); return FALSE; }
- /* enable XInput2 unless we are already clipping */ - if (!data->clipping_cursor) enable_xinput2(); - - if (data->xi2_state != xi_enabled) - { - WARN( "XInput2 not supported, refusing to clip to %s\n", wine_dbgstr_rect(clip) ); - NtUserClipCursor( NULL ); - return TRUE; - } - TRACE( "clipping to %s win %lx\n", wine_dbgstr_rect(clip), clip_window );
if (!data->clipping_cursor) XUnmapWindow( data->display, clip_window ); @@ -405,18 +279,12 @@ static BOOL grab_clipping_window( const RECT *clip )
set_window_cursor( clip_window, cursor );
- if (!clipping_cursor) - { - disable_xinput2(); + if (!clipping_cursor) { return FALSE; } clip_rect = *clip; data->clipping_cursor = TRUE; return TRUE; -#else - WARN( "XInput2 was not available at compile time\n" ); - return FALSE; -#endif }
/*********************************************************************** @@ -436,7 +304,6 @@ void ungrab_clipping_window(void) if (clipping_cursor) XUngrabPointer( data->display, CurrentTime ); clipping_cursor = FALSE; data->clipping_cursor = FALSE; - disable_xinput2(); }
/*********************************************************************** @@ -528,7 +395,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU { struct x11drv_thread_data *thread_data = x11drv_thread_data(); if (!thread_data->clipping_cursor || thread_data->clip_window != window) return; - __wine_send_input( hwnd, input, NULL, 0 ); + __wine_send_input( hwnd, input, NULL, noraw_flags ); return; }
@@ -555,7 +422,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU SERVER_END_REQ; }
- __wine_send_input( hwnd, input, NULL, 0 ); + __wine_send_input( hwnd, input, NULL, noraw_flags ); }
#ifdef SONAME_LIBXCURSOR @@ -1498,7 +1365,7 @@ void move_resize_window( HWND hwnd, int dir ) input.mi.dwFlags = button_up_flags[button - 1] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; input.mi.time = NtGetTickCount(); input.mi.dwExtraInfo = 0; - __wine_send_input( hwnd, &input, NULL, 0 ); + __wine_send_input( hwnd, &input, NULL, noraw_flags ); }
while (NtUserPeekMessage( &msg, 0, 0, 0, PM_REMOVE )) @@ -1634,133 +1501,163 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev ) }
#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - /*********************************************************************** - * X11DRV_DeviceChanged + * X11DRV_RawMotion */ -static BOOL X11DRV_DeviceChanged( XGenericEventCookie *xev ) -{ - XIDeviceChangedEvent *event = xev->data; - struct x11drv_thread_data *data = x11drv_thread_data(); - - if (event->deviceid != data->xi2_core_pointer) return FALSE; - if (event->reason != XISlaveSwitch) return FALSE; - - update_relative_valuators( event->classes, event->num_classes ); - data->xi2_current_slave = event->sourceid; - return TRUE; -} - -static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) +static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) { - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - XIValuatorClassInfo *x = &thread_data->x_valuator, *y = &thread_data->y_valuator; - double x_value = 0, y_value = 0, x_scale, y_scale; - const double *values = event->valuators.values; - RECT virtual_rect; + XIRawEvent *event = xev->data; + const double *values = event->raw_values; + RAWINPUT rawinput; + INPUT input; int i;
- if (x->number < 0 || y->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. + /* Any mouse motion on any X11 window will generate xinput2 events to *all* + * X11 windows. If focus is not a good way to determine if a thread wants + * to get raw input events then we can make xinput2 always-on and filter + * out the noisy events: + * if (thread_data->xi2_state != xi2_enabled) return FALSE; */ - 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 (broken_rawevents && is_old_motion_event( xev->serial )) + { + TRACE( "old serial %lu, ignoring\n", xev->serial ); + return FALSE; } - if (event->deviceid != thread_data->xi2_current_slave) return FALSE;
- virtual_rect = NtUserGetVirtualScreenRect(); + rawinput.data.mouse.lLastX = 0; + rawinput.data.mouse.lLastY = 0;
- if (x->max <= x->min) x_scale = 1; - else x_scale = (virtual_rect.right - virtual_rect.left) / (x->max - x->min); - if (y->max <= y->min) y_scale = 1; - else y_scale = (virtual_rect.bottom - virtual_rect.top) / (y->max - y->min); - - for (i = 0; i <= max( x->number, y->number ); i++) + /* it would be better to parse these, but X and Y are always 0 and 1, + * respectively. */ + for (i = 0; i < 2; i++) { - if (!XIMaskIsSet( event->valuators.mask, i )) continue; - if (i == x->number) - { - x_value = *values; - x->value += x_value * x_scale; - } - if (i == y->number) - { - y_value = *values; - y->value += y_value * y_scale; + if (XIMaskIsSet( event->valuators.mask, i )) { + if (i == 0) { + rawinput.data.mouse.lLastX = *values; + } else if (i == 1) { + rawinput.data.mouse.lLastY = *values; + } } values++; }
- input->mi.dx = round( x->value ); - input->mi.dy = round( y->value ); + /* ignore scroll events for now */ + if (rawinput.data.mouse.lLastX == 0 && + rawinput.data.mouse.lLastY == 0) return FALSE;
- TRACE( "event %f,%f value %f,%f input %d,%d\n", x_value, y_value, x->value, y->value, - (int)input->mi.dx, (int)input->mi.dy ); + input.type = INPUT_HARDWARE; + input.hi.uMsg = WM_INPUT; + input.hi.wParamH = 0; + input.hi.wParamL = 0;
- x->value -= input->mi.dx; - y->value -= input->mi.dy; + rawinput.header.dwType = RIM_TYPEMOUSE; + rawinput.header.dwSize = offsetof(RAWINPUT, data) + sizeof(RAWMOUSE); + rawinput.header.hDevice = ULongToHandle(1); /* WINE_MOUSE_HANDLE */ + rawinput.header.wParam = RIM_INPUT; + rawinput.data.mouse.usFlags = MOUSEEVENTF_MOVE; + rawinput.data.mouse.ulRawButtons = 0; + rawinput.data.mouse.usButtonData = 0; + rawinput.data.mouse.usButtonFlags = 0; + rawinput.data.mouse.ulExtraInformation = 0;
- if (!input->mi.dx && !input->mi.dy) - { - TRACE( "accumulating motion\n" ); - return FALSE; - } + TRACE_(rawinput)("sending raw input x=%d y=%d\n", + (int)rawinput.data.mouse.lLastX, (int)rawinput.data.mouse.lLastY); + + __wine_send_input( 0, &input, &rawinput, 0 );
return TRUE; } +#endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */
/*********************************************************************** - * X11DRV_RawMotion + * enable_xinput2 */ -static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) +void enable_xinput2(void) { - XIRawEvent *event = xev->data; - INPUT input; +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + struct x11drv_thread_data *data = x11drv_thread_data(); + XIEventMask mask;
- if (broken_rawevents && is_old_motion_event( xev->serial )) - { - TRACE( "old serial %lu, ignoring\n", xev->serial ); - return FALSE; - } + if (!data) return; + if (!xinput2_available) return; + if (data->xi2_state == xi_enabled) return;
- input.type = INPUT_MOUSE; - input.mi.mouseData = 0; - input.mi.dwFlags = MOUSEEVENTF_MOVE; - input.mi.time = EVENT_x11_time_to_win32_time( event->time ); - input.mi.dwExtraInfo = 0; - input.mi.dx = 0; - input.mi.dy = 0; - if (!map_raw_event_coords( event, &input )) return FALSE; + mask.deviceid = XIMasterPointer; + mask.mask_len = XIMaskLen(XI_LASTEVENT); + mask.mask = calloc(mask.mask_len, sizeof(char));
- __wine_send_input( 0, &input, NULL, 0 ); - return TRUE; + XISetMask(mask.mask, XI_RawMotion); + + pXISelectEvents(data->display, DefaultRootWindow( data->display ), &mask, 1); + + free(mask.mask); + + data->xi2_state = xi_enabled; + TRACE("xinput2 enabled"); +#endif }
-#endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ +/*********************************************************************** + * disable_xinput2 + */ +void disable_xinput2(void) +{ +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + struct x11drv_thread_data *data = x11drv_thread_data(); + XIEventMask mask; + + if (!data) return; + if (data->xi2_state != xi_enabled) return; + + mask.deviceid = XIMasterPointer; + mask.mask = NULL; + mask.mask_len = 0; + + pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); + + data->xi2_state = xi_disabled; + TRACE("xinput2 disabled"); +#endif +} + +/*********************************************************************** + * X11DRV_GenericEvent + */ +BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev ) +{ + BOOL ret = FALSE; + XGenericEventCookie *event = &xev->xcookie; + + if (!event->data) return FALSE; +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + if (event->extension != xinput2_opcode) return FALSE; +#endif
+ switch (event->evtype) + { +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + case XI_RawMotion: + ret = X11DRV_RawMotion( event ); + break; +#endif + + default: + TRACE( "Unhandled event %#x\n", event->evtype ); + break; + } + return ret; +}
/*********************************************************************** * X11DRV_XInput2_Init */ void X11DRV_XInput2_Init(void) { -#if defined(SONAME_LIBXI) && defined(HAVE_X11_EXTENSIONS_XINPUT2_H) +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H int event, error; + int xi2maj = 2, xi2min = 1; +#ifdef SONAME_LIBXI void *libxi_handle = dlopen( SONAME_LIBXI, RTLD_NOW );
if (!libxi_handle) @@ -1768,58 +1665,40 @@ void X11DRV_XInput2_Init(void) WARN( "couldn't load %s\n", SONAME_LIBXI ); return; } + #define LOAD_FUNCPTR(f) \ if (!(p##f = dlsym( libxi_handle, #f))) \ { \ WARN("Failed to load %s.\n", #f); \ return; \ } - - LOAD_FUNCPTR(XIGetClientPointer); - LOAD_FUNCPTR(XIFreeDeviceInfo); - LOAD_FUNCPTR(XIQueryDevice); LOAD_FUNCPTR(XIQueryVersion); LOAD_FUNCPTR(XISelectEvents); #undef LOAD_FUNCPTR +#endif
- xinput2_available = XQueryExtension( gdi_display, "XInputExtension", &xinput2_opcode, &event, &error ); + if (FALSE == XQueryExtension( gdi_display, "XInputExtension", &xinput2_opcode, &event, &error )) + { + WARN( "X server missing XInputExtension, cannot use XInput2\n" ); + return; + }
/* Until version 1.10.4 rawinput was broken in XOrg, see * https://bugs.freedesktop.org/show_bug.cgi?id=30068 */ broken_rawevents = strstr(XServerVendor( gdi_display ), "X.Org") && XVendorRelease( gdi_display ) < 11004000;
-#else - TRACE( "X Input 2 support not compiled in.\n" ); -#endif -} - - -/*********************************************************************** - * X11DRV_GenericEvent - */ -BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev ) -{ - BOOL ret = FALSE; -#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - XGenericEventCookie *event = &xev->xcookie; - - if (!event->data) return FALSE; - if (event->extension != xinput2_opcode) return FALSE; - - switch (event->evtype) + if (Success == pXIQueryVersion( gdi_display, &xi2maj, &xi2min )) { - case XI_DeviceChanged: - ret = X11DRV_DeviceChanged( event ); - break; - case XI_RawMotion: - ret = X11DRV_RawMotion( event ); - break; - - default: - TRACE( "Unhandled event %#x\n", event->evtype ); - break; + TRACE("XInput2 version %d.%d detected\n", xi2maj, xi2min); + xinput2_available = TRUE; + noraw_flags = MOUSEEVENTF_MOVE; + } + else + { + WARN( "XInput2 >= 2.1 not found\n" ); } +#else + TRACE( "XInput2 support not compiled in.\n" ); #endif - return ret; } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 2c15a95dfab..5535f6d52d8 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -262,6 +262,8 @@ extern void X11DRV_ThreadDetach(void) DECLSPEC_HIDDEN;
extern void X11DRV_Xcursor_Init(void) DECLSPEC_HIDDEN; extern void X11DRV_XInput2_Init(void) DECLSPEC_HIDDEN; +extern void enable_xinput2(void) DECLSPEC_HIDDEN; +extern void disable_xinput2(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, @@ -391,13 +393,7 @@ struct x11drv_thread_data Window clip_window; /* window used for cursor clipping */ BOOL clipping_cursor; /* whether thread is currently clipping the cursor */ #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - 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; - XIValuatorClassInfo x_valuator; - XIValuatorClassInfo y_valuator; - int xi2_core_pointer; /* XInput2 core pointer id */ - int xi2_current_slave; /* Current slave driving the Core pointer */ + enum { xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ };
@@ -575,7 +571,6 @@ extern BOOL X11DRV_SelectionClear( HWND hWnd, XEvent *event ) DECLSPEC_HIDDEN; extern BOOL X11DRV_MappingNotify( HWND hWnd, XEvent *event ) DECLSPEC_HIDDEN; extern BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN;
-extern int xinput2_opcode DECLSPEC_HIDDEN; extern Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) DECLSPEC_HIDDEN; extern void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) DECLSPEC_HIDDEN;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=139741
Your paranoid android.
=== debian11b (64 bit WoW report) ===
dinput: device8.c:325: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:329: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:334: Test failed: 0x800: got count 0 device8.c:340: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:345: Test failed: 0x800: got count 0 device8.c:353: Test failed: 0x800: keydown for D did not register device8.c:360: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:365: Test failed: 0x800: got count 0 device8.c:387: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:391: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:396: Test failed: 0x800: got count 0 device8.c:403: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:409: Test failed: 0x800: got count 0 device8.c:425: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:431: Test failed: 0x800: got count 0 device8.c:1499: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:1504: Test failed: 0x800: got count 0 device8.c:1508: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:1528: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:1539: Test failed: 0x800: GetDeviceData returned 0 device8.c:1540: Test failed: 0x800: got count 0 device8.c:1549: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:1555: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:1555: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:1560: Test failed: 0x800: GetDeviceData returned 0 device8.c:1566: Test failed: 0x800: got count 0 device8.c:2233: Test failed: 0x800: WaitForSingleObject returned 0x102 device8.c:1698: Test failed: 0x800: lang 0x409: key 0x51, dik 0x10: got state 0 device8.c:1698: Test failed: 0x800: lang 0x409: key 0x57, dik 0x11: got state 0 device8.c:1698: Test failed: 0x800: lang 0x409: key 0x45, dik 0x12: got state 0 device8.c:1698: Test failed: 0x800: lang 0x409: key 0x52, dik 0x13: got state 0 device8.c:1698: Test failed: 0x800: lang 0x409: key 0x54, dik 0x14: got state 0 device8.c:1698: Test failed: 0x800: lang 0x409: key 0x59, dik 0x15: got state 0 device8.c:1698: Test failed: 0x800: lang 0x409: key 0x5b, dik 0x1a: got state 0 device8.c:1698: Test failed: 0x800: lang 0x409: key 0x5d, dik 0x1b: got state 0 device8: Timeout
user32: input.c:2462: Test failed: GetRawInputBuffer succeeded input.c:2463: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2464: Test failed: GetRawInputBuffer returned deadbeef input.c:2469: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2495: Test failed: GetRawInputBuffer returned 0 input.c:2496: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2499: Test failed: Unexpected rawinput data: 0 input.c:2510: Test failed: GetRawInputBuffer succeeded input.c:2511: Test failed: GetRawInputBuffer returned deadbeef input.c:2512: Test failed: Unexpected rawinput data: 0 input.c:2553: Test failed: GetRawInputBuffer returned 0 input.c:2554: Test failed: GetRawInputBuffer returned unexpected size: 0 input.c:2556: Test failed: Unexpected rawinput dwType: 0 input.c:2559: Test failed: Unexpected rawinput keyboard scan code: 0 input.c:2746: Test failed: 9: foreground process expected WM_INPUT message input.c:2747: Test failed: 9: foreground process expected RIM_INPUT message input.c:2746: Test failed: 10: foreground process expected WM_INPUT message input.c:2747: Test failed: 10: foreground process expected RIM_INPUT message input.c:2746: Test failed: 11: foreground process expected WM_INPUT message input.c:2747: Test failed: 11: foreground process expected RIM_INPUT message input.c:2746: Test failed: 12: foreground process expected WM_INPUT message input.c:2747: Test failed: 12: foreground process expected RIM_INPUT message