Patch for dinput keyboard
Arjen Nienhuis
arjen at BleHQ.org
Sun May 19 10:37:45 CDT 2002
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.
-------------- next part --------------
? 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)
More information about the wine-devel
mailing list