From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/win32u/message.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 5a5c26d9947..39fb74a5e11 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2528,6 +2528,9 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H } }
+ if (msg->message == WM_MOUSEWHEEL) + msg->hwnd = info.hwndFocus; + if (!msg->hwnd || !is_current_thread_window( msg->hwnd )) { accept_hardware_message( hw_id );
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- server/queue.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/server/queue.c b/server/queue.c index 3e19d579eec..682898a2c49 100644 --- a/server/queue.c +++ b/server/queue.c @@ -799,6 +799,40 @@ static inline unsigned int get_unique_id(void) return id; }
+/* try to merge a WM_MOUSEWHEEL message with the last in the list; return 1 if successful */ +static int merge_mousewheel( struct thread_input *input, const struct message *msg ) +{ + struct message *prev; + struct list *ptr; + + for (ptr = list_tail( &input->msg_list ); ptr; ptr = list_prev( &input->msg_list, ptr )) + { + prev = LIST_ENTRY( ptr, struct message, entry ); + if (prev->msg != WM_INPUT) break; + } + if (!ptr) return 0; + if (prev->result) return 0; + if (prev->win && msg->win && prev->win != msg->win) return 0; + if (prev->msg != msg->msg) return 0; + if (prev->type != msg->type) return 0; + if (prev->x != msg->x || prev->y != msg->y) return 0; + /* now we can merge it */ + prev->wparam = msg->wparam; + prev->lparam = msg->lparam; + prev->x = msg->x; + prev->y = msg->y; + prev->time = msg->time; + if (msg->type == MSG_HARDWARE && prev->data && msg->data) + { + struct hardware_msg_data *prev_data = prev->data; + struct hardware_msg_data *msg_data = msg->data; + prev_data->info = msg_data->info; + } + list_remove( ptr ); + list_add_tail( &input->msg_list, ptr ); + return 1; +} + /* try to merge a WM_MOUSEMOVE message with the last in the list; return 1 if successful */ static int merge_mousemove( struct thread_input *input, const struct message *msg ) { @@ -861,6 +895,7 @@ static int merge_unique_message( struct thread_input *input, unsigned int messag /* try to merge a message with the messages in the list; return 1 if successful */ static int merge_message( struct thread_input *input, const struct message *msg ) { + if (msg->msg == WM_MOUSEWHEEL) return merge_mousewheel( input, msg ); if (msg->msg == WM_MOUSEMOVE) return merge_mousemove( input, msg ); if (msg->msg == WM_WINE_CLIPCURSOR) return merge_unique_message( input, WM_WINE_CLIPCURSOR, msg ); if (msg->msg == WM_WINE_SETCURSOR) return merge_unique_message( input, WM_WINE_SETCURSOR, msg );
Anton Baskanov (@baskanov) commented about dlls/win32u/message.c:
} }
- if (msg->message == WM_MOUSEWHEEL)
msg->hwnd = info.hwndFocus;
What's the point? Even native doesn't do this anymore starting with Windows 10.
On Mon Feb 10 09:24:12 2025 +0000, Anton Baskanov wrote:
What's the point? Even native doesn't do this anymore starting with Windows 10.
Where did you get that information from? According to my tests with Spy++ WM_MOUSEWHEEL messages are always sent to a focus windows. MSDN clearly states that WM_MOUSEWHEEL should be sent to a focus window. An application that I have here depends on this behaviour.
It would probably need some tests, especially wrt capture window behavior as I think you're overriding it.
Rémi Bernon (@rbernon) commented about server/queue.c:
- struct message *prev;
- struct list *ptr;
- for (ptr = list_tail( &input->msg_list ); ptr; ptr = list_prev( &input->msg_list, ptr ))
- {
prev = LIST_ENTRY( ptr, struct message, entry );
if (prev->msg != WM_INPUT) break;
- }
- if (!ptr) return 0;
- if (prev->result) return 0;
- if (prev->win && msg->win && prev->win != msg->win) return 0;
- if (prev->msg != msg->msg) return 0;
- if (prev->type != msg->type) return 0;
- if (prev->x != msg->x || prev->y != msg->y) return 0;
- /* now we can merge it */
- prev->wparam = msg->wparam;
Merging the messages don't seem right, they contain relative wheel position so this will effectively drop some movements?
On Mon Feb 10 09:59:23 2025 +0000, Rémi Bernon wrote:
Merging the messages don't seem right, they contain relative wheel position so this will effectively drop some movements?
This seems to be a valid concern, however: the application that I have here on WM_MOUSEWHEEL scrolls and repaints huge image using gdiplus APIs, this takes quite a bit of time even under Windows, and according to my testing intensive rolling of the mouse wheel doesn't lead to jumps in the image scrolls, an observed behaviour is that image gets scrolled smoothly without jumps, and doesn't keep scrolling once I stop rolling the mouse wheel.
On Mon Feb 10 10:24:33 2025 +0000, Rémi Bernon wrote:
It would probably need some tests, especially wrt capture window behavior as I think you're overriding it.
I don't immediately have an idea how to test WM_MOUSEWHEEL, all the investigations I've done were made using Spy++.
On Mon Feb 10 09:30:03 2025 +0000, Dmitry Timoshkov wrote:
Where did you get that information from? According to my tests with Spy++ WM_MOUSEWHEEL messages are always sent to a focus windows. MSDN clearly states that WM_MOUSEWHEEL should be sent to a focus window. An application that I have here depends on this behaviour.
In Windows 11 there is an option in **Settings -> Bluetooth & devices -> Mouse** called **Scroll inactive windows when hovering over them**, which IIRC is enabled by default. Windows 10 has something similar. With it enabled you can e.g. change the selected item in an unfocused combo box by hovering over it and scrolling. It is also mentioned here: https://devblogs.microsoft.com/oldnewthing/20160420-00/?p=93325
On Tue Feb 11 03:02:57 2025 +0000, Anton Baskanov wrote:
In Windows 11 there is an option in **Settings -> Bluetooth & devices -> Mouse** called **Scroll inactive windows when hovering over them**, which IIRC is enabled by default. Windows 10 has something similar. With it enabled you can e.g. change the selected item in an unfocused combo box by hovering over it and scrolling. It is also mentioned here: https://devblogs.microsoft.com/oldnewthing/20160420-00/?p=93325
That doesn't seem to confirm your statement.
On Tue Feb 11 07:18:14 2025 +0000, Dmitry Timoshkov wrote:
That doesn't seem to confirm your statement.
Here is a simple test app: [combo.zip](/uploads/55de678d93bde781c53fb5cece33509c/combo.zip)
On Windows 11 it behaves like this:

On Wine without your patch it does the same:

However, with your patch applied it behaves differently:
