diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index f6030c5d088..ebe1b49da2f 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -95,6 +95,7 @@ struct dinput_device HWND win; enum device_status status; BOOL use_raw_input; /* use raw input instead of low-level messages */ + HHOOK cbt_hook; /* CBT hook to track foreground changes */ LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */ int queue_len; /* valid size of the queue */ diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 42541b9084a..0d502821966 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -61,7 +61,6 @@ struct input_thread_state UINT devices_count; HHOOK mouse_ll_hook; HHOOK keyboard_ll_hook; - HHOOK callwndproc_hook; RAWINPUTDEVICE rawinput_devices[2]; struct dinput_device *devices[INPUT_THREAD_MAX_DEVICES]; HANDLE events[INPUT_THREAD_MAX_DEVICES]; @@ -112,12 +111,21 @@ void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); } +static void unhook_device_window_foreground_changes( struct dinput_device *device ) +{ + if (!device->cbt_hook) return; + UnhookWindowsHookEx( device->cbt_hook ); + device->cbt_hook = NULL; +} + static void dinput_device_internal_unacquire( IDirectInputDevice8W *iface, DWORD status ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); TRACE( "iface %p.\n", iface ); + unhook_device_window_foreground_changes( impl ); + EnterCriticalSection( &impl->crit ); if (impl->status == STATUS_ACQUIRED) { @@ -198,17 +206,26 @@ static LRESULT CALLBACK cbt_hook_proc( int code, WPARAM wparam, LPARAM lparam ) return CallNextHookEx( 0, code, wparam, lparam ); } +static void hook_device_window_foreground_changes( struct dinput_device *device ) +{ + DWORD tid, pid; + if (!(tid = GetWindowThreadProcessId( device->win, &pid ))) return; + device->cbt_hook = SetWindowsHookExW( WH_CBT, cbt_hook_proc, DINPUT_instance, tid ); +} + static void input_thread_update_device_list( struct input_thread_state *state ) { RAWINPUTDEVICE rawinput_keyboard = {.usUsagePage = HID_USAGE_PAGE_GENERIC, .usUsage = HID_USAGE_GENERIC_KEYBOARD, .dwFlags = RIDEV_REMOVE}; RAWINPUTDEVICE rawinput_mouse = {.usUsagePage = HID_USAGE_PAGE_GENERIC, .usUsage = HID_USAGE_GENERIC_MOUSE, .dwFlags = RIDEV_REMOVE}; - UINT count = 0, keyboard_ll_count = 0, mouse_ll_count = 0, foreground_count = 0; + UINT count = 0, keyboard_ll_count = 0, mouse_ll_count = 0; struct dinput_device *device; EnterCriticalSection( &dinput_hook_crit ); LIST_FOR_EACH_ENTRY( device, &acquired_device_list, struct dinput_device, entry ) { - if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; + unhook_device_window_foreground_changes( device ); + if (device->dwCoopLevel & DISCL_FOREGROUND) hook_device_window_foreground_changes( device ); + if (!device->read_event || !device->vtbl->read) continue; state->events[count] = device->read_event; dinput_device_internal_addref( (state->devices[count] = device) ); @@ -250,14 +267,6 @@ static void input_thread_update_device_list( struct input_thread_state *state ) state->devices_count = count; LeaveCriticalSection( &dinput_hook_crit ); - if (foreground_count && !state->callwndproc_hook) - state->callwndproc_hook = SetWindowsHookExW( WH_CBT, cbt_hook_proc, DINPUT_instance, 0 ); - else if (!foreground_count && state->callwndproc_hook) - { - UnhookWindowsHookEx( state->callwndproc_hook ); - state->callwndproc_hook = NULL; - } - if (keyboard_ll_count && !state->keyboard_ll_hook) state->keyboard_ll_hook = SetWindowsHookExW( WH_KEYBOARD_LL, input_thread_ll_hook_proc, DINPUT_instance, 0 ); else if (!keyboard_ll_count && state->keyboard_ll_hook) @@ -413,7 +422,6 @@ static DWORD WINAPI dinput_thread_proc( void *params ) } while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); - if (state.callwndproc_hook) UnhookWindowsHookEx( state.callwndproc_hook ); if (state.keyboard_ll_hook) UnhookWindowsHookEx( state.keyboard_ll_hook ); if (state.mouse_ll_hook) UnhookWindowsHookEx( state.mouse_ll_hook ); DestroyWindow( di_em_win );