dinput keyboard

Arjen Nienhuis arjen at BleHQ.org
Thu May 9 00:55:35 CDT 2002


I made this patch for the keyboard part of dinput.

It fixes two games. One game uses GetDeviceData, and the other uses 
GetDeviceState. Are there any games that do work?

It might need some thread safety, but I don't know when the x11 events 
occur.

All comments are welcome.
-------------- next part --------------
? pinput.diff
? dinput.diff
Index: dlls/dinput/dinput.spec
===================================================================
RCS file: /home/wine/wine/dlls/dinput/dinput.spec,v
retrieving revision 1.7
diff -u -r1.7 dinput.spec
--- dlls/dinput/dinput.spec	9 May 2002 00:05:49 -0000	1.7
+++ dlls/dinput/dinput.spec	9 May 2002 03:41:26 -0000
@@ -1,5 +1,6 @@
 name dinput
 type win32
+init Init
 
 debug_channels (dinput)
 
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	9 May 2002 03:41:27 -0000
@@ -52,6 +52,22 @@
 static dinput_device * dinput_devices[MAX_WINE_DINPUT_DEVICES];
 static int nrof_dinput_devices = 0;
 
+BOOL WINAPI Init( HINSTANCE inst, DWORD reason, LPVOID reserv)
+{
+    BOOL ret = TRUE;
+    switch(reason)
+    {
+      case DLL_PROCESS_ATTACH:
+        {
+          UINT (*pInitDInput)(UINT (*callback)(BYTE dik_code, BOOL down, DWORD timestamp));
+          pInitDInput = (void*)GetProcAddress(LoadLibraryA("x11drv"), "InitDInput");
+          pInitDInput(&DInputCallBack);
+          break;
+        }
+    }
+    return ret;
+}
+
 /* 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	9 May 2002 03:41:27 -0000
@@ -41,5 +41,6 @@
 } dinput_device;
 
 extern void dinput_register_device(dinput_device *device) ;
+extern UINT DInputCallBack(BYTE dik_code, BOOL down, DWORD timestamp);
 
 #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	9 May 2002 03:41:28 -0000
@@ -49,14 +49,15 @@
 	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' */
+        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' */
 };
 
-static SysKeyboardAImpl* current_lock = NULL;
-
 static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */
   0x0ab8648a,
   0x7735,
@@ -88,12 +89,59 @@
     newDevice->ref = 1;
     ICOM_VTBL(newDevice) = kvt;
     memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
-    memset(newDevice->keystate,0,256);
     newDevice->dinput = dinput;
 
     return newDevice;
 }
 
+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' */
+
+/**********************************************
+               DInputCallBack
+Called from x11drv
+FIXME:
+ 1. This should be thread safe, I guess.
+ 2. <quote author="unknown">Callbacks are ugly.</quote>
+**********************************************/
+UINT DInputCallBack(BYTE dik_code, BOOL down, DWORD timestamp)
+{
+  /* x11drv sends repeats, so I filter them here. */
+  if (DInputKeyState[dik_code] && down) return 0;
+
+  DInputKeyState[dik_code] = (down ? 0x80 : 0);
+
+  if (current != NULL)
+    {
+      if (current->hEvent)
+        SetEvent(current->hEvent);
+
+      if (current->buffersize >= 0)
+        {
+          int 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++;
+        }
+    }
+  return 0;
+}
 
 static HRESULT keyboarddev_create_device(IDirectInputAImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
 {
@@ -139,6 +187,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 +207,9 @@
 	LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
 )
 {
-    DWORD i;
-
-    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;
-        }
-    }
+    /* Note: device does not need to be acquired */
+    if (len != 256) return DIERR_INVALIDPARAM;
+    memcpy(ptr, DInputKeyState, 256);
     return DI_OK;
 }
 
@@ -179,42 +219,46 @@
 )
 {
 	ICOM_THIS(SysKeyboardAImpl,iface);
-	int i, n;
+	int i = 0;
 
 	TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n",
 	      This,dodsize,dod,entries,entries?*entries:0,flags);
 
+        if (dodsize < sizeof(*dod))
+          return DIERR_INVALIDPARAM;
 
-        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;
-}
+        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 (!(flags & DIGDD_PEEK))
+          {
+            This->count -= i;
+            This->start = (This->start + i) % This->buffersize;
+          }
+
+        if (This->overflow)
+          {
+            if (!(flags & DIGDD_PEEK))
+              This->overflow = FALSE;
 
-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;
+            return DI_BUFFEROVERFLOW;
+          }
+
+        return DI_OK;
 }
 
 static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
@@ -223,11 +267,23 @@
 	
 	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;
+        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;
+          }
+        else
+          This->buffer = NULL;
+
 	return DI_OK;
 }
 
@@ -236,12 +292,16 @@
 	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;
+
+        if (This->buffersize >= 0)
+          {
+            HeapFree(GetProcessHeap(), 0, This->buffer);
+            This->buffer = NULL;
+          }
 
 	return DI_OK;
 }
@@ -256,7 +316,6 @@
   TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
 
   This->hEvent = hnd;
-  current_lock = This;
   return DI_OK;
 }
 
Index: dlls/x11drv/keyboard.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/keyboard.c,v
retrieving revision 1.1
diff -u -r1.1 keyboard.c
--- dlls/x11drv/keyboard.c	30 Apr 2002 21:16:39 -0000	1.1
+++ dlls/x11drv/keyboard.c	9 May 2002 03:41:36 -0000
@@ -54,6 +54,7 @@
 WORD keyc2vkey[256], keyc2scan[256];
 
 static LPBYTE pKeyStateTable;
+static UINT (*pDInputCallBack) (BYTE dik_code, BOOL down, DWORD timestamp) = NULL;
 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
 #ifdef HAVE_XKB
@@ -863,6 +864,14 @@
 
     DWORD event_time = event->time - X11DRV_server_startticks;
 
+    if (pDInputCallBack != NULL)
+      {
+        WORD scan = keyc2scan[event->keycode];
+        BYTE dik_code = (scan > 0xFF) ? scan - 0x80 : scan;
+        BOOL down = event->type == KeyPress;
+        pDInputCallBack(dik_code, down, event_time);
+      }
+
     /* this allows support for dead keys */
     if ((event->keycode >> 8) == 0x10)
 	event->keycode=(event->keycode & 0xff);
@@ -1050,6 +1059,14 @@
   }
 
   TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
+}
+
+/**********************************************************************
+ *              InitDInput (X11DRV.@)
+ */
+void X11DRV_InitDInput(UINT (*callback)(BYTE dik_code, BOOL down, DWORD timestamp))
+{
+  pDInputCallBack = callback;
 }
 
 /**********************************************************************
Index: dlls/x11drv/x11drv.spec
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/x11drv.spec,v
retrieving revision 1.33
diff -u -r1.33 x11drv.spec
--- dlls/x11drv/x11drv.spec	9 May 2002 00:05:54 -0000	1.33
+++ dlls/x11drv/x11drv.spec	9 May 2002 03:41:36 -0000
@@ -97,3 +97,7 @@
 @ cdecl RegisterClipboardFormat(str) X11DRV_RegisterClipboardFormat
 @ cdecl IsSelectionOwner() X11DRV_IsSelectionOwner
 @ cdecl ResetSelectionOwner(ptr long) X11DRV_ResetSelectionOwner
+
+# DINPUT driver
+
+@ cdecl InitDInput(ptr) X11DRV_InitDInput


More information about the wine-patches mailing list