dinput: Handle multiple keyboard and mouse devices.
This commit is contained in:
parent
6d6e4f4ea2
commit
deb74efc04
|
@ -61,6 +61,7 @@ struct IDirectInputDevice2AImpl
|
|||
DWORD dwCoopLevel;
|
||||
HWND win;
|
||||
int acquired;
|
||||
DI_EVENT_PROC event_proc; /* function to receive mouse & keyboard events */
|
||||
|
||||
LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */
|
||||
int queue_len; /* size of the queue - set in 'SetProperty' */
|
||||
|
|
|
@ -678,50 +678,89 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
|
|||
* 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 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);
|
||||
switch (message)
|
||||
{
|
||||
case WM_USER+0x10:
|
||||
if (wParam == WH_KEYBOARD_LL)
|
||||
{
|
||||
if (lParam)
|
||||
{
|
||||
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);
|
||||
IDirectInputImpl *dinput;
|
||||
|
||||
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;
|
||||
|
||||
case WM_DESTROY:
|
||||
|
|
|
@ -58,5 +58,6 @@ extern const struct dinput_device joystick_linuxinput_device;
|
|||
extern HINSTANCE DINPUT_instance;
|
||||
|
||||
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 */
|
||||
|
|
|
@ -50,25 +50,18 @@ struct SysKeyboardImpl
|
|||
BYTE DInputKeyState[WINE_DINPUT_KEYBOARD_MAX_KEYS];
|
||||
};
|
||||
|
||||
static SysKeyboardImpl* current_lock = NULL;
|
||||
/* 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 )
|
||||
static void KeyboardCallback( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam )
|
||||
{
|
||||
SysKeyboardImpl *This = (SysKeyboardImpl *)current_lock;
|
||||
SysKeyboardImpl *This = (SysKeyboardImpl *)iface;
|
||||
int dik_code;
|
||||
KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam;
|
||||
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;
|
||||
|
||||
/* returns now if not HC_ACTION */
|
||||
if (code != HC_ACTION) return CallNextHookEx(0, code, wparam, lparam);
|
||||
TRACE("(%p) %ld,%ld\n", iface, wparam, lparam);
|
||||
|
||||
dik_code = hook->scanCode & 0xff;
|
||||
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 */
|
||||
if (new_diks == This->DInputKeyState[dik_code])
|
||||
return CallNextHookEx(0, code, wparam, lparam);
|
||||
return;
|
||||
|
||||
This->DInputKeyState[dik_code] = new_diks;
|
||||
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);
|
||||
queue_event((LPDIRECTINPUTDEVICE8A)This, dik_code, new_diks, hook->time, This->base.dinput->evsequence++);
|
||||
LeaveCriticalSection(&This->base.crit);
|
||||
|
||||
return CallNextHookEx(0, code, wparam, lparam);
|
||||
}
|
||||
|
||||
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;
|
||||
memcpy(&newDevice->base.guid, rguid, sizeof(*rguid));
|
||||
newDevice->base.dinput = dinput;
|
||||
newDevice->base.event_proc = KeyboardCallback;
|
||||
InitializeCriticalSection(&newDevice->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 (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);
|
||||
|
||||
return DI_OK;
|
||||
|
@ -328,12 +314,6 @@ static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,8 +68,7 @@ struct SysMouseImpl
|
|||
DIMOUSESTATE2 m_state;
|
||||
};
|
||||
|
||||
/* FIXME: This is ugly and not thread safe :/ */
|
||||
static IDirectInputDevice8A* current_lock = NULL;
|
||||
static void dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam );
|
||||
|
||||
const GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
|
||||
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);
|
||||
newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysMouseImpl*->base.crit");
|
||||
newDevice->base.dinput = dinput;
|
||||
newDevice->base.event_proc = dinput_mouse_hook;
|
||||
|
||||
/* Create copy of default data format */
|
||||
if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIMouse2.dwSize))) goto failed;
|
||||
|
@ -252,15 +252,13 @@ const struct dinput_device mouse_device = {
|
|||
*/
|
||||
|
||||
/* 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;
|
||||
SysMouseImpl* This = (SysMouseImpl*) current_lock;
|
||||
SysMouseImpl* This = (SysMouseImpl*) iface;
|
||||
DWORD dwCoop;
|
||||
int wdata = 0, inst_id = -1;
|
||||
|
||||
if (code != HC_ACTION) return CallNextHookEx( 0, code, wparam, lparam );
|
||||
|
||||
EnterCriticalSection(&This->base.crit);
|
||||
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++);
|
||||
|
||||
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) {
|
||||
|
@ -387,9 +379,6 @@ static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
|
|||
|
||||
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 */
|
||||
GetCursorPos( &point );
|
||||
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)
|
||||
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 */
|
||||
if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue