Ove Kaaven wrote:
The SetProperty code was just copied from mouse/main.c, so if there's a bug in it, it's there too.
I can fix that later.
DI_OK?
Right. dinput.h defines it as:
#define DI_OK S_OK
so it's the canonical return value from DirectInput methods.
DI_NOTOK whould be better.
*entries = 0;
nqtail = This->queue_tail;
while (len) {
DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head)
If dodsize > 16 then span = 1, but I don't really get the algorithm.
This is also copied from mouse/main.c and works there. The algorithm is simply about determining how much can be copied with a single memcpy, taking in account buffer wraparound and stuff. Here, it determines whether it can copy all the way to the queue head immediately, or stop at the end of the buffer first, before wrapping around to the beginning of it.
It is not possible to use memcopy when dodsize != sizeof(DeviceObjectData).
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 does not work (see earlier mails). but it isn't needed when keystate is global.
It works in WineX since map mode 3 is actually implemented there. I may be able to submit the patch that implements it if you want, it's not a very big patch.
Is map mode mode 3 not dependant on the NumLock state then? DInput isn't. But on the other hand, it only mathers when someone acquires the device while a key is pressed.
Well here is my new patch. I only used the Hook idea and the critical sections. It is better now, and shorter.
? paard Index: dlls/dinput/dinput.spec =================================================================== RCS file: /home/wine/wine/dlls/dinput/dinput.spec,v retrieving revision 1.8 diff -u -r1.8 dinput.spec --- dlls/dinput/dinput.spec 14 May 2002 20:54:59 -0000 1.8 +++ dlls/dinput/dinput.spec 19 May 2002 13:01:43 -0000 @@ -1,4 +1,5 @@ name dinput +init Init
@ stdcall DirectInputCreateA(long long ptr ptr) DirectInputCreateA @ stub DirectInputCreateW Index: dlls/dinput/dinput_main.c =================================================================== RCS file: /home/wine/wine/dlls/dinput/dinput_main.c,v retrieving revision 1.25 diff -u -r1.25 dinput_main.c --- dlls/dinput/dinput_main.c 9 Mar 2002 23:29:36 -0000 1.25 +++ dlls/dinput/dinput_main.c 19 May 2002 13:01:43 -0000 @@ -38,6 +38,7 @@
#include "wine/debug.h" #include "winbase.h" +#include "winuser.h" #include "winerror.h" #include "windef.h" #include "dinput_private.h" @@ -51,6 +52,21 @@ #define MAX_WINE_DINPUT_DEVICES 4 static dinput_device * dinput_devices[MAX_WINE_DINPUT_DEVICES]; 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 * the ELF startup initialisation at this point. Index: dlls/dinput/dinput_private.h =================================================================== RCS file: /home/wine/wine/dlls/dinput/dinput_private.h,v retrieving revision 1.3 diff -u -r1.3 dinput_private.h --- dlls/dinput/dinput_private.h 9 Mar 2002 23:29:36 -0000 1.3 +++ dlls/dinput/dinput_private.h 19 May 2002 13:01:44 -0000 @@ -42,4 +42,8 @@
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 */ Index: dlls/dinput/keyboard/main.c =================================================================== RCS file: /home/wine/wine/dlls/dinput/keyboard/main.c,v retrieving revision 1.10 diff -u -r1.10 main.c --- dlls/dinput/keyboard/main.c 7 May 2002 01:49:19 -0000 1.10 +++ dlls/dinput/keyboard/main.c 19 May 2002 13:01:44 -0000 @@ -49,13 +49,83 @@ IDirectInputAImpl *dinput; HANDLE hEvent; - HHOOK hook; /* SysKeyboardAImpl */ - BYTE keystate[256]; 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 */ 0x0ab8648a, @@ -88,7 +158,6 @@ newDevice->ref = 1; ICOM_VTBL(newDevice) = kvt; memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); - memset(newDevice->keystate,0,256); newDevice->dinput = dinput;
return newDevice; @@ -139,6 +208,12 @@ LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
TRACE("(buffersize=%ld)\n",pd->dwData); + + if (This->acquired) + return DIERR_INVALIDPARAM; + + This->buffersize = pd->dwData; + break; } default: @@ -153,23 +228,11 @@ LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr ) { - DWORD i; - - memset( ptr, 0, len ); + /* Note: device does not need to be acquired */ 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 DIERR_INVALIDPARAM; + + memcpy(ptr, DInputKeyState, 256); return DI_OK; }
@@ -179,55 +242,86 @@ ) { ICOM_THIS(SysKeyboardAImpl,iface); - int i, n; + int ret = DI_OK, i = 0;
TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n", This,dodsize,dod,entries,entries?*entries:0,flags);
+ if (This->buffer == NULL) + return DIERR_NOTBUFFERED;
- 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; -} + if (dodsize < sizeof(*dod)) + return DIERR_INVALIDPARAM;
-static LRESULT CALLBACK dinput_keyboard_hook(int code, WPARAM wparam, LPARAM lparam) -{ - SysKeyboardAImpl *This = current_lock; - if (This && This->hEvent) - SetEvent(This->hEvent); - return 1; + EnterCriticalSection(&(This->crit)); + + /* Copy item at a time for the case dodsize > sizeof(buffer[n]) */ + while ((i < *entries || *entries == INFINITE) && i < This->count) + { + if (dod != NULL) + { + int n = (This->start + i) % This->buffersize; + LPDIDEVICEOBJECTDATA pd + = (LPDIDEVICEOBJECTDATA)((BYTE *)dod + dodsize * i); + pd->dwOfs = This->buffer[n].dwOfs; + pd->dwData = This->buffer[n].dwData; + pd->dwTimeStamp = This->buffer[n].dwTimeStamp; + pd->dwSequence = This->buffer[n].dwSequence; + } + i++; + } + + *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 HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface); + static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface) { ICOM_THIS(SysKeyboardAImpl,iface); TRACE("(this=%p)\n",This); - if (This->acquired == 0) { - This->acquired = 1; - } - - This->hook = SetWindowsHookExW(WH_KEYBOARD, dinput_keyboard_hook, 0, 0); + if (This->acquired) + return S_FALSE; + + This->acquired = 1; + + 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; }
@@ -236,19 +330,26 @@ ICOM_THIS(SysKeyboardAImpl,iface); TRACE("(this=%p)\n",This);
- if (This->acquired == 1) { - This->acquired = 0; - UnhookWindowsHookEx( This->hook ); - } else { - ERR("Unacquiring a not-acquired device !!!\n"); - } + if (This->acquired == 0) + return DI_NOEFFECT; + + if (current == This) + 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; }
-/****************************************************************************** - * GetCapabilities : get the device capablitites - */ static HRESULT WINAPI SysKeyboardAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2A iface, HANDLE hnd) { ICOM_THIS(SysKeyboardAImpl,iface); @@ -256,10 +357,12 @@ TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
This->hEvent = hnd; - current_lock = This; return DI_OK; }
+/****************************************************************************** + * GetCapabilities : get the device capablitites + */ static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities( LPDIRECTINPUTDEVICE2A iface, LPDIDEVCAPS lpDIDevCaps)