dinput: Handle multiple keyboard and mouse devices.
This commit is contained in:
parent
6d6e4f4ea2
commit
deb74efc04
|
@ -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' */
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -50,25 +50,18 @@ 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;
|
||||||
|
|
||||||
/* returns now if not HC_ACTION */
|
TRACE("(%p) %ld,%ld\n", iface, wparam, lparam);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue