dinput8: Add support for rawinput based devices.

This adds a message window that will be used as the rawinput target
window for WM_INPUT messages.

Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2020-08-10 11:04:15 +02:00 committed by Alexandre Julliard
parent 03ad3ca17a
commit 225be12999
2 changed files with 80 additions and 0 deletions

View file

@ -69,6 +69,9 @@ struct IDirectInputDeviceImpl
HWND win;
int acquired;
BOOL use_raw_input; /* use raw input instead of low-level messages */
RAWINPUTDEVICE raw_device; /* raw device to (un)register */
LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */
int queue_len; /* valid size of the queue */
int queue_head; /* position to write new event into queue */

View file

@ -97,6 +97,9 @@ static const struct dinput_device *dinput_devices[] =
HINSTANCE DINPUT_instance;
static const WCHAR di_em_win_w[] = {'D','I','E','m','W','i','n',0};
static HWND di_em_win;
static BOOL check_hook_thread(void);
static CRITICAL_SECTION dinput_hook_crit;
static struct list direct_input_list = LIST_INIT( direct_input_list );
@ -637,6 +640,45 @@ static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, RE
return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
}
static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
IDirectInputDeviceImpl *dev;
RAWINPUT ri;
UINT size = sizeof(ri);
int rim = GET_RAWINPUT_CODE_WPARAM( wparam );
TRACE( "%p %d %lx %lx\n", hwnd, msg, wparam, lparam );
if (msg == WM_INPUT && (rim == RIM_INPUT || rim == RIM_INPUTSINK))
{
size = GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER) );
if (size == (UINT)-1 || size < sizeof(RAWINPUTHEADER))
WARN( "Unable to read raw input data\n" );
}
return DefWindowProcW( hwnd, msg, wparam, lparam );
}
static void register_di_em_win_class(void)
{
WNDCLASSEXW class;
memset(&class, 0, sizeof(class));
class.cbSize = sizeof(class);
class.lpfnWndProc = di_em_win_wndproc;
class.hInstance = DINPUT_instance;
class.lpszClassName = di_em_win_w;
if (!RegisterClassExW( &class ) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
WARN( "Unable to register message window class\n" );
}
static void unregister_di_em_win_class(void)
{
if (!UnregisterClassW( di_em_win_w, NULL ) && GetLastError() != ERROR_CLASS_DOES_NOT_EXIST)
WARN( "Unable to unregister message window class\n" );
}
static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion)
{
if (!This->initialized)
@ -1668,11 +1710,13 @@ static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam )
EnterCriticalSection( &dinput_hook_crit );
LIST_FOR_EACH_ENTRY( dev, &acquired_mouse_list, IDirectInputDeviceImpl, entry )
{
if (dev->use_raw_input) continue;
TRACE("calling dinput_mouse_hook (%p %lx %lx)\n", dev, wparam, lparam);
skip |= dinput_mouse_hook( &dev->IDirectInputDevice8A_iface, wparam, lparam );
}
LIST_FOR_EACH_ENTRY( dev, &acquired_keyboard_list, IDirectInputDeviceImpl, entry )
{
if (dev->use_raw_input) continue;
TRACE("calling dinput_keyboard_hook (%p %lx %lx)\n", dev, wparam, lparam);
skip |= dinput_keyboard_hook( &dev->IDirectInputDevice8A_iface, wparam, lparam );
}
@ -1728,6 +1772,9 @@ static DWORD WINAPI hook_thread_proc(void *param)
static HHOOK kbd_hook, mouse_hook;
MSG msg;
di_em_win = CreateWindowW( di_em_win_w, di_em_win_w, 0, 0, 0, 0, 0,
HWND_MESSAGE, 0, DINPUT_instance, NULL );
/* Force creation of the message queue */
PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE );
SetEvent(param);
@ -1778,6 +1825,9 @@ static DWORD WINAPI hook_thread_proc(void *param)
DispatchMessageW(&msg);
}
DestroyWindow( di_em_win );
di_em_win = NULL;
FreeLibraryAndExitThread(DINPUT_instance, 0);
}
@ -1860,6 +1910,31 @@ void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface, BOOL acquired)
hook_thread_event = NULL;
}
if (dev->use_raw_input)
{
if (acquired)
{
dev->raw_device.dwFlags = 0;
if (dev->dwCoopLevel & DISCL_BACKGROUND)
dev->raw_device.dwFlags |= RIDEV_INPUTSINK;
if (dev->dwCoopLevel & DISCL_EXCLUSIVE)
dev->raw_device.dwFlags |= RIDEV_NOLEGACY;
if ((dev->dwCoopLevel & DISCL_EXCLUSIVE) && dev->raw_device.usUsage == 2)
dev->raw_device.dwFlags |= RIDEV_CAPTUREMOUSE;
if ((dev->dwCoopLevel & DISCL_EXCLUSIVE) && dev->raw_device.usUsage == 6)
dev->raw_device.dwFlags |= RIDEV_NOHOTKEYS;
dev->raw_device.hwndTarget = di_em_win;
}
else
{
dev->raw_device.dwFlags = RIDEV_REMOVE;
dev->raw_device.hwndTarget = NULL;
}
if (!RegisterRawInputDevices( &dev->raw_device, 1, sizeof(RAWINPUTDEVICE) ))
WARN( "Unable to (un)register raw device %x:%x\n", dev->raw_device.usUsagePage, dev->raw_device.usUsage );
}
if (acquired)
hook_change_finished_event = CreateEventW( NULL, FALSE, FALSE, NULL );
PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, (LPARAM)hook_change_finished_event );
@ -1894,9 +1969,11 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved)
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(inst);
DINPUT_instance = inst;
register_di_em_win_class();
break;
case DLL_PROCESS_DETACH:
if (reserved) break;
unregister_di_em_win_class();
DeleteCriticalSection(&dinput_hook_crit);
break;
}