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.
From: Rémi Bernon rbernon@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] );
From: Rémi Bernon rbernon@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 ); }
From: Rémi Bernon rbernon@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;