dinput: Handle multiple keyboard and mouse devices.

This commit is contained in:
Vitaliy Margolen 2007-07-06 23:36:30 -06:00 committed by Alexandre Julliard
parent 6d6e4f4ea2
commit deb74efc04
5 changed files with 88 additions and 84 deletions

View File

@ -61,6 +61,7 @@ struct IDirectInputDevice2AImpl
DWORD dwCoopLevel; DWORD dwCoopLevel;
HWND win; HWND win;
int acquired; int acquired;
DI_EVENT_PROC event_proc; /* function to receive mouse & keyboard events */
LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */ LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */
int queue_len; /* size of the queue - set in 'SetProperty' */ int queue_len; /* size of the queue - set in 'SetProperty' */

View File

@ -678,50 +678,89 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
* DInput hook thread * DInput hook thread
*/ */
static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam )
{
IDirectInputImpl *dinput;
if (code != HC_ACTION) return CallNextHookEx( 0, code, wparam, lparam );
EnterCriticalSection( &dinput_hook_crit );
LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
{
IDirectInputDevice2AImpl *dev;
EnterCriticalSection( &dinput->crit );
LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDevice2AImpl, entry )
if (dev->acquired && dev->event_proc)
{
TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam);
dev->event_proc( (LPDIRECTINPUTDEVICE8A)dev, wparam, lparam );
}
LeaveCriticalSection( &dinput->crit );
}
LeaveCriticalSection( &dinput_hook_crit );
return CallNextHookEx( 0, code, wparam, lparam );
}
static LRESULT CALLBACK dinput_hook_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) static LRESULT CALLBACK dinput_hook_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
static HHOOK kbd_hook, mouse_hook; static HHOOK kbd_hook, mouse_hook;
BOOL res; UINT kbd_cnt = 0, mice_cnt = 0;
TRACE("got message %x %p %p\n", message, (LPVOID)wParam, (LPVOID)lParam); TRACE("got message %x %p %p\n", message, (LPVOID)wParam, (LPVOID)lParam);
switch (message) switch (message)
{ {
case WM_USER+0x10: case WM_USER+0x10:
if (wParam == WH_KEYBOARD_LL)
{ {
if (lParam) IDirectInputImpl *dinput;
{
if (kbd_hook) return 0;
kbd_hook = SetWindowsHookExW(WH_KEYBOARD_LL, (LPVOID)lParam, DINPUT_instance, 0);
return (LRESULT)kbd_hook;
}
else
{
if (!kbd_hook) return 0;
res = UnhookWindowsHookEx(kbd_hook);
kbd_hook = NULL;
return res;
}
}
else if (wParam == WH_MOUSE_LL)
{
if (lParam)
{
if (mouse_hook) return 0;
mouse_hook = SetWindowsHookExW(WH_MOUSE_LL, (LPVOID)lParam, DINPUT_instance, 0);
return (LRESULT)mouse_hook;
}
else
{
if (!mouse_hook) return 0;
res = UnhookWindowsHookEx(mouse_hook);
mouse_hook = NULL;
return res;
}
}
else if (!wParam && !lParam)
DestroyWindow(hWnd);
if (!wParam && !lParam)
{
DestroyWindow( hWnd );
return 0;
}
EnterCriticalSection( &dinput_hook_crit );
/* Count acquired keyboards and mice*/
LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
{
IDirectInputDevice2AImpl *dev;
EnterCriticalSection( &dinput->crit );
LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDevice2AImpl, entry )
{
if (!dev->acquired) continue;
if (IsEqualGUID( &dev->guid, &GUID_SysKeyboard ) ||
IsEqualGUID( &dev->guid, &DInput_Wine_Keyboard_GUID ))
kbd_cnt++;
else
if (IsEqualGUID( &dev->guid, &GUID_SysMouse ) ||
IsEqualGUID( &dev->guid, &DInput_Wine_Mouse_GUID ))
mice_cnt++;
}
LeaveCriticalSection( &dinput->crit );
}
LeaveCriticalSection( &dinput_hook_crit );
if (kbd_cnt && !kbd_hook)
kbd_hook = SetWindowsHookExW( WH_KEYBOARD_LL, LL_hook_proc, DINPUT_instance, 0 );
else if (!kbd_cnt && kbd_hook)
{
UnhookWindowsHookEx( kbd_hook );
kbd_hook = NULL;
}
if (mice_cnt && !mouse_hook)
mouse_hook = SetWindowsHookExW( WH_MOUSE_LL, LL_hook_proc, DINPUT_instance, 0 );
else if (!mice_cnt && mouse_hook)
{
UnhookWindowsHookEx( mouse_hook );
mouse_hook = NULL;
}
}
return 0; return 0;
case WM_DESTROY: case WM_DESTROY:

View File

@ -58,5 +58,6 @@ extern const struct dinput_device joystick_linuxinput_device;
extern HINSTANCE DINPUT_instance; extern HINSTANCE DINPUT_instance;
extern HHOOK set_dinput_hook(int hook_id, LPVOID proc); extern HHOOK set_dinput_hook(int hook_id, LPVOID proc);
typedef void (*DI_EVENT_PROC)(LPDIRECTINPUTDEVICE8A, WPARAM, LPARAM);
#endif /* __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H */ #endif /* __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H */

View File

@ -50,26 +50,19 @@ struct SysKeyboardImpl
BYTE DInputKeyState[WINE_DINPUT_KEYBOARD_MAX_KEYS]; BYTE DInputKeyState[WINE_DINPUT_KEYBOARD_MAX_KEYS];
}; };
static SysKeyboardImpl* current_lock = NULL; static void KeyboardCallback( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam )
/* Today's acquired device
* FIXME: currently this can be only one.
* Maybe this should be a linked list or st.
* I don't know what the rules are for multiple acquired keyboards,
* but 'DI_LOSTFOCUS' and 'DI_UNACQUIRED' exist for a reason.
*/
static LRESULT CALLBACK KeyboardCallback( int code, WPARAM wparam, LPARAM lparam )
{ {
SysKeyboardImpl *This = (SysKeyboardImpl *)current_lock; SysKeyboardImpl *This = (SysKeyboardImpl *)iface;
int dik_code; int dik_code;
KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam;
BYTE new_diks; BYTE new_diks;
TRACE("(%d,%ld,%ld)\n", code, wparam, lparam); if (wparam != WM_KEYDOWN && wparam != WM_KEYUP &&
wparam != WM_SYSKEYDOWN && wparam != WM_SYSKEYUP)
return;
TRACE("(%p) %ld,%ld\n", iface, wparam, lparam);
/* returns now if not HC_ACTION */
if (code != HC_ACTION) return CallNextHookEx(0, code, wparam, lparam);
dik_code = hook->scanCode & 0xff; dik_code = hook->scanCode & 0xff;
if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80; if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80;
@ -77,7 +70,7 @@ static LRESULT CALLBACK KeyboardCallback( int code, WPARAM wparam, LPARAM lparam
/* returns now if key event already known */ /* returns now if key event already known */
if (new_diks == This->DInputKeyState[dik_code]) if (new_diks == This->DInputKeyState[dik_code])
return CallNextHookEx(0, code, wparam, lparam); return;
This->DInputKeyState[dik_code] = new_diks; This->DInputKeyState[dik_code] = new_diks;
TRACE(" setting %02X to %02X\n", dik_code, This->DInputKeyState[dik_code]); TRACE(" setting %02X to %02X\n", dik_code, This->DInputKeyState[dik_code]);
@ -86,8 +79,6 @@ static LRESULT CALLBACK KeyboardCallback( int code, WPARAM wparam, LPARAM lparam
EnterCriticalSection(&This->base.crit); EnterCriticalSection(&This->base.crit);
queue_event((LPDIRECTINPUTDEVICE8A)This, dik_code, new_diks, hook->time, This->base.dinput->evsequence++); queue_event((LPDIRECTINPUTDEVICE8A)This, dik_code, new_diks, hook->time, This->base.dinput->evsequence++);
LeaveCriticalSection(&This->base.crit); LeaveCriticalSection(&This->base.crit);
return CallNextHookEx(0, code, wparam, lparam);
} }
const GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */ const GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */
@ -189,6 +180,7 @@ static SysKeyboardImpl *alloc_device(REFGUID rguid, const void *kvt, IDirectInpu
newDevice->base.ref = 1; newDevice->base.ref = 1;
memcpy(&newDevice->base.guid, rguid, sizeof(*rguid)); memcpy(&newDevice->base.guid, rguid, sizeof(*rguid));
newDevice->base.dinput = dinput; newDevice->base.dinput = dinput;
newDevice->base.event_proc = KeyboardCallback;
InitializeCriticalSection(&newDevice->base.crit); InitializeCriticalSection(&newDevice->base.crit);
newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysKeyboardImpl*->base.crit"); newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysKeyboardImpl*->base.crit");
@ -306,12 +298,6 @@ static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
if ((res = IDirectInputDevice2AImpl_Acquire(iface)) != DI_OK) return res; if ((res = IDirectInputDevice2AImpl_Acquire(iface)) != DI_OK) return res;
if (current_lock != NULL) {
FIXME("Not more than one keyboard can be acquired at the same time.\n");
SysKeyboardAImpl_Unacquire((LPDIRECTINPUTDEVICE8A)current_lock);
}
current_lock = This;
set_dinput_hook(WH_KEYBOARD_LL, KeyboardCallback); set_dinput_hook(WH_KEYBOARD_LL, KeyboardCallback);
return DI_OK; return DI_OK;
@ -328,12 +314,6 @@ static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
set_dinput_hook(WH_KEYBOARD_LL, NULL); set_dinput_hook(WH_KEYBOARD_LL, NULL);
/* No more locks */
if (current_lock == This)
current_lock = NULL;
else
ERR("this != current_lock\n");
return DI_OK; return DI_OK;
} }

View File

@ -68,8 +68,7 @@ struct SysMouseImpl
DIMOUSESTATE2 m_state; DIMOUSESTATE2 m_state;
}; };
/* FIXME: This is ugly and not thread safe :/ */ static void dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam );
static IDirectInputDevice8A* current_lock = NULL;
const GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */ const GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
0x9e573ed8, 0x7734, 0x11d2, {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} 0x9e573ed8, 0x7734, 0x11d2, {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
@ -174,6 +173,7 @@ static SysMouseImpl *alloc_device(REFGUID rguid, const void *mvt, IDirectInputIm
InitializeCriticalSection(&newDevice->base.crit); InitializeCriticalSection(&newDevice->base.crit);
newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysMouseImpl*->base.crit"); newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysMouseImpl*->base.crit");
newDevice->base.dinput = dinput; newDevice->base.dinput = dinput;
newDevice->base.event_proc = dinput_mouse_hook;
/* Create copy of default data format */ /* Create copy of default data format */
if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIMouse2.dwSize))) goto failed; if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIMouse2.dwSize))) goto failed;
@ -252,15 +252,13 @@ const struct dinput_device mouse_device = {
*/ */
/* low-level mouse hook */ /* low-level mouse hook */
static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam ) static void dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam )
{ {
MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
SysMouseImpl* This = (SysMouseImpl*) current_lock; SysMouseImpl* This = (SysMouseImpl*) iface;
DWORD dwCoop; DWORD dwCoop;
int wdata = 0, inst_id = -1; int wdata = 0, inst_id = -1;
if (code != HC_ACTION) return CallNextHookEx( 0, code, wparam, lparam );
EnterCriticalSection(&This->base.crit); EnterCriticalSection(&This->base.crit);
dwCoop = This->base.dwCoopLevel; dwCoop = This->base.dwCoopLevel;
@ -345,12 +343,6 @@ static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lpara
wdata, hook->time, This->base.dinput->evsequence++); wdata, hook->time, This->base.dinput->evsequence++);
LeaveCriticalSection(&This->base.crit); LeaveCriticalSection(&This->base.crit);
/* Ignore message */
if (dwCoop & DISCL_EXCLUSIVE) return 1;
/* Pass the events down to previous handlers (e.g. win32 input) */
return CallNextHookEx( 0, code, wparam, lparam );
} }
static BOOL dinput_window_check(SysMouseImpl* This) { static BOOL dinput_window_check(SysMouseImpl* This) {
@ -387,9 +379,6 @@ static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
if ((res = IDirectInputDevice2AImpl_Acquire(iface)) != DI_OK) return res; if ((res = IDirectInputDevice2AImpl_Acquire(iface)) != DI_OK) return res;
/* Store (in a global variable) the current lock */
current_lock = (IDirectInputDevice8A*)This;
/* Init the mouse state */ /* Init the mouse state */
GetCursorPos( &point ); GetCursorPos( &point );
if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS) if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS)
@ -448,12 +437,6 @@ static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
if (This->base.dwCoopLevel & DISCL_EXCLUSIVE) if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
ShowCursor(TRUE); /* show cursor */ ShowCursor(TRUE); /* show cursor */
/* No more locks */
if (current_lock == (IDirectInputDevice8A*) This)
current_lock = NULL;
else
ERR("this(%p) != current_lock(%p)\n", This, current_lock);
/* And put the mouse cursor back where it was at acquire time */ /* And put the mouse cursor back where it was at acquire time */
if (This->base.dwCoopLevel & DISCL_EXCLUSIVE) if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
{ {