[PATCH v2 0/3] MR2169: dinput: Use a CBT hook to track foreground window.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54431 -- v2: dinput: Use a WH_CBT hook instead of WH_CALLWNDPROC. dinput: Name input thread message and wparam values. dinput: Split dinput_unacquire_window_devices helper. https://gitlab.winehq.org/wine/wine/-/merge_requests/2169
From: Rémi Bernon <rbernon(a)codeweavers.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54431 --- dlls/dinput/dinput_main.c | 52 +++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 149dd402aa8..6ea6338fd99 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -163,40 +163,50 @@ static void dinput_unacquire_window_devices( HWND window ) LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_device_list, struct dinput_device, entry ) { - if (!window || window == impl->win) - { - TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - } + if (window != impl->win) continue; + TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_mouse_list, struct dinput_device, entry ) { - if (!window || window == impl->win) - { - TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - } + if (window != impl->win) continue; + TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_rawmouse_list, struct dinput_device, entry ) { - if (!window || window == impl->win) - { - TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - } + if (window != impl->win) continue; + TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_keyboard_list, struct dinput_device, entry ) { - if (!window || window == impl->win) - { - TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - } + if (window != impl->win) continue; + TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } LeaveCriticalSection( &dinput_hook_crit ); } +static void dinput_unacquire_devices(void) +{ + struct dinput_device *impl, *next; + + EnterCriticalSection( &dinput_hook_crit ); + + LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_device_list, struct dinput_device, entry ) + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); + LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_mouse_list, struct dinput_device, entry ) + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); + LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_rawmouse_list, struct dinput_device, entry ) + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); + LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_keyboard_list, struct dinput_device, entry ) + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); + + LeaveCriticalSection( &dinput_hook_crit ); +} + static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam ) { CWPSTRUCT *msg = (CWPSTRUCT *)lparam; @@ -390,7 +400,7 @@ static DWORD WINAPI dinput_thread_proc( void *params ) if (state.running) { ERR( "Unexpected termination, ret %#lx\n", ret ); - dinput_unacquire_window_devices( 0 ); + dinput_unacquire_devices(); } while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2169
From: Rémi Bernon <rbernon(a)codeweavers.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54431 --- dlls/dinput/dinput_main.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 6ea6338fd99..0bff483f100 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -49,6 +49,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); #define INPUT_THREAD_MAX_DEVICES 128 +#define INPUT_THREAD_NOTIFY (WM_USER + 0x10) +#define NOTIFY_THREAD_STOP 0 +#define NOTIFY_REFRESH_DEVICES 1 + struct input_thread_state { BOOL running; @@ -101,7 +105,7 @@ void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ) list_add_tail( &acquired_device_list, &impl->entry ); LeaveCriticalSection( &dinput_hook_crit ); - SendMessageW( di_em_win, WM_USER + 0x10, 1, 0 ); + SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); } void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) @@ -112,7 +116,7 @@ void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) list_remove( &impl->entry ); LeaveCriticalSection( &dinput_hook_crit ); - SendMessageW( di_em_win, WM_USER + 0x10, 1, 0 ); + SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); } static void dinput_device_internal_unacquire( IDirectInputDevice8W *iface, DWORD status ) @@ -324,15 +328,19 @@ static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR } } - if (msg == WM_USER + 0x10) + if (msg == INPUT_THREAD_NOTIFY) { TRACE( "Processing hook change notification wparam %#Ix, lparam %#Ix.\n", wparam, lparam ); - if (!wparam) state->running = FALSE; - else + switch (wparam) { + case NOTIFY_THREAD_STOP: + state->running = FALSE; + break; + case NOTIFY_REFRESH_DEVICES: while (state->devices_count--) dinput_device_internal_release( state->devices[state->devices_count] ); input_thread_update_device_list( state ); + break; } return 0; @@ -440,7 +448,7 @@ void input_thread_remove_user(void) { TRACE( "Stopping input thread.\n" ); - SendMessageW( di_em_win, WM_USER + 0x10, 0, 0 ); + SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_THREAD_STOP, 0 ); WaitForSingleObject( dinput_thread, INFINITE ); CloseHandle( dinput_thread ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2169
From: Rémi Bernon <rbernon(a)codeweavers.com> WH_CALLWNDPROC hooks are called on every message, but we only need it for the activation messages. WH_CBT hooks are called for a few events only, which is much lighter, as we need to use a global hook to track windows which belong to any other thread. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54431 --- dlls/dinput/dinput_main.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 0bff483f100..9af8e064dc4 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -52,6 +52,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); #define INPUT_THREAD_NOTIFY (WM_USER + 0x10) #define NOTIFY_THREAD_STOP 0 #define NOTIFY_REFRESH_DEVICES 1 +#define NOTIFY_FOREGROUND_LOST 2 struct input_thread_state { @@ -211,15 +212,14 @@ static void dinput_unacquire_devices(void) LeaveCriticalSection( &dinput_hook_crit ); } -static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam ) +static LRESULT CALLBACK cbt_hook_proc( int code, WPARAM wparam, LPARAM lparam ) { - CWPSTRUCT *msg = (CWPSTRUCT *)lparam; - - if (code != HC_ACTION || (msg->message != WM_KILLFOCUS && - msg->message != WM_ACTIVATEAPP && msg->message != WM_ACTIVATE)) - return CallNextHookEx( 0, code, wparam, lparam ); - - if (msg->hwnd != GetForegroundWindow()) dinput_unacquire_window_devices( msg->hwnd ); + if (code == HCBT_ACTIVATE && di_em_win) + { + CBTACTIVATESTRUCT *data = (CBTACTIVATESTRUCT *)lparam; + SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_FOREGROUND_LOST, + (LPARAM)data->hWndActive ); + } return CallNextHookEx( 0, code, wparam, lparam ); } @@ -265,7 +265,7 @@ static void input_thread_update_device_list( struct input_thread_state *state ) LeaveCriticalSection( &dinput_hook_crit ); if (foreground_count && !state->callwndproc_hook) - state->callwndproc_hook = SetWindowsHookExW( WH_CALLWNDPROC, callwndproc_proc, DINPUT_instance, GetCurrentThreadId() ); + state->callwndproc_hook = SetWindowsHookExW( WH_CBT, cbt_hook_proc, DINPUT_instance, 0 ); else if (!foreground_count && state->callwndproc_hook) { UnhookWindowsHookEx( state->callwndproc_hook ); @@ -341,6 +341,9 @@ static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR while (state->devices_count--) dinput_device_internal_release( state->devices[state->devices_count] ); input_thread_update_device_list( state ); break; + case NOTIFY_FOREGROUND_LOST: + dinput_unacquire_window_devices( (HWND)lparam ); + break; } return 0; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2169
participants (1)
-
Rémi Bernon