On Sat, 18 May 2002 arjen@blehq.org wrote:
This 'beautiful' patch I wrote for fixing dinput was silently ignored. Can someone comment about it?
The x11drv parts are unnecessary. It's done differently (more Alexandre-style) in WineX. Since there's no particular need to hold this piece back whether or not the code trade Gav wants to do is successful (especially since you're working on it in any case), I may as well use it to help you get this functionality into Wine. Here's the code merged against ReWind, licensed under the X11 license. You may have to merge it again against the current Wine code yourself, since some other DirectInput patches may not have been applied to ReWind. (Of course, change this in other ways as well if you feel like it.)
Log entry from WineX: Ove Kaaven ovek@transgaming.com Implemented buffered keyboard input properly (using a system hook instead of polling).
Index: dlls/dinput/keyboard/main.c =================================================================== RCS file: /cvsroot/rewind/rewind/dlls/dinput/keyboard/main.c,v retrieving revision 1.8 diff -u -r1.8 main.c --- dlls/dinput/keyboard/main.c 18 Oct 2001 21:30:06 -0000 1.8 +++ dlls/dinput/keyboard/main.c 18 May 2002 23:30:29 -0000 @@ -34,10 +34,16 @@ GUID guid;
IDirectInputAImpl *dinput; - - /* SysKeyboardAImpl */ - BYTE keystate[256]; + + /* SysKeyboardAImpl */ + BYTE keystate[256]; + HHOOK hook; + HWND win; + DWORD dwCoopLevel; + LPDIDEVICEOBJECTDATA data_queue; + int queue_head, queue_tail, queue_len; int acquired; + CRITICAL_SECTION crit; };
static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */ @@ -47,6 +53,9 @@ {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41} };
+static IDirectInputDevice2A* current_lock = NULL; + + static BOOL keyboarddev_enum_device(DWORD dwDevType, DWORD dwFlags, LPCDIDEVICEINSTANCEA lpddi) { if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_KEYBOARD)) { @@ -70,6 +79,7 @@ newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardAImpl)); newDevice->ref = 1; ICOM_VTBL(newDevice) = kvt; + InitializeCriticalSection(&(newDevice->crit)); memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); memset(newDevice->keystate,0,256); newDevice->dinput = dinput; @@ -107,6 +117,50 @@
DECL_GLOBAL_CONSTRUCTOR(keyboarddev_register) { dinput_register_device(&keyboarddev); }
+static ULONG WINAPI SysKeyboardAImpl_Release( + LPDIRECTINPUTDEVICE2A iface +) +{ + ICOM_THIS(SysKeyboardAImpl,iface); + + This->ref--; + if (This->ref) + return This->ref; + + /* Free the data queue */ + if (This->data_queue != NULL) + HeapFree(GetProcessHeap(),0,This->data_queue); + + if (This->hook) { + UnhookWindowsHookEx( This->hook ); + } + DeleteCriticalSection(&(This->crit)); + + HeapFree(GetProcessHeap(),0,This); + return 0; +} + +static HRESULT WINAPI SysKeyboardAImpl_SetCooperativeLevel( + LPDIRECTINPUTDEVICE2A iface,HWND hwnd,DWORD dwflags +) +{ + ICOM_THIS(SysKeyboardAImpl,iface); + + TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags); + + if (TRACE_ON(dinput)) + _dump_cooperativelevel_DI(dwflags); + + /* Store the window which asks for the keyboard */ + if (!hwnd) + hwnd = GetDesktopWindow(); + This->win = hwnd; + This->dwCoopLevel = dwflags; + + return 0; +} + + static HRESULT WINAPI SysKeyboardAImpl_SetProperty( LPDIRECTINPUTDEVICE2A iface,REFGUID rguid,LPCDIPROPHEADER ph ) @@ -115,13 +169,19 @@
TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n", - ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow); + ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow); if (!HIWORD(rguid)) { switch ((DWORD)rguid) { case (DWORD) DIPROP_BUFFERSIZE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - - TRACE("(buffersize=%ld)\n",pd->dwData); + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + + TRACE("buffersize = %ld\n",pd->dwData); + + This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0, + pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + This->queue_head = 0; + This->queue_tail = 0; + This->queue_len = pd->dwData; break; } default: @@ -132,28 +192,64 @@ return 0; }
+static LRESULT CALLBACK dinput_keyboard_hook( int code, WPARAM wparam, LPARAM lparam ) +{ + LRESULT ret; + KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; + SysKeyboardAImpl *This = (SysKeyboardAImpl*) current_lock; + DWORD dwCoop; + WORD dik; + + if (code != HC_ACTION) return CallNextHookEx( This->hook, code, wparam, lparam ); + + EnterCriticalSection(&(This->crit)); + dwCoop = This->dwCoopLevel; + + TRACE(" msg %x scan %lx flags %lx\n", + wparam, hook->scanCode, hook->flags ); + + dik = hook->scanCode; + if (hook->flags & LLKHF_EXTENDED) dik |= 0x80; + if (hook->flags & LLKHF_UP) { + if (This->keystate[dik] != 0) { + GEN_EVENT(dik, 0x00, hook->time, This->dinput->evsequence++); + This->keystate[dik] = 0; + } + } + else { + if (This->keystate[dik] == 0) { + GEN_EVENT(dik, 0x80, hook->time, This->dinput->evsequence++); + This->keystate[dik] = 0x80; + } + } + + LeaveCriticalSection(&(This->crit)); + + if (dwCoop & DISCL_NONEXCLUSIVE) + { /* pass the events down to previous handlers (e.g. win32 input) */ + ret = CallNextHookEx( This->hook, code, wparam, lparam ); + } + else ret = 1; /* ignore message */ + return ret; +} + static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState( LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr ) { - DWORD i; + ICOM_THIS(SysKeyboardAImpl,iface); + + if (!This->acquired) + return DIERR_NOTACQUIRED;
- memset( ptr, 0, len ); - if (len != 256) - { - WARN("whoops, got len %ld?\n", len); - return DI_OK; - } - 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; + memset( ptr, 0, len ); + if (len != 256) + { + WARN("whoops, got len %ld?\n", len); + return DI_OK; + } + memcpy(ptr, This->keystate, len); + return DI_OK; }
static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData( @@ -162,34 +258,53 @@ ) { ICOM_THIS(SysKeyboardAImpl,iface); - int i, n; + DWORD len, nqtail; + + EnterCriticalSection(&(This->crit)); + TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
- TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n", - This,dodsize,dod,entries,entries?*entries:0,flags); + len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0) + + (This->queue_head - This->queue_tail); + if (len > *entries) len = *entries; + + if (dod == NULL) { + if (len) + TRACE("Application discarding %ld event(s).\n", len); + + *entries = len; + nqtail = This->queue_tail + len; + while (nqtail >= This->queue_len) nqtail -= This->queue_len; + } else { + if (dodsize < sizeof(DIDEVICEOBJECTDATA)) { + ERR("Wrong structure size !\n"); + LeaveCriticalSection(&(This->crit)); + return DIERR_INVALIDPARAM; + } + + if (len) + TRACE("Application retrieving %ld event(s).\n", len); + + *entries = 0; + nqtail = This->queue_tail; + while (len) { + DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head) + - nqtail; + if (span > len) span = len; + /* Copy the buffered data into the application queue */ + memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize); + /* Advance position */ + nqtail += span; + if (nqtail >= This->queue_len) nqtail -= This->queue_len; + *entries += span; + len -= span; + } + } + if (!(flags & DIGDD_PEEK)) + This->queue_tail = nqtail;
+ LeaveCriticalSection(&(This->crit));
- for (i = n = 0; (i < 0x80) && (n < *entries); i++) - { - WORD state, vkey = MapVirtualKeyA( i, 1 ); - if (!vkey) continue; - state = (GetAsyncKeyState( vkey ) >> 8) & 0x80; - if (state != This->keystate[vkey]) - { - if (dod) - { - /* add an entry */ - dod[n].dwOfs = i; /* scancode */ - dod[n].dwData = state; - dod[n].dwTimeStamp = GetCurrentTime(); /* umm */ - dod[n].dwSequence = This->dinput->evsequence++; - n++; - } - if (!(flags & DIGDD_PEEK)) This->keystate[vkey] = state; - } - } - if (n) TRACE_(dinput)("%d entries\n",n); - *entries = n; - return DI_OK; + return DI_OK; }
static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface) @@ -199,10 +314,27 @@ TRACE("(this=%p)\n",This); if (This->acquired == 0) { - This->acquired = 1; + DWORD i; + + /* Store (in a global variable) the current lock */ + current_lock = (IDirectInputDevice2A*)This; + + /* Install our keyboard hook */ + This->hook = SetWindowsHookExW( WH_KEYBOARD_LL, dinput_keyboard_hook, 0, 0 ); + + /* Read current keyboard state */ + memset(&This->keystate, 0, 256); + for (i = 0; i < 0x100; i++) + { + WORD vkey = MapVirtualKeyA( i, 1 ); /* FIXME: use map mode 3 when implemented */ + if (vkey && (GetAsyncKeyState( vkey ) & 0x8000)) + This->keystate[i] = 0x80; + } + + This->acquired = 1; + return DI_OK; } - - return DI_OK; + return S_FALSE; }
static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface) @@ -211,9 +343,16 @@ TRACE("(this=%p)\n",This);
if (This->acquired == 1) { - This->acquired = 0; + if (This->hook) { + UnhookWindowsHookEx( This->hook ); + This->hook = 0; + } + + current_lock = NULL; + + This->acquired = 0; } else { - ERR("Unacquiring a not-acquired device !!!\n"); + ERR("Unacquiring a not-acquired device !!!\n"); }
return DI_OK; @@ -254,7 +393,7 @@ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE IDirectInputDevice2AImpl_QueryInterface, IDirectInputDevice2AImpl_AddRef, - IDirectInputDevice2AImpl_Release, + SysKeyboardAImpl_Release, SysKeyboardAImpl_GetCapabilities, IDirectInputDevice2AImpl_EnumObjects, IDirectInputDevice2AImpl_GetProperty, @@ -265,7 +404,7 @@ SysKeyboardAImpl_GetDeviceData, IDirectInputDevice2AImpl_SetDataFormat, IDirectInputDevice2AImpl_SetEventNotification, - IDirectInputDevice2AImpl_SetCooperativeLevel, + SysKeyboardAImpl_SetCooperativeLevel, IDirectInputDevice2AImpl_GetObjectInfo, IDirectInputDevice2AImpl_GetDeviceInfo, IDirectInputDevice2AImpl_RunControlPanel,