Signed-off-by: Derek Lesho [email protected] --- 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 2085fd3f9f..120de073c8 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -250,7 +250,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 24239916af..0ab5adfead 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; @@ -1668,6 +1671,9 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons msg_data->rawinput.mouse.data = input->mouse.data;
queue_hardware_message( desktop, msg, 0 ); + + if (device->flags & RIDEV_NOLEGACY) + return FALSE; }
for (i = 0; i < ARRAY_SIZE( messages ); i++) @@ -1793,6 +1799,9 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c msg_data->rawinput.kbd.scan = input->kbd.scan;
queue_hardware_message( desktop, msg, 0 ); + + if (device->flags & RIDEV_NOLEGACY) + return FALSE; }
if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0;
Signed-off-by: Derek Lesho [email protected] --- 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 43ce77c2dd..b6dd7d5932 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 5adc83db8b..8b8a8a1512 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 0ab5adfead..d12db927b9 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 );
Signed-off-by: Derek Lesho [email protected] --- server/protocol.def | 28 ++++++++++++++++++++++++++++ server/queue.c | 41 +++++++++++++++++++++++++++++++++++++++++ server/trace.c | 21 +++++++++++++++++++++ tools/make_requests | 1 + 4 files changed, 91 insertions(+)
diff --git a/server/protocol.def b/server/protocol.def index 8b8a8a1512..3a6a202f49 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -358,6 +358,29 @@ typedef union } hw; } hw_input_t;
+typedef union +{ + int type; + struct + { + int type; /* RIM_TYPEMOUSE */ + int x; /* relative x movement */ + int y; /* relative y movement */ + unsigned short button_flags; /* mouse button */ + unsigned short button_data; /* event details */ + } mouse; + struct + { + int type; /* RIM_TYPEKEYBOARD */ + /* TODO: fill this in if/when necessary */ + } kbd; + struct + { + int type; /* RIM_TYPEHID */ + /* TODO: fill this in if/when necessary */ + } hid; +} hw_rawinput_t; + typedef union { unsigned char bytes[1]; /* raw data for sent messages */ @@ -2294,6 +2317,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 d12db927b9..35cfcecff5 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2421,6 +2421,47 @@ 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)) + { + if (!(msg = alloc_hardware_message( 0, source, 0 ))) return; + 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; + + queue_hardware_message( desktop, msg, 0 ); + } + 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 3562823659..bccab449cf 100644 --- a/server/trace.c +++ b/server/trace.c @@ -390,6 +390,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,x=%d,y=%d,button_flags=%04hx,button_data=%04hx}", + prefix, 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 367f245653..cf631923a7 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -53,6 +53,7 @@ my %formats = "ioctl_code_t" => [ 4, 4, "&dump_ioctl_code" ], "cpu_type_t" => [ 4, 4, "&dump_cpu_type" ], "hw_input_t" => [ 32, 8, "&dump_hw_input" ], + "hw_rawinput_t" => [ 16, 8, "&dump_hw_rawinput" ] );
my @requests = ();
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=54266
Your paranoid android.
=== debian9 (32 bit report) ===
user32: msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000
On Sat, 2019-06-29 at 22:26 -0400, Derek Lesho wrote:
Signed-off-by: Derek Lesho [email protected]
server/protocol.def | 28 ++++++++++++++++++++++++++++ server/queue.c | 41 +++++++++++++++++++++++++++++++++++++++++ server/trace.c | 21 +++++++++++++++++++++ tools/make_requests | 1 + 4 files changed, 91 insertions(+)
diff --git a/server/protocol.def b/server/protocol.def index 8b8a8a1512..3a6a202f49 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -358,6 +358,29 @@ typedef union } hw; } hw_input_t;
+typedef union +{
- int type;
- struct
- {
int type; /* RIM_TYPEMOUSE */
int x; /* relative x movement */
int y; /* relative y movement */
unsigned short button_flags; /* mouse button */
unsigned short button_data; /* event details */
- } mouse;
- struct
- {
int type; /* RIM_TYPEKEYBOARD */
/* TODO: fill this in if/when necessary */
- } kbd;
- struct
- {
int type; /* RIM_TYPEHID */
/* TODO: fill this in if/when necessary */
- } hid;
+} hw_rawinput_t;
I'm still wondering if it should be merged with hw_input_t or not and use the same send_hardware_message request for raw inputs and normal inputs, but in any case this union should at least be used for the rawinput field in struct hardware_msg_data (with the kbd fields added) instead of duplicating it.
Yeah I'm not sure whether they should be merged either, I think it comes down to preference. Maybe Vincent or Alexandre should decide.
About using the union in hardware_msg_data, you're right, I didn't notice that and I'll deduplicate that.
On Tue, Jul 23, 2019 at 3:50 AM Rémi Bernon [email protected] wrote:
On Sat, 2019-06-29 at 22:26 -0400, Derek Lesho wrote:
Signed-off-by: Derek Lesho [email protected]
server/protocol.def | 28 ++++++++++++++++++++++++++++ server/queue.c | 41 +++++++++++++++++++++++++++++++++++++++++ server/trace.c | 21 +++++++++++++++++++++ tools/make_requests | 1 + 4 files changed, 91 insertions(+)
diff --git a/server/protocol.def b/server/protocol.def index 8b8a8a1512..3a6a202f49 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -358,6 +358,29 @@ typedef union } hw; } hw_input_t;
+typedef union +{
- int type;
- struct
- {
int type; /* RIM_TYPEMOUSE */
int x; /* relative x movement */
int y; /* relative y movement */
unsigned short button_flags; /* mouse button */
unsigned short button_data; /* event details */
- } mouse;
- struct
- {
int type; /* RIM_TYPEKEYBOARD */
/* TODO: fill this in if/when necessary */
- } kbd;
- struct
- {
int type; /* RIM_TYPEHID */
/* TODO: fill this in if/when necessary */
- } hid;
+} hw_rawinput_t;
I'm still wondering if it should be merged with hw_input_t or not and use the same send_hardware_message request for raw inputs and normal inputs, but in any case this union should at least be used for the rawinput field in struct hardware_msg_data (with the kbd fields added) instead of duplicating it. -- Rémi Bernon [email protected]
Signed-off-by: Derek Lesho [email protected] --- server/protocol.def | 52 ++++++++++++++++++++++++++++----------------- server/queue.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ server/trace.c | 21 ++++++++++++++++++ tools/make_requests | 1 + 4 files changed, 107 insertions(+), 19 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 8b8a8a1512..b5368c71f6 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -286,31 +286,40 @@ 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 */ + 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; +#define RIM_ENABLE_NATIVE_MOUSE_MOVE 0x0800 +#define RIM_ENABLE_NATIVE_MOUSE_PRESS 0x1000 + 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 @@ -2294,6 +2303,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 d12db927b9..03e64341c1 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2421,6 +2421,58 @@ 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 (device->target ? (thread != current) : (current->queue->input != desktop->foreground_input)) + { + if ( thread ) + release_object( thread ); + release_object( desktop ); + return; + } + if (thread) + release_object( thread ); + + if (!(msg = alloc_hardware_message( 0, source, 0 ))) return; + 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; + + queue_hardware_message( desktop, msg, 0 ); + } + 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 3562823659..bccab449cf 100644 --- a/server/trace.c +++ b/server/trace.c @@ -390,6 +390,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,x=%d,y=%d,button_flags=%04hx,button_data=%04hx}", + prefix, 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 367f245653..cf631923a7 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -53,6 +53,7 @@ my %formats = "ioctl_code_t" => [ 4, 4, "&dump_ioctl_code" ], "cpu_type_t" => [ 4, 4, "&dump_cpu_type" ], "hw_input_t" => [ 32, 8, "&dump_hw_input" ], + "hw_rawinput_t" => [ 16, 8, "&dump_hw_rawinput" ] );
my @requests = ();
v8 of this patch incorporates Remi's recommendations to use the hw_rawinput_t union for hardware_msg_data and send the rawinput messages to the relevant thread only.
On Fri, Jul 26, 2019 at 3:30 PM Derek Lesho [email protected] wrote:
Signed-off-by: Derek Lesho [email protected]
server/protocol.def | 52 ++++++++++++++++++++++++++++----------------- server/queue.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ server/trace.c | 21 ++++++++++++++++++ tools/make_requests | 1 + 4 files changed, 107 insertions(+), 19 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 8b8a8a1512..b5368c71f6 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -286,31 +286,40 @@ 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 */
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; +#define RIM_ENABLE_NATIVE_MOUSE_MOVE 0x0800 +#define RIM_ENABLE_NATIVE_MOUSE_PRESS 0x1000
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 @@ -2294,6 +2303,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 d12db927b9..03e64341c1 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2421,6 +2421,58 @@ 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 (device->target ? (thread != current) :
(current->queue->input != desktop->foreground_input))
{
if ( thread )
release_object( thread );
release_object( desktop );
return;
}
if (thread)
release_object( thread );
if (!(msg = alloc_hardware_message( 0, source, 0 ))) return;
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;
queue_hardware_message( desktop, msg, 0 );
}
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 3562823659..bccab449cf 100644 --- a/server/trace.c +++ b/server/trace.c @@ -390,6 +390,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,x=%d,y=%d,button_flags=%04hx,button_data=%04hx}",
prefix, 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 367f245653..cf631923a7 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -53,6 +53,7 @@ my %formats = "ioctl_code_t" => [ 4, 4, "&dump_ioctl_code" ], "cpu_type_t" => [ 4, 4, "&dump_cpu_type" ], "hw_input_t" => [ 32, 8, "&dump_hw_input" ],
- "hw_rawinput_t" => [ 16, 8, "&dump_hw_rawinput" ]
);
my @requests = ();
2.22.0
On 7/26/19 9:30 PM, Derek Lesho wrote:
+#define RIM_ENABLE_NATIVE_MOUSE_MOVE 0x0800 +#define RIM_ENABLE_NATIVE_MOUSE_PRESS 0x1000
I think you don't need these anymore (and they are deleted in a later patch).
struct thread *thread = device->target ? get_window_thread( device->target ) : NULL;
if (device->target ? (thread != current) : (current->queue->input != desktop->foreground_input))
{
if ( thread )
release_object( thread );
release_object( desktop );
return;
}
if (thread)
release_object( thread );
I think it is a bit convoluted, adding at the end of the function:
done: if (thread) release_object( thread );
and then "goto done;" in the case where the message should be ignored, would be clearer.
Also if target window is specified, the raw input messages should still only be delivered if window is also the foreground window.
Note that there's a RIDEV_INPUTSINK flag that can be set, but in this case the messages will be delivered to background windows with RIM_INPUTSINK wparam instead of RIM_INPUT.
I believe we can ignore windows in background for now, or we should implement the correct behavior with INPUTSINK.
Signed-off-by: Derek Lesho [email protected] --- dlls/user32/input.c | 29 +++++++++++++++++++++++++++++ dlls/user32/user32.spec | 1 + include/winuser.h | 1 + 3 files changed, 31 insertions(+)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 8b2ae805aa..f7ef1c3be2 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -33,6 +33,7 @@ #include <assert.h>
#define NONAMELESSUNION +#define NONAMELESSSTRUCT
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -129,6 +130,34 @@ 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.usFlags || raw_input->data.mouse.ulRawButtons + || raw_input->data.mouse.ulExtraInformation) + WARN("Unhandled parameters"); + + 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 d5b8597d8e..7103b86055 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -832,4 +832,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 3cffaa19ac..5d8774b6e6 100644 --- a/include/winuser.h +++ b/include/winuser.h @@ -4354,6 +4354,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
Signed-off-by: Derek Lesho [email protected] --- server/protocol.def | 2 + server/queue.c | 99 ++++++++++++++++++++++++++------------------- 2 files changed, 59 insertions(+), 42 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 3a6a202f49..9703b49154 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -358,6 +358,8 @@ typedef union } hw; } hw_input_t;
+#define RIM_ENABLE_NATIVE_MOUSE_MOVE 0x0800 +#define RIM_ENABLE_NATIVE_MOUSE_PRESS 0x1000 typedef union { int type; diff --git a/server/queue.c b/server/queue.c index 35cfcecff5..41c26d8fa0 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1599,6 +1599,9 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa return 1; }
+int emulate_raw_mouse_move = 1; +int emulate_raw_mouse_press = 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 ) @@ -1666,53 +1669,59 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
if ((device = current->process->rawinput_mouse)) { - if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0; - msg_data = msg->data; + if ( (emulate_raw_mouse_press && flags & ~MOUSEEVENTF_MOVE) || (emulate_raw_mouse_move && flags & MOUSEEVENTF_MOVE) ) + { + 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; + 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 = x - desktop->cursor.x; - msg_data->rawinput.mouse.y = y - desktop->cursor.y; - msg_data->rawinput.mouse.button_flags = 0; - msg_data->rawinput.mouse.button_data = 0; + msg_data->flags = 0; + msg_data->rawinput.type = RIM_TYPEMOUSE; + msg_data->rawinput.mouse.x = emulate_raw_mouse_move ? x - desktop->cursor.x : 0; + msg_data->rawinput.mouse.y = emulate_raw_mouse_move ? y - desktop->cursor.y : 0; + 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 (emulate_raw_mouse_press) + { + 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; - } + 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 ); + queue_hardware_message( desktop, msg, 0 ); + }
if (device->flags & RIDEV_NOLEGACY) return FALSE; @@ -2455,6 +2464,12 @@ DECL_HANDLER(send_rawinput_message) queue_hardware_message( desktop, msg, 0 ); } break; + case RIM_ENABLE_NATIVE_MOUSE_MOVE: + emulate_raw_mouse_move = 0; + break; + case RIM_ENABLE_NATIVE_MOUSE_PRESS: + emulate_raw_mouse_press = 0; + break; default: set_error( STATUS_INVALID_PARAMETER ); }
On Sat, 2019-06-29 at 22:26 -0400, Derek Lesho wrote:
Signed-off-by: Derek Lesho [email protected]
server/protocol.def | 2 + server/queue.c | 99 ++++++++++++++++++++++++++------------------- 2 files changed, 59 insertions(+), 42 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 3a6a202f49..9703b49154 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -358,6 +358,8 @@ typedef union } hw; } hw_input_t;
+#define RIM_ENABLE_NATIVE_MOUSE_MOVE 0x0800 +#define RIM_ENABLE_NATIVE_MOUSE_PRESS 0x1000 typedef union { int type; diff --git a/server/queue.c b/server/queue.c index 35cfcecff5..41c26d8fa0 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1599,6 +1599,9 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa return 1; }
+int emulate_raw_mouse_move = 1; +int emulate_raw_mouse_press = 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 ) @@ -1666,53 +1669,59 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
if ((device = current->process->rawinput_mouse)) {
if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0;
msg_data = msg->data;
if ( (emulate_raw_mouse_press && flags & ~MOUSEEVENTF_MOVE) || (emulate_raw_mouse_move && flags & MOUSEEVENTF_MOVE) )
{
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;
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 = x - desktop->cursor.x;
msg_data->rawinput.mouse.y = y - desktop->cursor.y;
msg_data->rawinput.mouse.button_flags = 0;
msg_data->rawinput.mouse.button_data = 0;
msg_data->flags = 0;
msg_data->rawinput.type = RIM_TYPEMOUSE;
msg_data->rawinput.mouse.x = emulate_raw_mouse_move ? x - desktop->cursor.x : 0;
msg_data->rawinput.mouse.y = emulate_raw_mouse_move ? y - desktop->cursor.y : 0;
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 (emulate_raw_mouse_press)
{
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;
}
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 );
queue_hardware_message( desktop, msg, 0 );
} if (device->flags & RIDEV_NOLEGACY) return FALSE;
@@ -2455,6 +2464,12 @@ DECL_HANDLER(send_rawinput_message) queue_hardware_message( desktop, msg, 0 ); } break;
- case RIM_ENABLE_NATIVE_MOUSE_MOVE:
emulate_raw_mouse_move = 0;
break;
- case RIM_ENABLE_NATIVE_MOUSE_PRESS:
emulate_raw_mouse_press = 0;
default: set_error( STATUS_INVALID_PARAMETER ); }break;
Don't you think we could simplify that by using only one emulate_raw_input flag? Are there any platforms where only some of the raw input events are received?
Also the flag could probably be cleared on the first direct raw input request received instead of requiring private flag values, and an empty raw input event could be sent right after the initialization if we still want to be informed early on.
Well, while it is certainly possible to use actual rawinput for sending keyboard events and mouse presses, I don't see much of an incentive to. With mouse motion, the DE is bypassed so mouse acceleration and sensitivity are bypassed (just like on windows), but I don't think DE's modify keyboard events or mouse presses in any meaningful way.
Plus, the fewer code paths we have doing the same thing the better I think.
On Tue, Jul 23, 2019 at 4:08 AM Rémi Bernon [email protected] wrote:
On Sat, 2019-06-29 at 22:26 -0400, Derek Lesho wrote:
Signed-off-by: Derek Lesho [email protected]
server/protocol.def | 2 + server/queue.c | 99 ++++++++++++++++++++++++++------------------- 2 files changed, 59 insertions(+), 42 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 3a6a202f49..9703b49154 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -358,6 +358,8 @@ typedef union } hw; } hw_input_t;
+#define RIM_ENABLE_NATIVE_MOUSE_MOVE 0x0800 +#define RIM_ENABLE_NATIVE_MOUSE_PRESS 0x1000 typedef union { int type; diff --git a/server/queue.c b/server/queue.c index 35cfcecff5..41c26d8fa0 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1599,6 +1599,9 @@ static int send_hook_ll_message( struct desktop
*desktop, struct message *hardwa
return 1;
}
+int emulate_raw_mouse_move = 1; +int emulate_raw_mouse_press = 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 )
@@ -1666,53 +1669,59 @@ static int queue_mouse_message( struct desktop
*desktop, user_handle_t win, cons
if ((device = current->process->rawinput_mouse)) {
if (!(msg = alloc_hardware_message( input->mouse.info, source,
time ))) return 0;
msg_data = msg->data;
if ( (emulate_raw_mouse_press && flags & ~MOUSEEVENTF_MOVE) ||
(emulate_raw_mouse_move && flags & MOUSEEVENTF_MOVE) )
{
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;
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 = x - desktop->cursor.x;
msg_data->rawinput.mouse.y = y - desktop->cursor.y;
msg_data->rawinput.mouse.button_flags = 0;
msg_data->rawinput.mouse.button_data = 0;
msg_data->flags = 0;
msg_data->rawinput.type = RIM_TYPEMOUSE;
msg_data->rawinput.mouse.x = emulate_raw_mouse_move ? x
- desktop->cursor.x : 0;
msg_data->rawinput.mouse.y = emulate_raw_mouse_move ? y
- desktop->cursor.y : 0;
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 (emulate_raw_mouse_press)
{
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;
}
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 );
queue_hardware_message( desktop, msg, 0 );
} if (device->flags & RIDEV_NOLEGACY) return FALSE;
@@ -2455,6 +2464,12 @@ DECL_HANDLER(send_rawinput_message) queue_hardware_message( desktop, msg, 0 ); } break;
- case RIM_ENABLE_NATIVE_MOUSE_MOVE:
emulate_raw_mouse_move = 0;
break;
- case RIM_ENABLE_NATIVE_MOUSE_PRESS:
emulate_raw_mouse_press = 0;
default: set_error( STATUS_INVALID_PARAMETER ); }break;
Don't you think we could simplify that by using only one emulate_raw_input flag? Are there any platforms where only some of the raw input events are received?
Also the flag could probably be cleared on the first direct raw input request received instead of requiring private flag values, and an empty raw input event could be sent right after the initialization if we still want to be informed early on. -- Rémi Bernon [email protected]
On Tue, 2019-07-23 at 12:16 -0400, Derek Lesho wrote:
Well, while it is certainly possible to use actual rawinput for sending keyboard events and mouse presses, I don't see much of an incentive to. With mouse motion, the DE is bypassed so mouse acceleration and sensitivity are bypassed (just like on windows), but I don't think DE's modify keyboard events or mouse presses in any meaningful way.
Then you don't need the emulate_raw_mouse_press flag. Keyboard raw input is another topic of course.
If you drop the emulate_raw_mouse_press flag, which isn't going to be enabled anyway as you said, I believe your patch, and the code, will be simpler. I think you can drop the big if and only change:
- msg_data->rawinput.mouse.x = x - desktop->cursor.x; - msg_data->rawinput.mouse.y = y - desktop->cursor.y; + msg_data->rawinput.mouse.x = emulate_raw_mouse_move ? x - desktop->cursor.x : 0; + msg_data->rawinput.mouse.y = emulate_raw_mouse_move ? y - desktop->cursor.y : 0;
You could then conditionally call queue_hardware_message below if the button data is empty in order to avoid sending empty events.
With emulate_raw_mouse_press, I wanted to keep our options open as Xi_RawButtonPress/Release do exist, and maybe in the future a usecase will come up where we want to use them. If we can confirm that there is no point to keeping them for either the mac or x11 driver, I'll remove it.
On Wed, Jul 24, 2019 at 6:28 AM Rémi Bernon [email protected] wrote:
On Tue, 2019-07-23 at 12:16 -0400, Derek Lesho wrote:
Well, while it is certainly possible to use actual rawinput for sending keyboard events and mouse presses, I don't see much of an incentive to. With mouse motion, the DE is bypassed so mouse acceleration and
sensitivity
are bypassed (just like on windows), but I don't think DE's modify
keyboard
events or mouse presses in any meaningful way.
Then you don't need the emulate_raw_mouse_press flag. Keyboard raw input is another topic of course.
If you drop the emulate_raw_mouse_press flag, which isn't going to be enabled anyway as you said, I believe your patch, and the code, will be simpler. I think you can drop the big if and only change:
msg_data->rawinput.mouse.x = x - desktop->cursor.x;
msg_data->rawinput.mouse.y = y - desktop->cursor.y;
msg_data->rawinput.mouse.x = emulate_raw_mouse_move ? x -
desktop->cursor.x : 0;
msg_data->rawinput.mouse.y = emulate_raw_mouse_move ? y -
desktop->cursor.y : 0;
You could then conditionally call queue_hardware_message below if the button data is empty in order to avoid sending empty events. -- Rémi Bernon [email protected]
Signed-off-by: Derek Lesho [email protected] --- v9: Make raw-mouse emulation all of nothing --- server/protocol.def | 5 +++-- server/queue.c | 14 ++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index b5368c71f6..4ce9091661 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -310,8 +310,7 @@ typedef union /* TODO: fill this in if/when necessary */ } hid; } hw_rawinput_t; -#define RIM_ENABLE_NATIVE_MOUSE_MOVE 0x0800 -#define RIM_ENABLE_NATIVE_MOUSE_PRESS 0x1000 +#define RIM_ENABLE_NATIVE_MOUSE 0x0800
struct hardware_msg_data { @@ -367,6 +366,8 @@ typedef union } hw; } hw_input_t;
+#define RIM_ENABLE_NATIVE_MOUSE_MOVE 0x0800 +#define RIM_ENABLE_NATIVE_MOUSE_PRESS 0x1000 typedef union { unsigned char bytes[1]; /* raw data for sent messages */ diff --git a/server/queue.c b/server/queue.c index 03e64341c1..fd830d2da1 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; }
+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; @@ -1713,11 +1716,11 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons }
queue_hardware_message( desktop, msg, 0 ); - - if (device->flags & RIDEV_NOLEGACY) - return FALSE; }
+ if (device && device->flags & RIDEV_NOLEGACY) + return FALSE; + for (i = 0; i < ARRAY_SIZE( messages ); i++) { if (!messages[i]) continue; @@ -2466,6 +2469,9 @@ DECL_HANDLER(send_rawinput_message) queue_hardware_message( desktop, msg, 0 ); } break; + case RIM_ENABLE_NATIVE_MOUSE_MOVE: + emulate_raw_mouse = 0; + break; default: set_error( STATUS_INVALID_PARAMETER ); }
On 7/27/19 1:18 AM, Derek Lesho wrote:
Signed-off-by: Derek Lesho [email protected]
v9: Make raw-mouse emulation all of nothing
server/protocol.def | 5 +++-- server/queue.c | 14 ++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index b5368c71f6..4ce9091661 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -310,8 +310,7 @@ typedef union /* TODO: fill this in if/when necessary */ } hid; } hw_rawinput_t; -#define RIM_ENABLE_NATIVE_MOUSE_MOVE 0x0800 -#define RIM_ENABLE_NATIVE_MOUSE_PRESS 0x1000 +#define RIM_ENABLE_NATIVE_MOUSE 0x0800
struct hardware_msg_data { @@ -367,6 +366,8 @@ typedef union } hw; } hw_input_t;
+#define RIM_ENABLE_NATIVE_MOUSE_MOVE 0x0800 +#define RIM_ENABLE_NATIVE_MOUSE_PRESS 0x1000 typedef union { unsigned char bytes[1]; /* raw data for sent messages */ diff --git a/server/queue.c b/server/queue.c index 03e64341c1..fd830d2da1 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; }
+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;
@@ -1713,11 +1716,11 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons }
queue_hardware_message( desktop, msg, 0 );
if (device->flags & RIDEV_NOLEGACY)
return FALSE; }
- if (device && device->flags & RIDEV_NOLEGACY)
return FALSE;
for (i = 0; i < ARRAY_SIZE( messages ); i++) { if (!messages[i]) continue;
@@ -2466,6 +2469,9 @@ DECL_HANDLER(send_rawinput_message) queue_hardware_message( desktop, msg, 0 ); } break;
- case RIM_ENABLE_NATIVE_MOUSE_MOVE:
emulate_raw_mouse = 0;
break; default: set_error( STATUS_INVALID_PARAMETER ); }
IMHO reacting to the first send_rawinput_message request to decide to stop emulating raw input is enough, no need for custom message type that may collide at some point with Windows values.
Signed-off-by: Derek Lesho [email protected] --- dlls/winex11.drv/mouse.c | 97 ++++++++++++++++++++++++++-------- dlls/winex11.drv/x11drv.h | 6 ++- dlls/winex11.drv/x11drv_main.c | 10 ++++ 3 files changed, 90 insertions(+), 23 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..b5afbb04df 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -284,11 +284,26 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } #endif
+/*********************************************************************** + * inform_wineserver + */ +static void inform_wineserver(void) +{ + static int once = 0; + if (!once) + { + RAWINPUT raw_input; + raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE; + __wine_send_raw_input(&raw_input); + once = 1; + } +} +
/*********************************************************************** - * 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(); @@ -318,7 +333,6 @@ static void enable_xinput2(void) 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 );
@@ -337,19 +351,21 @@ static void enable_xinput2(void) data->xi2_current_slave = 0;
data->xi2_state = xi_enabled; + + inform_wineserver(); #endif }
/*********************************************************************** - * 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; @@ -368,6 +384,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 @@ -393,9 +424,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 ); @@ -423,7 +454,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) { - disable_xinput2(); + disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE; } @@ -489,7 +520,7 @@ LRESULT clip_cursor_notify( HWND 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 */ @@ -1724,16 +1755,18 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel;
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 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 @@ -1758,25 +1791,21 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) x_rel = &thread_data->x_rel_valuator; y_rel = &thread_data->y_rel_valuator;
- input.u.mi.mouseData = 0; - input.u.mi.dwFlags = MOUSEEVENTF_MOVE; - input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); - input.u.mi.dwExtraInfo = 0; - input.u.mi.dx = 0; - input.u.mi.dy = 0; - virtual_rect = get_virtual_screen_rect();
for (i = 0; i <= max ( 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_dx = raw_val; } if (i == y_rel->number) { @@ -1784,6 +1813,8 @@ 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_dy = raw_val; } }
@@ -1793,10 +1824,32 @@ 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 ); + raw_input.data.mouse.lLastX = raw_dx; + raw_input.data.mouse.lLastY = raw_dy; + raw_input.data.mouse.u.usButtonFlags = 0; + raw_input.data.mouse.u.usButtonData = 0; + raw_input.data.mouse.ulExtraInformation = 0; + + TRACE("raw event %f,%f\n", raw_dx, raw_dy); + + raw_input.header.dwType = RIM_TYPEMOUSE; + + if ( LIST_ENTRY((&g_x11_threads)->next, struct x11drv_thread_data, entry) == thread_data ) + __wine_send_raw_input( &raw_input ); + + if (thread_data->xi2_state == xi_extra) + { + input.u.mi.mouseData = 0; + input.u.mi.dwFlags = MOUSEEVENTF_MOVE; + input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); + input.u.mi.dwExtraInfo = 0; + + 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 ); + }
- 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 a0308b0675..378c1d7508 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -194,6 +194,8 @@ extern BOOL 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,14 +337,16 @@ 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; int xi2_core_pointer; /* XInput2 core pointer id */ int xi2_current_slave; /* Current slave driving the Core pointer */ + struct list entry; /* Entry in global list of setup X11 threads */ }; +extern struct list g_x11_threads DECLSPEC_HIDDEN; /* Global list of setup X11 threads */
extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; extern DWORD thread_data_tls_index DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e67a3c05a9..685b3dd0f4 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -601,6 +601,9 @@ static BOOL process_attach(void) }
+struct list g_x11_threads = LIST_INIT( g_x11_threads ); + + /*********************************************************************** * ThreadDetach (X11DRV.@) */ @@ -610,6 +613,9 @@ void CDECL X11DRV_ThreadDetach(void)
if (data) { + list_remove( &data->entry ); + X11DRV_XInput2_Disable(); + if (data->xim) XCloseIM( data->xim ); if (data->font_set) XFreeFontSet( data->display, data->font_set ); XCloseDisplay( data->display ); @@ -680,6 +686,10 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (use_xim) X11DRV_SetupXIM();
+ X11DRV_XInput2_Enable(); + + list_add_tail( &g_x11_threads, &data->entry ); + return data; }
This patch had to be updated as multiple threads in a process were sending identical rawinput messages and increasing sensitivity.
On Sat, Jun 29, 2019 at 10:26 PM Derek Lesho [email protected] wrote:
Signed-off-by: Derek Lesho [email protected]
dlls/winex11.drv/mouse.c | 97 ++++++++++++++++++++++++++-------- dlls/winex11.drv/x11drv.h | 6 ++- dlls/winex11.drv/x11drv_main.c | 10 ++++ 3 files changed, 90 insertions(+), 23 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..b5afbb04df 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -284,11 +284,26 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } #endif
+/***********************************************************************
inform_wineserver
- */
+static void inform_wineserver(void) +{
- static int once = 0;
- if (!once)
- {
RAWINPUT raw_input;
raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE;
__wine_send_raw_input(&raw_input);
once = 1;
- }
+}
/***********************************************************************
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(); @@ -318,7 +333,6 @@ static void enable_xinput2(void) 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 );
@@ -337,19 +351,21 @@ static void enable_xinput2(void) data->xi2_current_slave = 0;
data->xi2_state = xi_enabled;
- inform_wineserver();
#endif }
/***********************************************************************
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;
@@ -368,6 +384,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
@@ -393,9 +424,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 ); @@ -423,7 +454,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) {
disable_xinput2();
}disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE;
@@ -489,7 +520,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) TRACE( "clip hwnd reset from %p\n", hwnd ); data->clip_hwnd = 0; data->clip_reset = GetTickCount();
disable_xinput2();
} else if (hwnd == GetForegroundWindow()) /* request to clip */disable_xinput2_path(); DestroyWindow( hwnd );
@@ -1724,16 +1755,18 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel;
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 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 @@ -1758,25 +1791,21 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) x_rel = &thread_data->x_rel_valuator; y_rel = &thread_data->y_rel_valuator;
input.u.mi.mouseData = 0;
input.u.mi.dwFlags = MOUSEEVENTF_MOVE;
input.u.mi.time = EVENT_x11_time_to_win32_time( event->time );
input.u.mi.dwExtraInfo = 0;
input.u.mi.dx = 0;
input.u.mi.dy = 0;
virtual_rect = get_virtual_screen_rect();
for (i = 0; i <= max ( 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_dx = raw_val; } if (i == y_rel->number) {
@@ -1784,6 +1813,8 @@ 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_dy = raw_val; }
@@ -1793,10 +1824,32 @@ 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 );
- raw_input.data.mouse.lLastX = raw_dx;
- raw_input.data.mouse.lLastY = raw_dy;
- raw_input.data.mouse.u.usButtonFlags = 0;
- raw_input.data.mouse.u.usButtonData = 0;
- raw_input.data.mouse.ulExtraInformation = 0;
- TRACE("raw event %f,%f\n", raw_dx, raw_dy);
- raw_input.header.dwType = RIM_TYPEMOUSE;
- if ( LIST_ENTRY((&g_x11_threads)->next, struct x11drv_thread_data,
entry) == thread_data )
__wine_send_raw_input( &raw_input );
- if (thread_data->xi2_state == xi_extra)
- {
input.u.mi.mouseData = 0;
input.u.mi.dwFlags = MOUSEEVENTF_MOVE;
input.u.mi.time = EVENT_x11_time_to_win32_time(
event->time );
input.u.mi.dwExtraInfo = 0;
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 );
- }
- 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 a0308b0675..378c1d7508 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -194,6 +194,8 @@ extern BOOL 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,14 +337,16 @@ 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; int xi2_core_pointer; /* XInput2 core pointer id */ int xi2_current_slave; /* Current slave driving the Core pointer */
- struct list entry; /* Entry in global list of setup X11
threads */ }; +extern struct list g_x11_threads DECLSPEC_HIDDEN; /* Global list of setup X11 threads */
extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; extern DWORD thread_data_tls_index DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e67a3c05a9..685b3dd0f4 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -601,6 +601,9 @@ static BOOL process_attach(void) }
+struct list g_x11_threads = LIST_INIT( g_x11_threads );
/***********************************************************************
ThreadDetach (X11DRV.@)
*/ @@ -610,6 +613,9 @@ void CDECL X11DRV_ThreadDetach(void)
if (data) {
list_remove( &data->entry );
X11DRV_XInput2_Disable();
if (data->xim) XCloseIM( data->xim ); if (data->font_set) XFreeFontSet( data->display, data->font_set ); XCloseDisplay( data->display );
@@ -680,6 +686,10 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (use_xim) X11DRV_SetupXIM();
- X11DRV_XInput2_Enable();
- list_add_tail( &g_x11_threads, &data->entry );
- return data;
}
-- 2.21.0
Signed-off-by: Derek Lesho [email protected] --- dlls/winex11.drv/mouse.c | 101 ++++++++++++++++++++++++++------- dlls/winex11.drv/x11drv.h | 6 +- dlls/winex11.drv/x11drv_main.c | 10 ++++ 3 files changed, 94 insertions(+), 23 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..8110bafb44 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -284,11 +284,26 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } #endif
+/*********************************************************************** + * inform_wineserver + */ +static void inform_wineserver(void) +{ + static int once = 0; + if (!once) + { + RAWINPUT raw_input; + raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE; + __wine_send_raw_input(&raw_input); + once = 1; + } +} +
/*********************************************************************** - * 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(); @@ -318,7 +333,6 @@ static void enable_xinput2(void) 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 );
@@ -337,19 +351,21 @@ static void enable_xinput2(void) data->xi2_current_slave = 0;
data->xi2_state = xi_enabled; + + inform_wineserver(); #endif }
/*********************************************************************** - * 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; @@ -368,6 +384,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 @@ -393,9 +424,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 ); @@ -423,7 +454,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) { - disable_xinput2(); + disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE; } @@ -489,7 +520,7 @@ LRESULT clip_cursor_notify( HWND 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 */ @@ -1724,16 +1755,18 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel;
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 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 @@ -1758,25 +1791,25 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) x_rel = &thread_data->x_rel_valuator; y_rel = &thread_data->y_rel_valuator;
- input.u.mi.mouseData = 0; - input.u.mi.dwFlags = MOUSEEVENTF_MOVE; - input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); - input.u.mi.dwExtraInfo = 0; - input.u.mi.dx = 0; - input.u.mi.dy = 0; - virtual_rect = get_virtual_screen_rect();
+ /* sometimes we don't get X and Y valuators */ + input.u.mi.dx = 0; + input.u.mi.dy = 0; + for (i = 0; i <= max ( 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_dx = raw_val; } if (i == y_rel->number) { @@ -1784,6 +1817,8 @@ 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_dy = raw_val; } }
@@ -1793,10 +1828,32 @@ 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 ); + raw_input.data.mouse.lLastX = raw_dx; + raw_input.data.mouse.lLastY = raw_dy; + raw_input.data.mouse.u.usButtonFlags = 0; + raw_input.data.mouse.u.usButtonData = 0; + raw_input.data.mouse.ulExtraInformation = 0; + + TRACE("raw event %f,%f\n", raw_dx, raw_dy); + + raw_input.header.dwType = RIM_TYPEMOUSE; + + if ( LIST_ENTRY((&g_x11_threads)->next, struct x11drv_thread_data, entry) == thread_data ) + __wine_send_raw_input( &raw_input ); + + if (thread_data->xi2_state == xi_extra) + { + input.u.mi.mouseData = 0; + input.u.mi.dwFlags = MOUSEEVENTF_MOVE; + input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); + input.u.mi.dwExtraInfo = 0; + + 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 ); + }
- 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 a0308b0675..378c1d7508 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -194,6 +194,8 @@ extern BOOL 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,14 +337,16 @@ 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; int xi2_core_pointer; /* XInput2 core pointer id */ int xi2_current_slave; /* Current slave driving the Core pointer */ + struct list entry; /* Entry in global list of setup X11 threads */ }; +extern struct list g_x11_threads DECLSPEC_HIDDEN; /* Global list of setup X11 threads */
extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; extern DWORD thread_data_tls_index DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e67a3c05a9..685b3dd0f4 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -601,6 +601,9 @@ static BOOL process_attach(void) }
+struct list g_x11_threads = LIST_INIT( g_x11_threads ); + + /*********************************************************************** * ThreadDetach (X11DRV.@) */ @@ -610,6 +613,9 @@ void CDECL X11DRV_ThreadDetach(void)
if (data) { + list_remove( &data->entry ); + X11DRV_XInput2_Disable(); + if (data->xim) XCloseIM( data->xim ); if (data->font_set) XFreeFontSet( data->display, data->font_set ); XCloseDisplay( data->display ); @@ -680,6 +686,10 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (use_xim) X11DRV_SetupXIM();
+ X11DRV_XInput2_Enable(); + + list_add_tail( &g_x11_threads, &data->entry ); + return data; }
I needed to add the default values for input.u.mi.d* to replace the XI_ButtonPress workaround, as that workaround broke native rawinput.
On Tue, Jul 2, 2019 at 8:48 PM Derek Lesho [email protected] wrote:
Signed-off-by: Derek Lesho [email protected]
dlls/winex11.drv/mouse.c | 101 ++++++++++++++++++++++++++------- dlls/winex11.drv/x11drv.h | 6 +- dlls/winex11.drv/x11drv_main.c | 10 ++++ 3 files changed, 94 insertions(+), 23 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..8110bafb44 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -284,11 +284,26 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } #endif
+/***********************************************************************
inform_wineserver
- */
+static void inform_wineserver(void) +{
- static int once = 0;
- if (!once)
- {
RAWINPUT raw_input;
raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE;
__wine_send_raw_input(&raw_input);
once = 1;
- }
+}
/***********************************************************************
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(); @@ -318,7 +333,6 @@ static void enable_xinput2(void) 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 );
@@ -337,19 +351,21 @@ static void enable_xinput2(void) data->xi2_current_slave = 0;
data->xi2_state = xi_enabled;
- inform_wineserver();
#endif }
/***********************************************************************
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;
@@ -368,6 +384,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
@@ -393,9 +424,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 ); @@ -423,7 +454,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) {
disable_xinput2();
}disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE;
@@ -489,7 +520,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) TRACE( "clip hwnd reset from %p\n", hwnd ); data->clip_hwnd = 0; data->clip_reset = GetTickCount();
disable_xinput2();
} else if (hwnd == GetForegroundWindow()) /* request to clip */disable_xinput2_path(); DestroyWindow( hwnd );
@@ -1724,16 +1755,18 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel;
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 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 @@ -1758,25 +1791,25 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) x_rel = &thread_data->x_rel_valuator; y_rel = &thread_data->y_rel_valuator;
- input.u.mi.mouseData = 0;
- input.u.mi.dwFlags = MOUSEEVENTF_MOVE;
- input.u.mi.time = EVENT_x11_time_to_win32_time( event->time );
- input.u.mi.dwExtraInfo = 0;
- input.u.mi.dx = 0;
- input.u.mi.dy = 0;
- virtual_rect = get_virtual_screen_rect();
- /* sometimes we don't get X and Y valuators */
- input.u.mi.dx = 0;
- input.u.mi.dy = 0;
- for (i = 0; i <= max ( 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_dx = raw_val; } if (i == y_rel->number) {
@@ -1784,6 +1817,8 @@ 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_dy = raw_val; }
@@ -1793,10 +1828,32 @@ 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 );
- raw_input.data.mouse.lLastX = raw_dx;
- raw_input.data.mouse.lLastY = raw_dy;
- raw_input.data.mouse.u.usButtonFlags = 0;
- raw_input.data.mouse.u.usButtonData = 0;
- raw_input.data.mouse.ulExtraInformation = 0;
- TRACE("raw event %f,%f\n", raw_dx, raw_dy);
- raw_input.header.dwType = RIM_TYPEMOUSE;
- if ( LIST_ENTRY((&g_x11_threads)->next, struct x11drv_thread_data,
entry) == thread_data )
__wine_send_raw_input( &raw_input );
- if (thread_data->xi2_state == xi_extra)
- {
input.u.mi.mouseData = 0;
input.u.mi.dwFlags = MOUSEEVENTF_MOVE;
input.u.mi.time = EVENT_x11_time_to_win32_time(
event->time );
input.u.mi.dwExtraInfo = 0;
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 );
- }
- 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 a0308b0675..378c1d7508 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -194,6 +194,8 @@ extern BOOL 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,14 +337,16 @@ 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; int xi2_core_pointer; /* XInput2 core pointer id */ int xi2_current_slave; /* Current slave driving the Core pointer */
- struct list entry; /* Entry in global list of setup X11
threads */ }; +extern struct list g_x11_threads DECLSPEC_HIDDEN; /* Global list of setup X11 threads */
extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; extern DWORD thread_data_tls_index DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e67a3c05a9..685b3dd0f4 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -601,6 +601,9 @@ static BOOL process_attach(void) }
+struct list g_x11_threads = LIST_INIT( g_x11_threads );
/***********************************************************************
ThreadDetach (X11DRV.@)
*/ @@ -610,6 +613,9 @@ void CDECL X11DRV_ThreadDetach(void)
if (data) {
list_remove( &data->entry );
X11DRV_XInput2_Disable();
if (data->xim) XCloseIM( data->xim ); if (data->font_set) XFreeFontSet( data->display, data->font_set ); XCloseDisplay( data->display );
@@ -680,6 +686,10 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (use_xim) X11DRV_SetupXIM();
- X11DRV_XInput2_Enable();
- list_add_tail( &g_x11_threads, &data->entry );
- return data;
}
-- 2.21.0
Signed-off-by: Derek Lesho [email protected] --- dlls/winex11.drv/mouse.c | 88 +++++++++++++++++++++++++++------- dlls/winex11.drv/x11drv.h | 6 ++- dlls/winex11.drv/x11drv_main.c | 10 ++++ 3 files changed, 86 insertions(+), 18 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..1ceac3d7f2 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -284,11 +284,26 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } #endif
+/*********************************************************************** + * inform_wineserver + */ +static void inform_wineserver(void) +{ + static int once = 0; + if (!once) + { + RAWINPUT raw_input; + raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE; + __wine_send_raw_input(&raw_input); + once = 1; + } +} +
/*********************************************************************** - * 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(); @@ -318,7 +333,6 @@ static void enable_xinput2(void) 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 );
@@ -337,19 +351,21 @@ static void enable_xinput2(void) data->xi2_current_slave = 0;
data->xi2_state = xi_enabled; + + inform_wineserver(); #endif }
/*********************************************************************** - * 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; @@ -368,6 +384,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 @@ -393,9 +424,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 ); @@ -423,7 +454,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) { - disable_xinput2(); + disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE; } @@ -489,7 +520,7 @@ LRESULT clip_cursor_notify( HWND 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 */ @@ -1724,16 +1755,18 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel;
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 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 @@ -1758,12 +1791,20 @@ 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 ); input.u.mi.dwExtraInfo = 0; - input.u.mi.dx = 0; - input.u.mi.dy = 0; + 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.lLastX = 0; + raw_input.data.mouse.lLastY = 0;
virtual_rect = get_virtual_screen_rect();
@@ -1771,12 +1812,15 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) { 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.lLastX = raw_dx = raw_val; } if (i == y_rel->number) { @@ -1784,6 +1828,8 @@ 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.lLastY = raw_dy = raw_val; } }
@@ -1793,10 +1839,18 @@ 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 ); + } + + if ( LIST_ENTRY(list_head(&g_x11_threads), struct x11drv_thread_data, entry) == thread_data) + { + TRACE("raw event %f,%f\n", raw_dx, raw_dy); + __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 a0308b0675..378c1d7508 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -194,6 +194,8 @@ extern BOOL 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,14 +337,16 @@ 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; int xi2_core_pointer; /* XInput2 core pointer id */ int xi2_current_slave; /* Current slave driving the Core pointer */ + struct list entry; /* Entry in global list of setup X11 threads */ }; +extern struct list g_x11_threads DECLSPEC_HIDDEN; /* Global list of setup X11 threads */
extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; extern DWORD thread_data_tls_index DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e67a3c05a9..685b3dd0f4 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -601,6 +601,9 @@ static BOOL process_attach(void) }
+struct list g_x11_threads = LIST_INIT( g_x11_threads ); + + /*********************************************************************** * ThreadDetach (X11DRV.@) */ @@ -610,6 +613,9 @@ void CDECL X11DRV_ThreadDetach(void)
if (data) { + list_remove( &data->entry ); + X11DRV_XInput2_Disable(); + if (data->xim) XCloseIM( data->xim ); if (data->font_set) XFreeFontSet( data->display, data->font_set ); XCloseDisplay( data->display ); @@ -680,6 +686,10 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (use_xim) X11DRV_SetupXIM();
+ X11DRV_XInput2_Enable(); + + list_add_tail( &g_x11_threads, &data->entry ); + return data; }
This is v4 of my 6th patch, it fixes a a major bug (not using list_head) and re-formats the patch to look nicer.
On Tue, Jul 16, 2019 at 7:56 PM Derek Lesho [email protected] wrote:
Signed-off-by: Derek Lesho [email protected]
dlls/winex11.drv/mouse.c | 88 +++++++++++++++++++++++++++------- dlls/winex11.drv/x11drv.h | 6 ++- dlls/winex11.drv/x11drv_main.c | 10 ++++ 3 files changed, 86 insertions(+), 18 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..1ceac3d7f2 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -284,11 +284,26 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } #endif
+/***********************************************************************
inform_wineserver
- */
+static void inform_wineserver(void) +{
- static int once = 0;
- if (!once)
- {
RAWINPUT raw_input;
raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE;
__wine_send_raw_input(&raw_input);
once = 1;
- }
+}
/***********************************************************************
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(); @@ -318,7 +333,6 @@ static void enable_xinput2(void) 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 );
@@ -337,19 +351,21 @@ static void enable_xinput2(void) data->xi2_current_slave = 0;
data->xi2_state = xi_enabled;
- inform_wineserver();
#endif }
/***********************************************************************
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;
@@ -368,6 +384,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
@@ -393,9 +424,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 ); @@ -423,7 +454,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) {
disable_xinput2();
}disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE;
@@ -489,7 +520,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) TRACE( "clip hwnd reset from %p\n", hwnd ); data->clip_hwnd = 0; data->clip_reset = GetTickCount();
disable_xinput2();
} else if (hwnd == GetForegroundWindow()) /* request to clip */disable_xinput2_path(); DestroyWindow( hwnd );
@@ -1724,16 +1755,18 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel;
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 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 @@ -1758,12 +1791,20 @@ 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 ); input.u.mi.dwExtraInfo = 0;
- input.u.mi.dx = 0;
- input.u.mi.dy = 0;
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.lLastX = 0;
raw_input.data.mouse.lLastY = 0;
virtual_rect = get_virtual_screen_rect();
@@ -1771,12 +1812,15 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) { 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.lLastX = raw_dx = raw_val; } if (i == y_rel->number) {
@@ -1784,6 +1828,8 @@ 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.lLastY = raw_dy = raw_val; }
@@ -1793,10 +1839,18 @@ 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 );
- }
- if ( LIST_ENTRY(list_head(&g_x11_threads), struct x11drv_thread_data,
entry) == thread_data)
- {
TRACE("raw event %f,%f\n", raw_dx, raw_dy);
__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 a0308b0675..378c1d7508 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -194,6 +194,8 @@ extern BOOL 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,14 +337,16 @@ 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; int xi2_core_pointer; /* XInput2 core pointer id */ int xi2_current_slave; /* Current slave driving the Core pointer */
- struct list entry; /* Entry in global list of setup X11
threads */ }; +extern struct list g_x11_threads DECLSPEC_HIDDEN; /* Global list of setup X11 threads */
extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; extern DWORD thread_data_tls_index DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e67a3c05a9..685b3dd0f4 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -601,6 +601,9 @@ static BOOL process_attach(void) }
+struct list g_x11_threads = LIST_INIT( g_x11_threads );
/***********************************************************************
ThreadDetach (X11DRV.@)
*/ @@ -610,6 +613,9 @@ void CDECL X11DRV_ThreadDetach(void)
if (data) {
list_remove( &data->entry );
X11DRV_XInput2_Disable();
if (data->xim) XCloseIM( data->xim ); if (data->font_set) XFreeFontSet( data->display, data->font_set ); XCloseDisplay( data->display );
@@ -680,6 +686,10 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (use_xim) X11DRV_SetupXIM();
- X11DRV_XInput2_Enable();
- list_add_tail( &g_x11_threads, &data->entry );
- return data;
}
-- 2.22.0
Signed-off-by: Derek Lesho [email protected] --- dlls/winex11.drv/mouse.c | 89 +++++++++++++++++++++++++++------- dlls/winex11.drv/x11drv.h | 4 +- dlls/winex11.drv/x11drv_main.c | 4 ++ 3 files changed, 79 insertions(+), 18 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..a68844d328 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -284,11 +284,26 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } #endif
+/*********************************************************************** + * inform_wineserver + */ +static void inform_wineserver(void) +{ + static int once = 0; + if (!once) + { + RAWINPUT raw_input; + raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE; + __wine_send_raw_input(&raw_input); + once = 1; + } +} +
/*********************************************************************** - * 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(); @@ -318,7 +333,6 @@ static void enable_xinput2(void) 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 );
@@ -337,19 +351,21 @@ static void enable_xinput2(void) data->xi2_current_slave = 0;
data->xi2_state = xi_enabled; + + inform_wineserver(); #endif }
/*********************************************************************** - * 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; @@ -368,6 +384,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 @@ -393,9 +424,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 ); @@ -423,7 +454,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) { - disable_xinput2(); + disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE; } @@ -489,7 +520,7 @@ LRESULT clip_cursor_notify( HWND 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 */ @@ -1724,16 +1755,19 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel; + static unsigned int last_cookie = 0;
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 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 @@ -1758,12 +1792,20 @@ 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 ); input.u.mi.dwExtraInfo = 0; - input.u.mi.dx = 0; - input.u.mi.dy = 0; + 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.lLastX = 0; + raw_input.data.mouse.lLastY = 0;
virtual_rect = get_virtual_screen_rect();
@@ -1771,12 +1813,15 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) { 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.lLastX = raw_dx = raw_val; } if (i == y_rel->number) { @@ -1784,6 +1829,8 @@ 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.lLastY = raw_dy = raw_val; } }
@@ -1793,10 +1840,18 @@ 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 ); + } + + if (InterlockedExchange(&last_cookie, xev->cookie) != xev->cookie) + { + TRACE("raw event %f,%f\n", raw_dx, raw_dy); + __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 a0308b0675..a9138eef2a 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -194,6 +194,8 @@ extern BOOL 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,7 +337,7 @@ 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; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e67a3c05a9..351ab89781 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -610,6 +610,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 ); @@ -680,6 +682,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (use_xim) X11DRV_SetupXIM();
+ X11DRV_XInput2_Enable(); + return data; }
This version removes the whole g_x11_threads list as I realized not all of them receive events. The new method of ensuring only one thread per process sending the events is much cleaner and should work 100% of the time.
On Thu, Jul 18, 2019 at 4:52 PM Derek Lesho [email protected] wrote:
Signed-off-by: Derek Lesho [email protected]
dlls/winex11.drv/mouse.c | 89 +++++++++++++++++++++++++++------- dlls/winex11.drv/x11drv.h | 4 +- dlls/winex11.drv/x11drv_main.c | 4 ++ 3 files changed, 79 insertions(+), 18 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..a68844d328 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -284,11 +284,26 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } #endif
+/***********************************************************************
inform_wineserver
- */
+static void inform_wineserver(void) +{
- static int once = 0;
- if (!once)
- {
RAWINPUT raw_input;
raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE;
__wine_send_raw_input(&raw_input);
once = 1;
- }
+}
/***********************************************************************
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(); @@ -318,7 +333,6 @@ static void enable_xinput2(void) 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 );
@@ -337,19 +351,21 @@ static void enable_xinput2(void) data->xi2_current_slave = 0;
data->xi2_state = xi_enabled;
- inform_wineserver();
#endif }
/***********************************************************************
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;
@@ -368,6 +384,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
@@ -393,9 +424,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 ); @@ -423,7 +454,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) {
disable_xinput2();
}disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE;
@@ -489,7 +520,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) TRACE( "clip hwnd reset from %p\n", hwnd ); data->clip_hwnd = 0; data->clip_reset = GetTickCount();
disable_xinput2();
} else if (hwnd == GetForegroundWindow()) /* request to clip */disable_xinput2_path(); DestroyWindow( hwnd );
@@ -1724,16 +1755,19 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel;
static unsigned int last_cookie = 0;
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 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 @@ -1758,12 +1792,20 @@ 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 ); input.u.mi.dwExtraInfo = 0;
- input.u.mi.dx = 0;
- input.u.mi.dy = 0;
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.lLastX = 0;
raw_input.data.mouse.lLastY = 0;
virtual_rect = get_virtual_screen_rect();
@@ -1771,12 +1813,15 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) { 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.lLastX = raw_dx = raw_val; } if (i == y_rel->number) {
@@ -1784,6 +1829,8 @@ 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.lLastY = raw_dy = raw_val; }
@@ -1793,10 +1840,18 @@ 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 );
- }
- if (InterlockedExchange(&last_cookie, xev->cookie) != xev->cookie)
- {
TRACE("raw event %f,%f\n", raw_dx, raw_dy);
__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 a0308b0675..a9138eef2a 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -194,6 +194,8 @@ extern BOOL 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,7 +337,7 @@ 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; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e67a3c05a9..351ab89781 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -610,6 +610,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 );
@@ -680,6 +682,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (use_xim) X11DRV_SetupXIM();
- X11DRV_XInput2_Enable();
- return data;
}
-- 2.22.0
Signed-off-by: Derek Lesho [email protected] --- dlls/winex11.drv/mouse.c | 89 +++++++++++++++++++++++++++------- dlls/winex11.drv/x11drv.h | 4 +- dlls/winex11.drv/x11drv_main.c | 4 ++ 3 files changed, 79 insertions(+), 18 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..db71a33a41 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -284,11 +284,26 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } #endif
+/*********************************************************************** + * inform_wineserver + */ +static void inform_wineserver(void) +{ + static int once = 0; + if (!once) + { + RAWINPUT raw_input; + raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE; + __wine_send_raw_input(&raw_input); + once = 1; + } +} +
/*********************************************************************** - * 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(); @@ -318,7 +333,6 @@ static void enable_xinput2(void) 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 );
@@ -337,19 +351,21 @@ static void enable_xinput2(void) data->xi2_current_slave = 0;
data->xi2_state = xi_enabled; + + inform_wineserver(); #endif }
/*********************************************************************** - * 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; @@ -368,6 +384,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 @@ -393,9 +424,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 ); @@ -423,7 +454,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) { - disable_xinput2(); + disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE; } @@ -489,7 +520,7 @@ LRESULT clip_cursor_notify( HWND 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 */ @@ -1724,16 +1755,19 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel; + static unsigned long last_time = 0;
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 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 @@ -1758,12 +1792,20 @@ 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 ); input.u.mi.dwExtraInfo = 0; - input.u.mi.dx = 0; - input.u.mi.dy = 0; + 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.lLastX = 0; + raw_input.data.mouse.lLastY = 0;
virtual_rect = get_virtual_screen_rect();
@@ -1771,12 +1813,15 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) { 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.lLastX = raw_dx = raw_val; } if (i == y_rel->number) { @@ -1784,6 +1829,8 @@ 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.lLastY = raw_dy = raw_val; } }
@@ -1793,10 +1840,18 @@ 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 ); + } + + if (InterlockedExchange( (LONG volatile*)&last_time, (LONG)event->time ) != event->time) + { + TRACE("raw event %f,%f\n", raw_dx, raw_dy); + __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 a0308b0675..a9138eef2a 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -194,6 +194,8 @@ extern BOOL 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,7 +337,7 @@ 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; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e67a3c05a9..351ab89781 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -610,6 +610,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 ); @@ -680,6 +682,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (use_xim) X11DRV_SetupXIM();
+ X11DRV_XInput2_Enable(); + return data; }
It looks like that if the cursor isn't clipped by the application (or by wine in fullscreen), then both master and slave XI2 device events are received (on the contrary, when the cursor is clipped then for some unclear reason only the slave device events are received).
In this case, one of the events is then discarded by merge_raw_motion_events in dlls/winex11.drv/event.c and as X11DRV_RawMotion is designed to track only slave devices (one per thread with the xi2_current_slave field AFAICS?), depending on which comes first, the event might not be processed and no raw input be sent.
Thank you for looking into this, would the solution to this problem be to preserve the event from the slave pointer in merge_raw_events?
On Mon, Jul 22, 2019 at 10:06 AM Rémi Bernon [email protected] wrote:
It looks like that if the cursor isn't clipped by the application (or by wine in fullscreen), then both master and slave XI2 device events are received (on the contrary, when the cursor is clipped then for some unclear reason only the slave device events are received).
In this case, one of the events is then discarded by merge_raw_motion_events in dlls/winex11.drv/event.c and as X11DRV_RawMotion is designed to track only slave devices (one per thread with the xi2_current_slave field AFAICS?), depending on which comes first, the event might not be processed and no raw input be sent. -- Rémi Bernon [email protected]
On Mon, 2019-07-22 at 22:16 -0400, Derek Lesho wrote:
Thank you for looking into this, would the solution to this problem be to preserve the event from the slave pointer in merge_raw_events?
On Mon, Jul 22, 2019 at 10:06 AM Rémi Bernon [email protected] wrote:
It looks like that if the cursor isn't clipped by the application (or by wine in fullscreen), then both master and slave XI2 device events are received (on the contrary, when the cursor is clipped then for some unclear reason only the slave device events are received).
In this case, one of the events is then discarded by merge_raw_motion_events in dlls/winex11.drv/event.c and as X11DRV_RawMotion is designed to track only slave devices (one per thread with the xi2_current_slave field AFAICS?), depending on which comes first, the event might not be processed and no raw input be sent. -- Rémi Bernon [email protected]
I'm still not sure how everything works in winex11.drv, but I believe raw input implementation could use some cleanup. For instance, I don't understand why a single slave device is selected rather than listening to the master device events, I find it a bit unreliable that the first slave device that sends events is selected over the others.
I would say that, for simplicity, only the master device events should be translated, but that would require to make it send events even when the cursor is clipped, and first understand why it doesn't (AFAICS with some Xlib test app, there's no differences before and after calling XGrabPointer so there's something else going on).
If that's not possible, or for a "better" implementation, then all and only slave devices should be listened to, and their inputs translated to the corresponding Windows raw input messages. Also, it may be useful to implement WM_INPUT_DEVICE_CHANGE messages on the corresponding XInput2 events (but that may be done later and only if deemed useful).
On Tue, 2019-07-23 at 09:26 +0200, Rémi Bernon wrote:
On Mon, 2019-07-22 at 22:16 -0400, Derek Lesho wrote:
Thank you for looking into this, would the solution to this problem be to preserve the event from the slave pointer in merge_raw_events?
On Mon, Jul 22, 2019 at 10:06 AM Rémi Bernon [email protected] wrote:
It looks like that if the cursor isn't clipped by the application (or by wine in fullscreen), then both master and slave XI2 device events are received (on the contrary, when the cursor is clipped then for some unclear reason only the slave device events are received).
In this case, one of the events is then discarded by merge_raw_motion_events in dlls/winex11.drv/event.c and as X11DRV_RawMotion is designed to track only slave devices (one per thread with the xi2_current_slave field AFAICS?), depending on which comes first, the event might not be processed and no raw input be sent. -- Rémi Bernon [email protected]
I'm still not sure how everything works in winex11.drv, but I believe raw input implementation could use some cleanup. For instance, I don't understand why a single slave device is selected rather than listening to the master device events, I find it a bit unreliable that the first slave device that sends events is selected over the others.
From http://who-t.blogspot.com/2009/06/xi2-recipes-part-3.html it looks
like every time the user starts using a different slave device, there's a DeviceChanged event being sent, so I guess it explains why.
I would say that, for simplicity, only the master device events should be translated, but that would require to make it send events even when the cursor is clipped, and first understand why it doesn't (AFAICS with some Xlib test app, there's no differences before and after calling XGrabPointer so there's something else going on).
If that's not possible, or for a "better" implementation, then all and only slave devices should be listened to, and their inputs translated to the corresponding Windows raw input messages. Also, it may be useful to implement WM_INPUT_DEVICE_CHANGE messages on the corresponding XInput2 events (but that may be done later and only if deemed useful).
Reading the series of posts about XInput2 linked above makes me think that listening to master devices is the correct way to proceed. It will also simplify the code, as we could even simplify the event mask by using XIAllMasterDevices instead of having to filter the events.
Regarding why master device events aren't sent once XGrabPointer is active only, the reason looks to be that wine advertises to support XInput 2.0 client API only. Calling XIQueryVersion with major = 2 and minor >= 1 in X11DRV_XInput2_Enable fixes the issue.
With all that, I believe that you should be able to make every window thread listen to XInput2 events without worrying anymore about duplicates, and the wineserver will dispatch the events to the right windows. You could maybe decide to report the raw inputs only to the foreground window in wineserver, or implement the RIDEV_INPUTSINK flag / RIM_INPUTSINK wParam for background raw input.
Thank you so much for your help, I'll make the relevant changes as soon as I get home.
On Tue, Jul 23, 2019 at 10:34 AM Rémi Bernon [email protected] wrote:
On Tue, 2019-07-23 at 09:26 +0200, Rémi Bernon wrote:
On Mon, 2019-07-22 at 22:16 -0400, Derek Lesho wrote:
Thank you for looking into this, would the solution to this problem be
to
preserve the event from the slave pointer in merge_raw_events?
On Mon, Jul 22, 2019 at 10:06 AM Rémi Bernon [email protected] wrote:
It looks like that if the cursor isn't clipped by the application (or by wine in fullscreen), then both master and slave XI2 device events are received (on the contrary, when the cursor is clipped then for
some
unclear reason only the slave device events are received).
In this case, one of the events is then discarded by merge_raw_motion_events in dlls/winex11.drv/event.c and as X11DRV_RawMotion is designed to track only slave devices (one per thread with the xi2_current_slave field AFAICS?), depending on which comes first, the event might not be processed and no raw input be
sent.
-- Rémi Bernon [email protected]
I'm still not sure how everything works in winex11.drv, but I believe raw input implementation could use some cleanup. For instance, I don't understand why a single slave device is selected rather than listening to the master device events, I find it a bit unreliable that the first slave device that sends events is selected over the others.
From http://who-t.blogspot.com/2009/06/xi2-recipes-part-3.html it looks like every time the user starts using a different slave device, there's a DeviceChanged event being sent, so I guess it explains why.
I would say that, for simplicity, only the master device events should be translated, but that would require to make it send events even when the cursor is clipped, and first understand why it doesn't (AFAICS with some Xlib test app, there's no differences before and after calling XGrabPointer so there's something else going on).
If that's not possible, or for a "better" implementation, then all and only slave devices should be listened to, and their inputs translated to the corresponding Windows raw input messages. Also, it may be useful to implement WM_INPUT_DEVICE_CHANGE messages on the corresponding XInput2 events (but that may be done later and only if deemed useful).
Reading the series of posts about XInput2 linked above makes me think that listening to master devices is the correct way to proceed. It will also simplify the code, as we could even simplify the event mask by using XIAllMasterDevices instead of having to filter the events.
Regarding why master device events aren't sent once XGrabPointer is active only, the reason looks to be that wine advertises to support XInput 2.0 client API only. Calling XIQueryVersion with major = 2 and minor >= 1 in X11DRV_XInput2_Enable fixes the issue.
With all that, I believe that you should be able to make every window thread listen to XInput2 events without worrying anymore about duplicates, and the wineserver will dispatch the events to the right windows. You could maybe decide to report the raw inputs only to the foreground window in wineserver, or implement the RIDEV_INPUTSINK flag / RIM_INPUTSINK wParam for background raw input. -- Rémi Bernon [email protected]
On Sat, 2019-07-20 at 16:09 -0400, Derek Lesho wrote:
Signed-off-by: Derek Lesho [email protected]
dlls/winex11.drv/mouse.c | 89 +++++++++++++++++++++++++++------- dlls/winex11.drv/x11drv.h | 4 +- dlls/winex11.drv/x11drv_main.c | 4 ++ 3 files changed, 79 insertions(+), 18 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..db71a33a41 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -284,11 +284,26 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } #endif
+/***********************************************************************
inform_wineserver
- */
+static void inform_wineserver(void) +{
- static int once = 0;
- if (!once)
- {
RAWINPUT raw_input;
raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE;
__wine_send_raw_input(&raw_input);
once = 1;
- }
+}
/***********************************************************************
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(); @@ -318,7 +333,6 @@ static void enable_xinput2(void) 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 );
@@ -337,19 +351,21 @@ static void enable_xinput2(void) data->xi2_current_slave = 0;
data->xi2_state = xi_enabled;
- inform_wineserver();
#endif }
/***********************************************************************
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;
@@ -368,6 +384,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
@@ -393,9 +424,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 );
@@ -423,7 +454,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) {
disable_xinput2();
}disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE;
@@ -489,7 +520,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) TRACE( "clip hwnd reset from %p\n", hwnd ); data->clip_hwnd = 0; data->clip_reset = GetTickCount();
disable_xinput2();
} else if (hwnd == GetForegroundWindow()) /* request to clip */disable_xinput2_path(); DestroyWindow( hwnd );
@@ -1724,16 +1755,19 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel;
static unsigned long last_time = 0;
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 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
@@ -1758,12 +1792,20 @@ 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 ); input.u.mi.dwExtraInfo = 0;
- input.u.mi.dx = 0;
- input.u.mi.dy = 0;
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.lLastX = 0;
raw_input.data.mouse.lLastY = 0;
virtual_rect = get_virtual_screen_rect();
@@ -1771,12 +1813,15 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) { 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.lLastX = raw_dx = raw_val; } if (i == y_rel->number) {
@@ -1784,6 +1829,8 @@ 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.lLastY = raw_dy = raw_val; }
@@ -1793,10 +1840,18 @@ 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 );
- }
- if (InterlockedExchange( (LONG volatile*)&last_time, (LONG)event->time ) != event->time)
- {
TRACE("raw event %f,%f\n", raw_dx, raw_dy);
__wine_send_raw_input( &raw_input );
- }
- input.type = INPUT_MOUSE;
- __wine_send_input( 0, &input ); return TRUE;
}
I think it /should/ be safe to only call __wine_send_raw_input here, although not 100% sure about it.
AFAICS MotionNotify events are sent as well - even with a 0x0 clip rectangle - and they will get translated to the corresponding WM_MOUSE* and WM_*BUTTON* events, and update the desktop cursor position if necessary. I understand that the call was here only to trigger the raw input emulation.
Signed-off-by: Derek Lesho [email protected] --- dlls/winex11.drv/mouse.c | 150 ++++++++++++++++----------------- dlls/winex11.drv/x11drv.h | 8 +- dlls/winex11.drv/x11drv_main.c | 4 + 3 files changed, 81 insertions(+), 81 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..f328eb369c 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -284,15 +284,31 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } #endif
+/*********************************************************************** + * inform_wineserver + */ +static void inform_wineserver(void) +{ + static int once = 0; + if (!once) + { + RAWINPUT raw_input; + raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE; + __wine_send_raw_input(&raw_input); + once = 1; + } +} +
/*********************************************************************** - * 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(); XIEventMask mask; + int core_pointer; XIDeviceInfo *pointer_info; unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)]; int count; @@ -301,7 +317,7 @@ static void enable_xinput2(void)
if (data->xi2_state == xi_unknown) { - int major = 2, minor = 0; + int major = 2, minor = 1; if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled; else { @@ -310,64 +326,65 @@ static void enable_xinput2(void) } } if (data->xi2_state == xi_unavailable) return; - if (!pXIGetClientPointer( data->display, None, &data->xi2_core_pointer )) return; + if (!pXIGetClientPointer( data->display, None, &core_pointer )) return;
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 );
pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 );
- pointer_info = pXIQueryDevice( data->display, data->xi2_core_pointer, &count ); + pointer_info = pXIQueryDevice( data->display, 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; + + inform_wineserver(); #endif }
/*********************************************************************** - * 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;
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 }
+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 @@ -393,9 +410,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 ); @@ -423,7 +440,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) { - disable_xinput2(); + disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE; } @@ -489,7 +506,7 @@ LRESULT clip_cursor_notify( HWND 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 */ @@ -1701,22 +1718,6 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev )
#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
-/*********************************************************************** - * X11DRV_DeviceChanged - */ -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; -} - /*********************************************************************** * X11DRV_RawMotion */ @@ -1724,46 +1725,36 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel;
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 (thread_data->xi2_state < xi_enabled) return FALSE;
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 ); input.u.mi.dwExtraInfo = 0; - input.u.mi.dx = 0; - input.u.mi.dy = 0; + 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.lLastX = 0; + raw_input.data.mouse.lLastY = 0;
virtual_rect = get_virtual_screen_rect();
@@ -1771,12 +1762,15 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) { 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.lLastX = raw_dx = raw_val; } if (i == y_rel->number) { @@ -1784,6 +1778,8 @@ 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.lLastY = raw_dy = raw_val; } }
@@ -1793,10 +1789,15 @@ 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 event %f,%f\n", raw_dx, raw_dy); + __wine_send_raw_input( &raw_input );
- input.type = INPUT_MOUSE; - __wine_send_input( 0, &input ); return TRUE; }
@@ -1858,9 +1859,6 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev )
switch (event->evtype) { - case XI_DeviceChanged: - ret = X11DRV_DeviceChanged( event ); - break; case XI_RawMotion: ret = X11DRV_RawMotion( event ); break; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index a0308b0675..a6d64f4383 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -194,6 +194,8 @@ extern BOOL 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,13 +337,9 @@ 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 */ - void *xi2_devices; /* list of XInput2 devices (valid when state is enabled) */ - int xi2_device_count; + enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled, xi_extra } xi2_state; /* XInput2 state */ 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; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e67a3c05a9..351ab89781 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -610,6 +610,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 ); @@ -680,6 +682,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (use_xim) X11DRV_SetupXIM();
+ X11DRV_XInput2_Enable(); + return data; }
This update has wine use XI2.1 and removes the legacy code dealing with the quirks in XI2.0. It also removes the duplicate event detection, as the server is smarter and will only accept raw-input events from the correct thread.
Thank you again for debugging the XI2.0 issue Remi!
On Fri, Jul 26, 2019 at 3:31 PM Derek Lesho [email protected] wrote:
Signed-off-by: Derek Lesho [email protected]
dlls/winex11.drv/mouse.c | 150 ++++++++++++++++----------------- dlls/winex11.drv/x11drv.h | 8 +- dlls/winex11.drv/x11drv_main.c | 4 + 3 files changed, 81 insertions(+), 81 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..f328eb369c 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -284,15 +284,31 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } #endif
+/***********************************************************************
inform_wineserver
- */
+static void inform_wineserver(void) +{
- static int once = 0;
- if (!once)
- {
RAWINPUT raw_input;
raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE;
__wine_send_raw_input(&raw_input);
once = 1;
- }
+}
/***********************************************************************
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(); XIEventMask mask;
- int core_pointer; XIDeviceInfo *pointer_info; unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)]; int count;
@@ -301,7 +317,7 @@ static void enable_xinput2(void)
if (data->xi2_state == xi_unknown) {
int major = 2, minor = 0;
int major = 2, minor = 1; if (!pXIQueryVersion( data->display, &major, &minor ))
data->xi2_state = xi_disabled; else { @@ -310,64 +326,65 @@ static void enable_xinput2(void) } } if (data->xi2_state == xi_unavailable) return;
- if (!pXIGetClientPointer( data->display, None,
&data->xi2_core_pointer )) return;
- if (!pXIGetClientPointer( data->display, None, &core_pointer ))
return;
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 );
pXISelectEvents( data->display, DefaultRootWindow( data->display ),
&mask, 1 );
- pointer_info = pXIQueryDevice( data->display, data->xi2_core_pointer,
&count );
- pointer_info = pXIQueryDevice( data->display, 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;
- inform_wineserver();
#endif }
/***********************************************************************
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;
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 }
+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
@@ -393,9 +410,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 ); @@ -423,7 +440,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) {
disable_xinput2();
}disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE;
@@ -489,7 +506,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) TRACE( "clip hwnd reset from %p\n", hwnd ); data->clip_hwnd = 0; data->clip_reset = GetTickCount();
disable_xinput2();
} else if (hwnd == GetForegroundWindow()) /* request to clip */disable_xinput2_path(); DestroyWindow( hwnd );
@@ -1701,22 +1718,6 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev )
#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
-/***********************************************************************
X11DRV_DeviceChanged
- */
-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;
-}
/***********************************************************************
X11DRV_RawMotion
*/ @@ -1724,46 +1725,36 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel;
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 (thread_data->xi2_state < xi_enabled) return FALSE;
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 ); input.u.mi.dwExtraInfo = 0;
- input.u.mi.dx = 0;
- input.u.mi.dy = 0;
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.lLastX = 0;
raw_input.data.mouse.lLastY = 0;
virtual_rect = get_virtual_screen_rect();
@@ -1771,12 +1762,15 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) { 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.lLastX = raw_dx = raw_val; } if (i == y_rel->number) {
@@ -1784,6 +1778,8 @@ 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.lLastY = raw_dy = raw_val; }
@@ -1793,10 +1789,15 @@ 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 event %f,%f\n", raw_dx, raw_dy);
- __wine_send_raw_input( &raw_input );
- input.type = INPUT_MOUSE;
- __wine_send_input( 0, &input ); return TRUE;
}
@@ -1858,9 +1859,6 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev )
switch (event->evtype) {
- case XI_DeviceChanged:
ret = X11DRV_DeviceChanged( event );
case XI_RawMotion: ret = X11DRV_RawMotion( event ); break;break;
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index a0308b0675..a6d64f4383 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -194,6 +194,8 @@ extern BOOL 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,13 +337,9 @@ 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 */
- void *xi2_devices; /* list of XInput2 devices (valid when
state is enabled) */
- int xi2_device_count;
- enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled,
xi_extra } xi2_state; /* XInput2 state */ 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; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e67a3c05a9..351ab89781 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -610,6 +610,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 );
@@ -680,6 +682,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (use_xim) X11DRV_SetupXIM();
- X11DRV_XInput2_Enable();
- return data;
}
-- 2.22.0
Signed-off-by: Derek Lesho [email protected] --- v9: Remove inform_wineserver, as we don't support button presses / the wheel until patch 7 --- dlls/winex11.drv/mouse.c | 133 ++++++++++++++------------------- dlls/winex11.drv/x11drv.h | 8 +- dlls/winex11.drv/x11drv_main.c | 4 + 3 files changed, 64 insertions(+), 81 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a5..7423f946b9 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -286,13 +286,14 @@ 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(); XIEventMask mask; + int core_pointer; XIDeviceInfo *pointer_info; unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)]; int count; @@ -301,7 +302,7 @@ static void enable_xinput2(void)
if (data->xi2_state == xi_unknown) { - int major = 2, minor = 0; + int major = 2, minor = 1; if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled; else { @@ -310,64 +311,63 @@ static void enable_xinput2(void) } } if (data->xi2_state == xi_unavailable) return; - if (!pXIGetClientPointer( data->display, None, &data->xi2_core_pointer )) return; + if (!pXIGetClientPointer( data->display, None, &core_pointer )) return;
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 );
pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 );
- pointer_info = pXIQueryDevice( data->display, data->xi2_core_pointer, &count ); + pointer_info = pXIQueryDevice( data->display, 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 + * 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;
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 }
+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 @@ -393,9 +393,9 @@ static BOOL grab_clipping_window( const RECT *clip ) return TRUE;
/* 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 ); @@ -423,7 +423,7 @@ static BOOL grab_clipping_window( const RECT *clip )
if (!clipping_cursor) { - disable_xinput2(); + disable_xinput2_path(); DestroyWindow( msg_hwnd ); return FALSE; } @@ -489,7 +489,7 @@ LRESULT clip_cursor_notify( HWND 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 */ @@ -1701,22 +1701,6 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev )
#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
-/*********************************************************************** - * X11DRV_DeviceChanged - */ -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; -} - /*********************************************************************** * X11DRV_RawMotion */ @@ -1724,46 +1708,36 @@ 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_dx = 0, raw_dy = 0, val, raw_val; struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_valuator_data *x_rel, *y_rel;
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 (thread_data->xi2_state < xi_enabled) return FALSE;
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 ); input.u.mi.dwExtraInfo = 0; - input.u.mi.dx = 0; - input.u.mi.dy = 0; + 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.lLastX = 0; + raw_input.data.mouse.lLastY = 0;
virtual_rect = get_virtual_screen_rect();
@@ -1771,12 +1745,15 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) { 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.lLastX = raw_dx = raw_val; } if (i == y_rel->number) { @@ -1784,6 +1761,8 @@ 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.lLastY = raw_dy = raw_val; } }
@@ -1793,10 +1772,15 @@ 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 event %f,%f\n", raw_dx, raw_dy); + __wine_send_raw_input( &raw_input );
- input.type = INPUT_MOUSE; - __wine_send_input( 0, &input ); return TRUE; }
@@ -1858,9 +1842,6 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev )
switch (event->evtype) { - case XI_DeviceChanged: - ret = X11DRV_DeviceChanged( event ); - break; case XI_RawMotion: ret = X11DRV_RawMotion( event ); break; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index a0308b0675..a6d64f4383 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -194,6 +194,8 @@ extern BOOL 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,13 +337,9 @@ 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 */ - void *xi2_devices; /* list of XInput2 devices (valid when state is enabled) */ - int xi2_device_count; + enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled, xi_extra } xi2_state; /* XInput2 state */ 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; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e67a3c05a9..351ab89781 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -610,6 +610,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 ); @@ -680,6 +682,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
if (use_xim) X11DRV_SetupXIM();
+ X11DRV_XInput2_Enable(); + return data; }
This would benefit from a split between xinput 2.1 request (as attached for example) and the original raw-input related patch.
Also, I believe you can completely replace the existing code with you raw input version, and remove all the "extra" level used for cursor clipping.
This also means that the "Don't react to small slow mouse movements." patch may now be obsolete as the raw values will directly be passed to the server.
As a related note, also for the next patch in the serie, AFAICS Windows raw values for X/Y movements are the same between Windows and XInput2, but I see a 8x scaling factor for the mouse wheel values that may be missing.
I agree that splitting up the patches is a good idea, but is it necessary that we continue supporting XInput 2.0? 2.1 was released in 2011 and I doubt many people running the latest versions of wine are going to be on such an ancient xserver.
Also, I am not quite sure what you mean by replacing the existing code with the rawinput version. Windows raw-input still operates on ints, and XI2 only sends rawmotion mouse events in raw_values as whole numbers, even if they're floats. However, when getting the data from valuators.values, there are not whole due from mouse acceleration / scaling. Even if we did send the floats to wineserver, I don't know how we'd transform them ourselves to match what the DE does ourselves.
On Mon, Jul 29, 2019 at 10:14 AM Rémi Bernon [email protected] wrote:
This would benefit from a split between xinput 2.1 request (as attached for example) and the original raw-input related patch.
Also, I believe you can completely replace the existing code with you raw input version, and remove all the "extra" level used for cursor clipping.
This also means that the "Don't react to small slow mouse movements." patch may now be obsolete as the raw values will directly be passed to the server.
As a related note, also for the next patch in the serie, AFAICS Windows raw values for X/Y movements are the same between Windows and XInput2, but I see a 8x scaling factor for the mouse wheel values that may be missing. -- Rémi Bernon [email protected]
On 7/29/19 7:00 PM, Derek Lesho wrote:
I agree that splitting up the patches is a good idea, but is it necessary that we continue supporting XInput 2.0? 2.1 was released in 2011 and I doubt many people running the latest versions of wine are going to be on such an ancient xserver.
I agree but it may be a matter of taste and Alexandre will decide whether he's OK with requiring XInput >= 2.1. I wrote the patch to be backward compatible but it could be simplified if that's OK.
Also, I am not quite sure what you mean by replacing the existing code with the rawinput version.
AFAIU the existing RawMotion event handler was sending INPUT messages to the server for the sole purpose of emulating and sending raw input messages. It is not required anymore so you can replace this "normal" input with your "raw" input code. The "normal" input messages will still be sent when MotionNotify events are processed.
Windows raw-input still operates on ints,
and XI2 only sends rawmotion mouse events in raw_values as whole numbers, even if they're floats. However, when getting the data from valuators.values, there are not whole due from mouse acceleration / scaling. Even if we did send the floats to wineserver, I don't know how we'd transform them ourselves to match what the DE does ourselves.
From what I could see for relative X/Y, XInput2 raw values looks to be integral values in floating point fields, and the values are the same as on Windows: +-1.0 for the smallest increment. Of course it may depend on the hardware / driver; I tested with some generic touchpad and mouse with the same results.
It looks to be slightly different for mouse wheel though, with an 8x factor:
* Using a stepping mouse wheel, I saw +-15.0 for a wheel step in XInput2, corresponding to +-120 on Windows.
* With touchpad finger scrolling, the smallest XInput2 raw value was around 0.488158 but Windows was acting like it was accumulating until value was >= 120 (but that may also be the VM acting in the middle).
AFAIU the existing RawMotion event handler was sending INPUT messages to the server for the sole purpose of emulating and sending raw input messages.
It was my impression that MotionNotify events are ignored when the the cursor is clipped, due to some bug or problem it. I went searching to see whether the case, and I found this: https://github.com/wine-mirror/wine/commit/0e2b4f99a9f5d97f8da0189037b7516cf...
This commit came around the time they were adding raw-input, and it seems to indicate that there is a problem w/ MotionNotify on a clipped cursor, but the ignore case isn't there anymore so maybe things have changed. Some other reasons I'm skeptical that the RawMotion code currently in place is only for rawinput events are that
1) The input is also sent as WM_MOUSEMOVE by the server, as there was no previous infrastructure to send raw-input separately and
2) When somebody tested warframe with my patch before I re-added mouse-movements, they had issues that were fixed by rebasing mouse-movements on my commit, and warframe does not use raw-input for the mouse.
As for the rest of your email, thank you for doing the testing to confirm these values.
On Tue, Jul 30, 2019 at 3:42 AM Rémi Bernon [email protected] wrote:
On 7/29/19 7:00 PM, Derek Lesho wrote:
I agree that splitting up the patches is a good idea, but is it necessary that we continue supporting XInput 2.0? 2.1 was released in 2011 and I doubt many people running the latest versions of wine are going to be on such an ancient xserver.
I agree but it may be a matter of taste and Alexandre will decide whether he's OK with requiring XInput >= 2.1. I wrote the patch to be backward compatible but it could be simplified if that's OK.
Also, I am not quite sure what you mean by replacing the existing code with the rawinput version.
AFAIU the existing RawMotion event handler was sending INPUT messages to the server for the sole purpose of emulating and sending raw input messages. It is not required anymore so you can replace this "normal" input with your "raw" input code. The "normal" input messages will still be sent when MotionNotify events are processed.
Windows raw-input still operates on ints,
and XI2 only sends rawmotion mouse events in raw_values as whole numbers, even if they're floats. However, when getting the data from valuators.values, there are not whole due from mouse acceleration / scaling. Even if we did send the floats to wineserver, I don't know how we'd transform them ourselves to match what the DE does ourselves.
From what I could see for relative X/Y, XInput2 raw values looks to be integral values in floating point fields, and the values are the same as on Windows: +-1.0 for the smallest increment. Of course it may depend on the hardware / driver; I tested with some generic touchpad and mouse with the same results.
It looks to be slightly different for mouse wheel though, with an 8x factor:
- Using a stepping mouse wheel, I saw +-15.0 for a wheel step in
XInput2, corresponding to +-120 on Windows.
- With touchpad finger scrolling, the smallest XInput2 raw value was
around 0.488158 but Windows was acting like it was accumulating until value was >= 120 (but that may also be the VM acting in the middle). -- Rémi Bernon [email protected]
On 7/31/19 12:41 AM, Derek Lesho wrote:
AFAIU the existing RawMotion event handler was sending INPUT messages to the server for the sole purpose of emulating and sending raw input messages.
It was my impression that MotionNotify events are ignored when the the cursor is clipped, due to some bug or problem it. I went searching to see whether the case, and I found this: https://github.com/wine-mirror/wine/commit/0e2b4f99a9f5d97f8da0189037b7516cf...
This commit came around the time they were adding raw-input, and it seems to indicate that there is a problem w/ MotionNotify on a clipped cursor, but the ignore case isn't there anymore so maybe things have changed. Some other reasons I'm skeptical that the RawMotion code currently in place is only for rawinput events are that
- The input is also sent as WM_MOUSEMOVE by the server, as there was
no previous infrastructure to send raw-input separately and
This commit is about warping the cursor, then ignoring the MotionNotify event induced by the warp itself.
I can see that the a pre-existing ignore case for MotionNotify events while clipping is active, comes from https://github.com/wine-mirror/wine/commit/8e9b4e0a5c6bee5f72ca2314db2623363... and https://github.com/wine-mirror/wine/commit/da9922b40da5bc581815a4357340f3f12..., then reverted in https://github.com/wine-mirror/wine/commit/9716d1c8619e5fe68d1ad3ab9a18b1064....
About these commits, I believe that while xinput2 events are received, and because they were translated as both raw input messages and normal input messages, it was maybe redundant to listen to MotionNotify as well. Also, the oldest commit makes me think that there could be some back-and-forth movement issues if MotionNotify events are processed while RawMotion events were delayed.
Now regarding the interactions between MotionNotify and RawMotion events while clipping the cursor, AFAICS MotionNotify events are still received when the cursor moves but is blocked by the X11 confine window, with its current position in x,y fields.
This means that regardless if the cursor is clipped or not, both MotionNotify and RawMotion events will currently get translated to raw and normal input messages, the raw message position being compared to the current position and converted to relative position, and the normal input message position being clamped with the clipping window and not sent if it is the same as the last known position (see queue_hardware_message in server/queue.c and https://github.com/wine-mirror/wine/commit/3909f51122ffc0f6150fa9758ba47c70d...).
So with the current code:
* If the cursor moved (inside a clipping window), you get a normal input message from either MotionNotify or RawMotion (which ever came first), then two raw input message, one with the corresponding relative movement, and another with 0x0 relative movement. The second normal input message is discarded because the cursor didn't move.
* If the cursor is clipped and blocked by confine window, Wine receives (order may vary as well):
* a MotionNotify event with identical position, which is translated to raw input message with 0x0 relative movement, but does not get translated to normal input message because the cursor didn't move.
* a RawMotion event with some relative movement, which is translated to the corresponding raw input message with relative movement, and is added to current position, then clamped, and then ignored w.r.t. normal input message because the clamped position is the same as the last.
Currently if the clipping window is disabled, then no RawMotion events are received anyway.
- When somebody tested warframe with my patch before I re-added
mouse-movements, they had issues that were fixed by rebasing mouse-movements on my commit, and warframe does not use raw-input for the mouse.
There could be some subtleties I may be overlooking, I will do some tests. Thanks for mentioning it.
I just tested disabling normal input from RawMotion in oblivion, which uses dinput, which does not use rawinput. Without it, I can not move the mouse outside of the confines of the clip even when the pointer is invisible / locked. I think that relative MOUSEMOVE events are still supposed to be sent when the cursor is pushing up against the clip, which would mean we need to keep the __wine_send_input extra stuff. I have the rest of the changes you requested completed and will submit them tomorrow as it's getting late here.
On Wed, Jul 31, 2019 at 4:04 AM Rémi Bernon [email protected] wrote:
On 7/31/19 12:41 AM, Derek Lesho wrote:
AFAIU the existing RawMotion event handler was sending INPUT messages to the server for the sole purpose of emulating and sending raw input messages.
It was my impression that MotionNotify events are ignored when the the cursor is clipped, due to some bug or problem it. I went searching to see whether the case, and I found this: https://github.com/wine-mirror/wine/commit/0e2b4f99a9f5d97f8da0189037b7516cf...
This commit came around the time they were adding raw-input, and it seems to indicate that there is a problem w/ MotionNotify on a clipped cursor, but the ignore case isn't there anymore so maybe things have changed. Some other reasons I'm skeptical that the RawMotion code currently in place is only for rawinput events are that
- The input is also sent as WM_MOUSEMOVE by the server, as there was
no previous infrastructure to send raw-input separately and
This commit is about warping the cursor, then ignoring the MotionNotify event induced by the warp itself.
I can see that the a pre-existing ignore case for MotionNotify events while clipping is active, comes from https://github.com/wine-mirror/wine/commit/8e9b4e0a5c6bee5f72ca2314db2623363... and https://github.com/wine-mirror/wine/commit/da9922b40da5bc581815a4357340f3f12..., then reverted in https://github.com/wine-mirror/wine/commit/9716d1c8619e5fe68d1ad3ab9a18b1064....
About these commits, I believe that while xinput2 events are received, and because they were translated as both raw input messages and normal input messages, it was maybe redundant to listen to MotionNotify as well. Also, the oldest commit makes me think that there could be some back-and-forth movement issues if MotionNotify events are processed while RawMotion events were delayed.
Now regarding the interactions between MotionNotify and RawMotion events while clipping the cursor, AFAICS MotionNotify events are still received when the cursor moves but is blocked by the X11 confine window, with its current position in x,y fields.
This means that regardless if the cursor is clipped or not, both MotionNotify and RawMotion events will currently get translated to raw and normal input messages, the raw message position being compared to the current position and converted to relative position, and the normal input message position being clamped with the clipping window and not sent if it is the same as the last known position (see queue_hardware_message in server/queue.c and https://github.com/wine-mirror/wine/commit/3909f51122ffc0f6150fa9758ba47c70d...).
So with the current code:
- If the cursor moved (inside a clipping window), you get a normal input
message from either MotionNotify or RawMotion (which ever came first), then two raw input message, one with the corresponding relative movement, and another with 0x0 relative movement. The second normal input message is discarded because the cursor didn't move.
- If the cursor is clipped and blocked by confine window, Wine receives
(order may vary as well):
- a MotionNotify event with identical position, which is translated
to raw input message with 0x0 relative movement, but does not get translated to normal input message because the cursor didn't move.
- a RawMotion event with some relative movement, which is translated
to the corresponding raw input message with relative movement, and is added to current position, then clamped, and then ignored w.r.t. normal input message because the clamped position is the same as the last.
Currently if the clipping window is disabled, then no RawMotion events are received anyway.
- When somebody tested warframe with my patch before I re-added
mouse-movements, they had issues that were fixed by rebasing mouse-movements on my commit, and warframe does not use raw-input for the mouse.
There could be some subtleties I may be overlooking, I will do some tests. Thanks for mentioning it. -- Rémi Bernon [email protected]
To add a little bit of further clarification, the purpose of sending normal input from rawmotion is for when we are at the edge of a clip and WM_MOUSEMOVE events without the MOUSEEVENTF_ABSOLUTE flag are sent, indicating the dx and dy parameters are relative.
On Thu, Aug 1, 2019 at 2:34 AM Derek Lesho [email protected] wrote:
I just tested disabling normal input from RawMotion in oblivion, which uses dinput, which does not use rawinput. Without it, I can not move the mouse outside of the confines of the clip even when the pointer is invisible / locked. I think that relative MOUSEMOVE events are still supposed to be sent when the cursor is pushing up against the clip, which would mean we need to keep the __wine_send_input extra stuff. I have the rest of the changes you requested completed and will submit them tomorrow as it's getting late here.
On Wed, Jul 31, 2019 at 4:04 AM Rémi Bernon [email protected] wrote:
On 7/31/19 12:41 AM, Derek Lesho wrote:
AFAIU the existing RawMotion event handler was sending INPUT messages to the server for the sole purpose of emulating and sending raw input messages.
It was my impression that MotionNotify events are ignored when the the cursor is clipped, due to some bug or problem it. I went searching to see whether the case, and I found this: https://github.com/wine-mirror/wine/commit/0e2b4f99a9f5d97f8da0189037b7516cf...
This commit came around the time they were adding raw-input, and it seems to indicate that there is a problem w/ MotionNotify on a clipped cursor, but the ignore case isn't there anymore so maybe things have changed. Some other reasons I'm skeptical that the RawMotion code currently in place is only for rawinput events are that
- The input is also sent as WM_MOUSEMOVE by the server, as there was
no previous infrastructure to send raw-input separately and
This commit is about warping the cursor, then ignoring the MotionNotify event induced by the warp itself.
I can see that the a pre-existing ignore case for MotionNotify events while clipping is active, comes from https://github.com/wine-mirror/wine/commit/8e9b4e0a5c6bee5f72ca2314db2623363... and https://github.com/wine-mirror/wine/commit/da9922b40da5bc581815a4357340f3f12..., then reverted in https://github.com/wine-mirror/wine/commit/9716d1c8619e5fe68d1ad3ab9a18b1064....
About these commits, I believe that while xinput2 events are received, and because they were translated as both raw input messages and normal input messages, it was maybe redundant to listen to MotionNotify as well. Also, the oldest commit makes me think that there could be some back-and-forth movement issues if MotionNotify events are processed while RawMotion events were delayed.
Now regarding the interactions between MotionNotify and RawMotion events while clipping the cursor, AFAICS MotionNotify events are still received when the cursor moves but is blocked by the X11 confine window, with its current position in x,y fields.
This means that regardless if the cursor is clipped or not, both MotionNotify and RawMotion events will currently get translated to raw and normal input messages, the raw message position being compared to the current position and converted to relative position, and the normal input message position being clamped with the clipping window and not sent if it is the same as the last known position (see queue_hardware_message in server/queue.c and https://github.com/wine-mirror/wine/commit/3909f51122ffc0f6150fa9758ba47c70d...).
So with the current code:
- If the cursor moved (inside a clipping window), you get a normal input
message from either MotionNotify or RawMotion (which ever came first), then two raw input message, one with the corresponding relative movement, and another with 0x0 relative movement. The second normal input message is discarded because the cursor didn't move.
- If the cursor is clipped and blocked by confine window, Wine receives
(order may vary as well):
- a MotionNotify event with identical position, which is translated
to raw input message with 0x0 relative movement, but does not get translated to normal input message because the cursor didn't move.
- a RawMotion event with some relative movement, which is translated
to the corresponding raw input message with relative movement, and is added to current position, then clamped, and then ignored w.r.t. normal input message because the clamped position is the same as the last.
Currently if the clipping window is disabled, then no RawMotion events are received anyway.
- When somebody tested warframe with my patch before I re-added
mouse-movements, they had issues that were fixed by rebasing mouse-movements on my commit, and warframe does not use raw-input for the mouse.
There could be some subtleties I may be overlooking, I will do some tests. Thanks for mentioning it. -- Rémi Bernon [email protected]
On 8/1/19 8:34 AM, Derek Lesho wrote:
I just tested disabling normal input from RawMotion in oblivion, which uses dinput, which does not use rawinput. Without it, I can not move the mouse outside of the confines of the clip even when the pointer is invisible / locked. I think that relative MOUSEMOVE events are still supposed to be sent when the cursor is pushing up against the clip, which would mean we need to keep the __wine_send_input extra stuff. I have the rest of the changes you requested completed and will submit them tomorrow as it's getting late here.
On Wed, Jul 31, 2019 at 4:04 AM Rémi Bernon [email protected] wrote:
On 7/31/19 12:41 AM, Derek Lesho wrote:
AFAIU the existing RawMotion event handler was sending INPUT messages to the server for the sole purpose of emulating and sending raw input messages.
It was my impression that MotionNotify events are ignored when the the cursor is clipped, due to some bug or problem it. I went searching to see whether the case, and I found this: https://github.com/wine-mirror/wine/commit/0e2b4f99a9f5d97f8da0189037b7516cf...
This commit came around the time they were adding raw-input, and it seems to indicate that there is a problem w/ MotionNotify on a clipped cursor, but the ignore case isn't there anymore so maybe things have changed. Some other reasons I'm skeptical that the RawMotion code currently in place is only for rawinput events are that
- The input is also sent as WM_MOUSEMOVE by the server, as there was
no previous infrastructure to send raw-input separately and
This commit is about warping the cursor, then ignoring the MotionNotify event induced by the warp itself.
I can see that the a pre-existing ignore case for MotionNotify events while clipping is active, comes from https://github.com/wine-mirror/wine/commit/8e9b4e0a5c6bee5f72ca2314db2623363... and https://github.com/wine-mirror/wine/commit/da9922b40da5bc581815a4357340f3f12..., then reverted in https://github.com/wine-mirror/wine/commit/9716d1c8619e5fe68d1ad3ab9a18b1064....
About these commits, I believe that while xinput2 events are received, and because they were translated as both raw input messages and normal input messages, it was maybe redundant to listen to MotionNotify as well. Also, the oldest commit makes me think that there could be some back-and-forth movement issues if MotionNotify events are processed while RawMotion events were delayed.
Now regarding the interactions between MotionNotify and RawMotion events while clipping the cursor, AFAICS MotionNotify events are still received when the cursor moves but is blocked by the X11 confine window, with its current position in x,y fields.
This means that regardless if the cursor is clipped or not, both MotionNotify and RawMotion events will currently get translated to raw and normal input messages, the raw message position being compared to the current position and converted to relative position, and the normal input message position being clamped with the clipping window and not sent if it is the same as the last known position (see queue_hardware_message in server/queue.c and https://github.com/wine-mirror/wine/commit/3909f51122ffc0f6150fa9758ba47c70d...).
So with the current code:
- If the cursor moved (inside a clipping window), you get a normal input
message from either MotionNotify or RawMotion (which ever came first), then two raw input message, one with the corresponding relative movement, and another with 0x0 relative movement. The second normal input message is discarded because the cursor didn't move.
- If the cursor is clipped and blocked by confine window, Wine receives
(order may vary as well):
* a MotionNotify event with identical position, which is translated
to raw input message with 0x0 relative movement, but does not get translated to normal input message because the cursor didn't move.
* a RawMotion event with some relative movement, which is translated
to the corresponding raw input message with relative movement, and is added to current position, then clamped, and then ignored w.r.t. normal input message because the clamped position is the same as the last.
Currently if the clipping window is disabled, then no RawMotion events are received anyway.
- When somebody tested warframe with my patch before I re-added
mouse-movements, they had issues that were fixed by rebasing mouse-movements on my commit, and warframe does not use raw-input for the mouse.
There could be some subtleties I may be overlooking, I will do some tests. Thanks for mentioning it. -- Rémi Bernon [email protected]
After doing some more investigation, I indeed missed the "low level" mouse messages (WH_MOUSE_LL hook) that can also be used to get mouse movement messages. These are received even if the cursor is blocked by the clipping rectangle, on the contrary to WM_MOUSEMOVE messages which aren't, and they carry the cursor position before clamping it to the clipping rectangle.
This is also used (incorrectly, see note below) in Wine for the dinput implementation to update the mouse positions.
So I guess that means RawMotion events should still send normal input messages.
We can yet get some simplification by using MotionNotify events XOR RawMotion events depending if xinput2 is available, as we will now always be listening to them, but that may be for later.
Note: During my tests I could see that dinput reports motion values that do not follow mouse speed, so implementing it with WH_MOUSE_LL seems wrong. It looks also that dinput and raw input are mutually exclusive, and as soon as dinput mouse is acquired, the application stops receiving WM_INPUT messages, but that may be my sample app that doesn't do it right.
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=54264
Your paranoid android.
=== debian9 (32 bit WoW report) ===
user32: msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000
This patch had to be updated as I didn't account for mouse messages sent from set_cursor_pos.
On Sat, Jun 29, 2019 at 10:26 PM Derek Lesho [email protected] wrote:
Signed-off-by: Derek Lesho [email protected]
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 2085fd3f9f..120de073c8 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -250,7 +250,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 24239916af..0ab5adfead 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;
@@ -1668,6 +1671,9 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons msg_data->rawinput.mouse.data = input->mouse.data;
queue_hardware_message( desktop, msg, 0 );
if (device->flags & RIDEV_NOLEGACY)
return FALSE;
}
for (i = 0; i < ARRAY_SIZE( messages ); i++)
@@ -1793,6 +1799,9 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c msg_data->rawinput.kbd.scan = input->kbd.scan;
queue_hardware_message( desktop, msg, 0 );
if (device->flags & RIDEV_NOLEGACY)
return FALSE;
}
if (!(msg = alloc_hardware_message( input->kbd.info, source, time
))) return 0;
2.21.0
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=54270
Your paranoid android.
=== debian9 (build log) ===
error: corrupt patch at line 83 Task: Patch failed to apply
=== debian9 (build log) ===
error: corrupt patch at line 83 Task: Patch failed to apply