forked from Mirrors/wine-wine
Fixed keyboard handling.
parent
48ac89b627
commit
c9654a7df8
|
@ -1,4 +1,5 @@
|
||||||
name dinput
|
name dinput
|
||||||
|
init Init
|
||||||
|
|
||||||
@ stdcall DirectInputCreateA(long long ptr ptr) DirectInputCreateA
|
@ stdcall DirectInputCreateA(long long ptr ptr) DirectInputCreateA
|
||||||
@ stub DirectInputCreateW
|
@ stub DirectInputCreateW
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
|
#include "winuser.h"
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "dinput_private.h"
|
#include "dinput_private.h"
|
||||||
|
@ -52,6 +53,21 @@ static ICOM_VTABLE(IDirectInput7A) ddi7avt;
|
||||||
static dinput_device * dinput_devices[MAX_WINE_DINPUT_DEVICES];
|
static dinput_device * dinput_devices[MAX_WINE_DINPUT_DEVICES];
|
||||||
static int nrof_dinput_devices = 0;
|
static int nrof_dinput_devices = 0;
|
||||||
|
|
||||||
|
BOOL WINAPI Init( HINSTANCE inst, DWORD reason, LPVOID reserv)
|
||||||
|
{
|
||||||
|
switch(reason)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
keyboard_hook = SetWindowsHookExW( WH_KEYBOARD_LL, KeyboardCallback, 0, 0 );
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
UnhookWindowsHookEx(keyboard_hook);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* register a direct draw driver. We better not use malloc for we are in
|
/* register a direct draw driver. We better not use malloc for we are in
|
||||||
* the ELF startup initialisation at this point.
|
* the ELF startup initialisation at this point.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -42,4 +42,8 @@ typedef struct dinput_device {
|
||||||
|
|
||||||
extern void dinput_register_device(dinput_device *device) ;
|
extern void dinput_register_device(dinput_device *device) ;
|
||||||
|
|
||||||
|
HHOOK keyboard_hook;
|
||||||
|
|
||||||
|
LRESULT CALLBACK KeyboardCallback( int code, WPARAM wparam, LPARAM lparam );
|
||||||
|
|
||||||
#endif /* __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H */
|
#endif /* __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H */
|
||||||
|
|
|
@ -49,13 +49,83 @@ struct SysKeyboardAImpl
|
||||||
IDirectInputAImpl *dinput;
|
IDirectInputAImpl *dinput;
|
||||||
|
|
||||||
HANDLE hEvent;
|
HANDLE hEvent;
|
||||||
HHOOK hook;
|
|
||||||
/* SysKeyboardAImpl */
|
/* SysKeyboardAImpl */
|
||||||
BYTE keystate[256];
|
|
||||||
int acquired;
|
int acquired;
|
||||||
|
int buffersize; /* set in 'SetProperty' */
|
||||||
|
LPDIDEVICEOBJECTDATA buffer; /* buffer for 'GetDeviceData'.
|
||||||
|
Alloc at 'Acquire', Free at
|
||||||
|
'Unacquire' */
|
||||||
|
int count; /* number of objects in use in
|
||||||
|
'buffer' */
|
||||||
|
int start; /* 'buffer' rotates. This is the
|
||||||
|
first in use (if count > 0) */
|
||||||
|
BOOL overflow; /* return DI_BUFFEROVERFLOW in
|
||||||
|
'GetDeviceData' */
|
||||||
|
CRITICAL_SECTION crit;
|
||||||
};
|
};
|
||||||
|
|
||||||
static SysKeyboardAImpl* current_lock = NULL;
|
SysKeyboardAImpl *current; /* 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 BYTE DInputKeyState[256]; /* array for 'GetDeviceState' */
|
||||||
|
|
||||||
|
HHOOK keyboard_hook;
|
||||||
|
|
||||||
|
LRESULT CALLBACK KeyboardCallback( int code, WPARAM wparam, LPARAM lparam )
|
||||||
|
{
|
||||||
|
if (code == HC_ACTION)
|
||||||
|
{
|
||||||
|
BYTE dik_code;
|
||||||
|
BOOL down;
|
||||||
|
DWORD timestamp;
|
||||||
|
|
||||||
|
{
|
||||||
|
KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam;
|
||||||
|
dik_code = hook->scanCode;
|
||||||
|
if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80;
|
||||||
|
down = !(hook->flags & LLKHF_UP);
|
||||||
|
timestamp = hook->time;
|
||||||
|
}
|
||||||
|
|
||||||
|
DInputKeyState[dik_code] = (down ? 0x80 : 0);
|
||||||
|
|
||||||
|
if (current != NULL)
|
||||||
|
{
|
||||||
|
if (current->hEvent)
|
||||||
|
SetEvent(current->hEvent);
|
||||||
|
|
||||||
|
if (current->buffer != NULL)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
EnterCriticalSection(&(current->crit));
|
||||||
|
|
||||||
|
n = (current->start + current->count) % current->buffersize;
|
||||||
|
|
||||||
|
current->buffer[n].dwOfs = dik_code;
|
||||||
|
current->buffer[n].dwData = down ? 0x80 : 0;
|
||||||
|
current->buffer[n].dwTimeStamp = timestamp;
|
||||||
|
current->buffer[n].dwSequence = current->dinput->evsequence++;
|
||||||
|
|
||||||
|
if (current->count == current->buffersize)
|
||||||
|
{
|
||||||
|
current->start++;
|
||||||
|
current->overflow = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
current->count++;
|
||||||
|
|
||||||
|
LeaveCriticalSection(&(current->crit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallNextHookEx(keyboard_hook, code, wparam, lparam);
|
||||||
|
}
|
||||||
|
|
||||||
static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */
|
static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */
|
||||||
0x0ab8648a,
|
0x0ab8648a,
|
||||||
|
@ -88,7 +158,6 @@ static SysKeyboardAImpl *alloc_device(REFGUID rguid, ICOM_VTABLE(IDirectInputDev
|
||||||
newDevice->ref = 1;
|
newDevice->ref = 1;
|
||||||
ICOM_VTBL(newDevice) = kvt;
|
ICOM_VTBL(newDevice) = kvt;
|
||||||
memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
|
memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
|
||||||
memset(newDevice->keystate,0,256);
|
|
||||||
newDevice->dinput = dinput;
|
newDevice->dinput = dinput;
|
||||||
|
|
||||||
return newDevice;
|
return newDevice;
|
||||||
|
@ -139,6 +208,12 @@ static HRESULT WINAPI SysKeyboardAImpl_SetProperty(
|
||||||
LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
|
LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
|
||||||
|
|
||||||
TRACE("(buffersize=%ld)\n",pd->dwData);
|
TRACE("(buffersize=%ld)\n",pd->dwData);
|
||||||
|
|
||||||
|
if (This->acquired)
|
||||||
|
return DIERR_INVALIDPARAM;
|
||||||
|
|
||||||
|
This->buffersize = pd->dwData;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -153,23 +228,11 @@ static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState(
|
||||||
LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
|
LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
DWORD i;
|
/* Note: device does not need to be acquired */
|
||||||
|
|
||||||
memset( ptr, 0, len );
|
|
||||||
if (len != 256)
|
if (len != 256)
|
||||||
{
|
return DIERR_INVALIDPARAM;
|
||||||
WARN("whoops, got len %ld?\n", len);
|
|
||||||
return DI_OK;
|
memcpy(ptr, DInputKeyState, 256);
|
||||||
}
|
|
||||||
for (i = 0; i < 0x80; i++)
|
|
||||||
{
|
|
||||||
WORD vkey = MapVirtualKeyA( i, 1 );
|
|
||||||
if (vkey && (GetAsyncKeyState( vkey ) & 0x8000))
|
|
||||||
{
|
|
||||||
((LPBYTE)ptr)[i] = 0x80;
|
|
||||||
((LPBYTE)ptr)[i | 0x80] = 0x80;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return DI_OK;
|
return DI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,43 +242,54 @@ static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData(
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ICOM_THIS(SysKeyboardAImpl,iface);
|
ICOM_THIS(SysKeyboardAImpl,iface);
|
||||||
int i, n;
|
int ret = DI_OK, i = 0;
|
||||||
|
|
||||||
TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n",
|
TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n",
|
||||||
This,dodsize,dod,entries,entries?*entries:0,flags);
|
This,dodsize,dod,entries,entries?*entries:0,flags);
|
||||||
|
|
||||||
|
if (This->buffer == NULL)
|
||||||
|
return DIERR_NOTBUFFERED;
|
||||||
|
|
||||||
for (i = n = 0; (i < 0x80) && (n < *entries); i++)
|
if (dodsize < sizeof(*dod))
|
||||||
{
|
return DIERR_INVALIDPARAM;
|
||||||
WORD state, vkey = MapVirtualKeyA( i, 1 );
|
|
||||||
if (!vkey) continue;
|
EnterCriticalSection(&(This->crit));
|
||||||
state = (GetAsyncKeyState( vkey ) >> 8) & 0x80;
|
|
||||||
if (state != This->keystate[vkey])
|
/* Copy item at a time for the case dodsize > sizeof(buffer[n]) */
|
||||||
{
|
while ((i < *entries || *entries == INFINITE) && i < This->count)
|
||||||
if (dod)
|
{
|
||||||
{
|
if (dod != NULL)
|
||||||
/* add an entry */
|
{
|
||||||
dod[n].dwOfs = i; /* scancode */
|
int n = (This->start + i) % This->buffersize;
|
||||||
dod[n].dwData = state;
|
LPDIDEVICEOBJECTDATA pd
|
||||||
dod[n].dwTimeStamp = GetCurrentTime(); /* umm */
|
= (LPDIDEVICEOBJECTDATA)((BYTE *)dod + dodsize * i);
|
||||||
dod[n].dwSequence = This->dinput->evsequence++;
|
pd->dwOfs = This->buffer[n].dwOfs;
|
||||||
n++;
|
pd->dwData = This->buffer[n].dwData;
|
||||||
}
|
pd->dwTimeStamp = This->buffer[n].dwTimeStamp;
|
||||||
if (!(flags & DIGDD_PEEK)) This->keystate[vkey] = state;
|
pd->dwSequence = This->buffer[n].dwSequence;
|
||||||
}
|
}
|
||||||
}
|
i++;
|
||||||
if (n) TRACE_(dinput)("%d entries\n",n);
|
}
|
||||||
*entries = n;
|
|
||||||
return DI_OK;
|
*entries = i;
|
||||||
|
|
||||||
|
if (This->overflow)
|
||||||
|
ret = DI_BUFFEROVERFLOW;
|
||||||
|
|
||||||
|
if (!(flags & DIGDD_PEEK))
|
||||||
|
{
|
||||||
|
/* Empty buffer */
|
||||||
|
This->count -= i;
|
||||||
|
This->start = (This->start + i) % This->buffersize;
|
||||||
|
This->overflow = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&(This->crit));
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static LRESULT CALLBACK dinput_keyboard_hook(int code, WPARAM wparam, LPARAM lparam)
|
static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface);
|
||||||
{
|
|
||||||
SysKeyboardAImpl *This = current_lock;
|
|
||||||
if (This && This->hEvent)
|
|
||||||
SetEvent(This->hEvent);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
|
static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
|
||||||
{
|
{
|
||||||
|
@ -223,11 +297,31 @@ static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
|
||||||
|
|
||||||
TRACE("(this=%p)\n",This);
|
TRACE("(this=%p)\n",This);
|
||||||
|
|
||||||
if (This->acquired == 0) {
|
if (This->acquired)
|
||||||
This->acquired = 1;
|
return S_FALSE;
|
||||||
}
|
|
||||||
|
This->acquired = 1;
|
||||||
This->hook = SetWindowsHookExW(WH_KEYBOARD, dinput_keyboard_hook, 0, 0);
|
|
||||||
|
if (current != NULL)
|
||||||
|
{
|
||||||
|
FIXME("Not more than one keyboard can be acquired at the same time.");
|
||||||
|
SysKeyboardAImpl_Unacquire(iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
current = This;
|
||||||
|
|
||||||
|
if (This->buffersize > 0)
|
||||||
|
{
|
||||||
|
This->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||||
|
This->buffersize * sizeof(*(This->buffer)));
|
||||||
|
This->start = 0;
|
||||||
|
This->count = 0;
|
||||||
|
This->overflow = FALSE;
|
||||||
|
InitializeCriticalSection(&(This->crit));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
This->buffer = NULL;
|
||||||
|
|
||||||
return DI_OK;
|
return DI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,19 +330,26 @@ static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
|
||||||
ICOM_THIS(SysKeyboardAImpl,iface);
|
ICOM_THIS(SysKeyboardAImpl,iface);
|
||||||
TRACE("(this=%p)\n",This);
|
TRACE("(this=%p)\n",This);
|
||||||
|
|
||||||
if (This->acquired == 1) {
|
if (This->acquired == 0)
|
||||||
This->acquired = 0;
|
return DI_NOEFFECT;
|
||||||
UnhookWindowsHookEx( This->hook );
|
|
||||||
} else {
|
if (current == This)
|
||||||
ERR("Unacquiring a not-acquired device !!!\n");
|
current = NULL;
|
||||||
}
|
else
|
||||||
|
ERR("this != current");
|
||||||
|
|
||||||
|
This->acquired = 0;
|
||||||
|
|
||||||
|
if (This->buffersize >= 0)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, This->buffer);
|
||||||
|
This->buffer = NULL;
|
||||||
|
DeleteCriticalSection(&(This->crit));
|
||||||
|
}
|
||||||
|
|
||||||
return DI_OK;
|
return DI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* GetCapabilities : get the device capablitites
|
|
||||||
*/
|
|
||||||
static HRESULT WINAPI SysKeyboardAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2A iface,
|
static HRESULT WINAPI SysKeyboardAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2A iface,
|
||||||
HANDLE hnd) {
|
HANDLE hnd) {
|
||||||
ICOM_THIS(SysKeyboardAImpl,iface);
|
ICOM_THIS(SysKeyboardAImpl,iface);
|
||||||
|
@ -256,10 +357,12 @@ static HRESULT WINAPI SysKeyboardAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2
|
||||||
TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
|
TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
|
||||||
|
|
||||||
This->hEvent = hnd;
|
This->hEvent = hnd;
|
||||||
current_lock = This;
|
|
||||||
return DI_OK;
|
return DI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* GetCapabilities : get the device capablitites
|
||||||
|
*/
|
||||||
static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities(
|
static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities(
|
||||||
LPDIRECTINPUTDEVICE2A iface,
|
LPDIRECTINPUTDEVICE2A iface,
|
||||||
LPDIDEVCAPS lpDIDevCaps)
|
LPDIDEVCAPS lpDIDevCaps)
|
||||||
|
|
Loading…
Reference in New Issue