Patch for dinput keyboard

Ove Kaaven ovehk at ping.uio.no
Sat May 18 18:50:47 CDT 2002


On Sat, 18 May 2002 arjen at 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 at 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,




More information about the wine-devel mailing list