Re: joystick GetDeviceData patch

Rob Crittenden <[email protected]>
Newsgroups gmane.comp.emulators.winex.devel
Message-ID <[email protected]>
On Tue, 30 Mar 2004, Ove Kaaven wrote:
> The device.c part of this patch is probably not supposed be included.
> The rest seems OK, except for a couple of things.

Ack, yeah, I got tired of seeing those. Didn't mean to include it.

> 1. I'm wondering if the overflow flag really should be cleared when the
> app is just peeking with DIGDD_PEEK now? You had it differently in your
> previous version of the patch?

Ah, yeah, right. My thinking last night was "Why clear the flag with every
fetch even when it hasn't overflowed?" I wasn't thinking about the PEEK
case. I've fixed it.

> 2. You seem to be removing the joy_polldev() call from GetDeviceData. I
> don't think you should. For Linux 2.2, 2.4, and 2.6, the device is not
> really a polled device, so we do not specify the DIDOI_POLLED flag.
> There's a chance some games may actually honor this flag properly, by
> not calling Poll when it's absent, and these would not work if you
> remove the call.

Hmm. Yeah, I don't know why I took that out. It turns out the BF1942 calls
GetDeviceState() as well and this ends up queuing up any events. My sample
program (from DX9 joystick example) didn't originally call GetDeviceData(),
I just hacked it to call it and display the # of events that were returned but
still report any events using GetDeviceState(). So basically I goofed in
removing it and my 2 test programs didn't catch it. I added a call to
joy_polldev() and removed the state check from my sample and it still works.
 
> By the way, there's a bug in joy_polldev, where the GEN_EVENT macro is
> fed the original dwData from the device driver, instead of the
> range-adjusted value (dwOut) which was written to
> This->buffer+odf->dwOfs. Feel free to fix it. It could even be related
> to your axis problem.

Sure, included.

Another patch is attached.

Thanks for your patience.

rob
joystick.diff (text/plain, 7.3 KB)
Index: dinput/device_private.h
===================================================================
RCS file: /cvsroot/winex/dlls/dinput/device_private.h,v
retrieving revision 1.11
diff -u -r1.11 device_private.h
--- dinput/device_private.h	15 Nov 2003 01:15:01 -0000	1.11
+++ dinput/device_private.h	30 Mar 2004 14:36:10 -0000
@@ -58,6 +58,8 @@
       This->data_queue[This->queue_head].dwSequence = seq;			\
       This->queue_head = nq;							\
     }										\
+    else									\
+      This->overflow = TRUE;							\
   }										\
 }
 
Index: dinput/joystick/main.c
===================================================================
RCS file: /cvsroot/winex/dlls/dinput/joystick/main.c,v
retrieving revision 1.6
diff -u -r1.6 main.c
--- dinput/joystick/main.c	21 Dec 2003 04:13:30 -0000	1.6
+++ dinput/joystick/main.c	30 Mar 2004 14:36:13 -0000
@@ -83,8 +83,10 @@
 	DataFormat*			wine_df;
 	ObjProps*			props;
         HANDLE				hEvent;
+        CRITICAL_SECTION                crit;
         LPDIDEVICEOBJECTDATA 		data_queue;
         int				queue_head, queue_tail, queue_len;
+        BOOL				overflow;
 
 	/* effects */
 	DWORD				dwAutoCenter;
@@ -210,6 +212,10 @@
       newDevice->props[u].lSaturation = 0; /* 0% */
     }
   }
+  newDevice->queue_len = -1; /* unbuffered */
+  newDevice->overflow = FALSE;
+
+  InitializeCriticalSection(&(newDevice->crit));
 
   newDevice->dwGain = 10000;
   newDevice->dwAutoCenter = 0;
@@ -292,6 +298,8 @@
   if (This->data_queue != NULL)
     HeapFree(GetProcessHeap(),0,This->data_queue);
 
+  DeleteCriticalSection(&(This->crit));
+
   /* Free the DataFormat */
   HeapFree(GetProcessHeap(), 0, This->offset_array);
   HeapFree(GetProcessHeap(), 0, This->buffer);
@@ -350,6 +358,7 @@
     HRESULT hr;
     DWORD dwObj;
     DWORD dwData;
+    DWORD dwEvent;
     DWORD dwTimeStamp;
 
     do {
@@ -360,9 +369,10 @@
 	odf = &This->drvdf->rgodf[dwObj];
 
 	/* update state buffer */
-	if (odf->dwType & DIDFT_BUTTON)
+	if (odf->dwType & DIDFT_BUTTON) {
 	    *(BYTE*)(This->buffer+odf->dwOfs) = dwData;
-	else if (odf->dwType & DIDFT_AXIS) {
+	    dwEvent = dwData;
+	} else if (odf->dwType & DIDFT_AXIS) {
 	    /* FIXME: cache these */
 	    LONG pmin = This->props[dwObj].lMin;
 	    LONG pmax = This->props[dwObj].lMax;
@@ -382,12 +392,15 @@
 		dwOut = (pmin + pmax) / 2;
 
 	    *(DWORD*)(This->buffer+odf->dwOfs) = dwOut;
-	} else
+	    dwEvent = dwOut;
+	} else {
 	    *(DWORD*)(This->buffer+odf->dwOfs) = dwData;
+	    dwEvent = dwData;
+	}
 
 	/* generate event */
 	if (gen_event) {
-	    GEN_EVENT(This->offset_array[dwObj],dwData,dwTimeStamp,(This->dinput->evsequence)++);
+	    GEN_EVENT(This->offset_array[dwObj],dwEvent,dwTimeStamp,(This->dinput->evsequence)++);
 	}
     } while (TRUE);
 }
@@ -448,21 +461,62 @@
 					      DWORD flags
 ) {
   ICOM_THIS(JoystickAImpl,iface);
+  DWORD len, count, nqtail;
+  int ret = DI_OK;
 
-  FIXME("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx),STUB!\n",This,dodsize,*entries,flags);
+  TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
 
   if (!This->acquired)
     return DIERR_NOTACQUIRED;
 
+  if (This->queue_len == -1)
+    return DIERR_NOTBUFFERED;
+
+  if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3))
+    return DIERR_INVALIDPARAM;
+
+  /* Check for any events */
   joy_polldev(This, FALSE, TRUE);
-  if (flags & DIGDD_PEEK)
-    FIXME("DIGDD_PEEK\n");
-  *entries = 0;
 
-  if (dod == NULL) {
-  } else {
+  EnterCriticalSection(&(This->crit));
+
+  len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
+      + (This->queue_head - This->queue_tail);
+  if (len > *entries) len = *entries;
+
+  count = 0;
+  nqtail = This->queue_tail;
+  while ((count < *entries || *entries == INFINITE) && count < len) {
+    if (dod != NULL) {
+      LPDIDEVICEOBJECTDATA pd = (LPDIDEVICEOBJECTDATA)((BYTE *)dod + dodsize * count);
+      pd->dwOfs       = This->data_queue[nqtail].dwOfs;
+      pd->dwData      = This->data_queue[nqtail].dwData;
+      pd->dwTimeStamp = This->data_queue[nqtail].dwTimeStamp;
+      pd->dwSequence  = This->data_queue[nqtail].dwSequence;
+    }
+    nqtail++;
+    if (nqtail >= This->queue_len) nqtail -= This->queue_len;
+    count++;
   }
-  return 0;
+
+  if (This->overflow) {
+    ret = DI_BUFFEROVERFLOW;
+    if (!(flags & DIGDD_PEEK)) {
+      This->overflow = FALSE;
+    }
+  }
+
+  if (!(flags & DIGDD_PEEK)) {
+    This->queue_tail = nqtail;
+  }
+
+  TRACE("Application %s %ld event(s). %s\n", *entries == INFINITE ? "flushing" : "retrieving", count, ret == DI_OK ? "" : "BUFFEROVERFLOW");
+
+  *entries = count;
+
+  LeaveCriticalSection(&(This->crit));
+
+  return ret;
 }
 
 int find_object(JoystickAImpl *This, DWORD dwHow, DWORD dwObj)
@@ -519,7 +573,13 @@
     case (DWORD) DIPROP_BUFFERSIZE: {
       LPCDIPROPDWORD	pd = (LPCDIPROPDWORD)ph;
 
-      FIXME("buffersize = %ld\n",pd->dwData);
+      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;
     }
     case (DWORD)DIPROP_RANGE: {
Index: dinput/mouse/main.c
===================================================================
RCS file: /cvsroot/winex/dlls/dinput/mouse/main.c,v
retrieving revision 1.46.2.2
diff -u -r1.46.2.2 main.c
--- dinput/mouse/main.c	2 Mar 2004 17:21:18 -0000	1.46.2.2
+++ dinput/mouse/main.c	30 Mar 2004 14:36:16 -0000
@@ -136,6 +136,7 @@
         DWORD				win_centerX, win_centerY;
         LPDIDEVICEOBJECTDATA 		data_queue;
         int				queue_head, queue_tail, queue_len;
+        BOOL				overflow;
 	/* warping: whether we need to move mouse back to middle once we
 	 * reach window borders (for e.g. shooters, "surface movement" games) */
         WARP_STATUS		        need_warp;
@@ -222,6 +223,9 @@
     newDevice->win = GetDesktopWindow();
     newDevice->dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND;
 
+    newDevice->queue_len = -1; /* unbuffered */
+    newDevice->overflow = FALSE;
+
     return newDevice;
 }
 
@@ -806,6 +810,7 @@
 ) {
   ICOM_THIS(SysMouseAImpl,iface);
   DWORD len, count, nqtail;
+  int ret = DI_OK;
 
   TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
 
@@ -814,6 +819,10 @@
       return DIERR_NOTACQUIRED;
   }
 
+  if (This->queue_len == -1) {
+      return DIERR_NOTBUFFERED;
+  }
+
   EnterCriticalSection(&(This->crit));
 
   len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
@@ -851,8 +860,16 @@
     }
     *entries = count;
   }
-  if (!(flags & DIGDD_PEEK))
+  if (This->overflow) {
+    ret = DI_BUFFEROVERFLOW;
+    if (!(flags & DIGDD_PEEK)) {
+      This->overflow = FALSE;
+    }
+  }
+
+  if (!(flags & DIGDD_PEEK)) {
     This->queue_tail = nqtail;
+  }
 
   LeaveCriticalSection(&(This->crit));
 
@@ -862,7 +879,7 @@
     dinput_window_check(This);
     dinput_mouse_warp(This, FALSE);
   }
-  return 0;
+  return ret;
 }
 
 /******************************************************************************
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.