[dinput][joystick_linuxinput] make axes work, that are "not in a row"

Christoph Frick frick at sc-networks.de
Thu Jan 11 03:56:36 CST 2007


hiho

with Vitaliy's patches i tried my games yesterday and everything seemed
ok (RBR works again). but my clutch on the wheel did not work and also
some cog on the flight-stick.

the problem was, that the axes got assigned their id just in the order
they came. this did not work if there are "gaps" between them. e.g. my
wheel has: ABS_X, ABS_Y, ABS_Z, ABS_RZ.

so what this patch does in general is fix this by the following steps:

- move the "wine" relevant stuff back in from the joydev into the impl
  (button, have(min|max))
- fix the used offsets to represent the actual offsets for the first
  POV in the c_dfDIJoystick2 and the first button there
- remember - like for the buttons - where we put a axis (idx) (the same
  applies here also for a pov - but it dont know any device that has
  more than one pov - and if if it would have gaps between them, i
  doubt)
- get rid of lxinput_to_user_index - it was added as an convinience
  method to be sure to wrap the defines from linux/input.h to be sure
  not to introduce problems when they change; but it was used only axes
  anyhow so i dropped it

with this patch applied on top of the ten from Vitaliy i tested the
folling games with wheel and joystick (together) in the following games
and everything now works like it worked before:

- Grand Prix Legends (good test as it is a win95 game - also since some
  earlier of Vitaliy's patches the game now also detects the analog axes
  on the 1+n devices)
- Life For Speed (shows all devices ingame with their current state;
  good test for working SetProperty)
- IL2 (test for POV)
- Richard Burns Rally (had an regression after the initial patches and
  no controller at all was working due to the missing instance-values in
  the internal format; this game wants to set a dataformat composed of
  the data we deliver by EnumObjects)

-- 

diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c
index e2f77f8..3e8a796 100644
--- a/dlls/dinput/joystick_linuxinput.c
+++ b/dlls/dinput/joystick_linuxinput.c
@@ -70,8 +70,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput);
 
 /* Wine joystick driver object instances */
 #define WINE_JOYSTICK_AXIS_BASE   0
-#define WINE_JOYSTICK_POV_BASE    6
-#define WINE_JOYSTICK_BUTTON_BASE 8
+#define WINE_JOYSTICK_POV_BASE    8
+#define WINE_JOYSTICK_BUTTON_BASE 12
 
 typedef struct EffectListItem EffectListItem;
 struct EffectListItem
@@ -111,12 +111,6 @@ struct JoyDev {
 
 	/* data returned by the EVIOCGABS() ioctl */
 	int				axes[ABS_MAX][5];
-	/* LUT for KEY_ to offset in rgbButtons */
-	BYTE				buttons[KEY_MAX];
-
-	/* autodetecting ranges per axe by following movement */
-	LONG				havemax[ABS_MAX];
-	LONG				havemin[ABS_MAX];
 };
 
 struct JoystickImpl
@@ -128,11 +122,20 @@ struct JoystickImpl
 	/* The 'parent' DInput */
 	IDirectInputImpl               *dinput;
 
+	/* autodetecting ranges per axe by following movement */
+	LONG				havemax[8];
+	LONG				havemin[8];
 	/* joystick private */
 	/* what range and deadzone the game wants */
-	LONG				wantmin[ABS_MAX];
-	LONG				wantmax[ABS_MAX];
-	LONG				deadz[ABS_MAX];
+	LONG				wantmin[8];
+	LONG				wantmax[8];
+	LONG				deadz[8];
+
+        /* LUT for the mapping of used axes */
+        int                             axes[ABS_MAX];
+
+	/* LUT for KEY_ to offset in rgbButtons */
+	BYTE				buttons[KEY_MAX];
 
 	int				joyfd;
 
@@ -177,7 +180,7 @@ static void find_joydevs(void)
     struct JoyDev joydev = {0};
     int fd;
     int no_ff_check = 0;
-    int j, buttons;
+    int j;
 
     snprintf(buf,MAX_PATH,EVDEVPREFIX"%d",i);
     buf[MAX_PATH-1] = 0;
@@ -254,21 +257,10 @@ static void find_joydevs(void)
 		  joydev.axes[j][AXE_ABSFUZZ],
 		  joydev.axes[j][AXE_ABSFLAT]
 		  );
-	      joydev.havemin[j] = joydev.axes[j][AXE_ABSMIN];
-	      joydev.havemax[j] = joydev.axes[j][AXE_ABSMAX];
 	    }
 	  }
 	}
 
-	buttons = 0;
-	for (j=0;j<KEY_MAX;j++) {
-	  if (test_bit(joydev.keybits,j)) {
-	    TRACE(" ... with button %d: %d\n", j, buttons);
-	    joydev.buttons[j] = 0x80 | buttons;
-	    buttons++;
-	  }
-	}
-
 	if (have_joydevs==0) {
 	  joydevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct JoyDev));
 	} else {
@@ -357,8 +349,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, const void *jvt, IDirectInputIm
 {
     JoystickImpl* newDevice;
     LPDIDATAFORMAT df = NULL;
-    int i, idx = 0;
-    int axis = 0, pov = 0, btn = 0;
+    int i, idx = 0, btn=0;
 
     newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl));
     if (!newDevice) return NULL;
@@ -373,19 +364,6 @@ static JoystickImpl *alloc_device(REFGUID rguid, const void *jvt, IDirectInputIm
 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
   newDevice->ff_state = FF_STATUS_STOPPED;
 #endif
-  for (i=0;i<ABS_MAX;i++) {
-    /* apps expect the range to be the same they would get from the
-     * GetProperty/range method */
-    newDevice->wantmin[i] = newDevice->joydev->havemin[i];
-    newDevice->wantmax[i] = newDevice->joydev->havemax[i];
-    /* TODO: 
-     * direct input defines a default for the deadzone somewhere; but as long
-     * as in map_axis the code for the dead zone is commented out its no
-     * problem
-     */
-    newDevice->deadz[i]   =  0;
-  }
-  fake_current_js_state(newDevice);
 
     /* Create copy of default data format */
     if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto failed;
@@ -395,19 +373,29 @@ static JoystickImpl *alloc_device(REFGUID rguid, const void *jvt, IDirectInputIm
     /* Supported Axis & POVs should map 1-to-1 */
     for (i = 0; i < 8; i++)
     {
-        if (!test_bit(newDevice->joydev->absbits, i)) continue;
+        if (!test_bit(newDevice->joydev->absbits, i)) {
+          newDevice->axes[i] = -1;
+          continue;
+        }
 
-        memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[axis + WINE_JOYSTICK_AXIS_BASE], df->dwObjSize);
-        df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(axis++) | DIDFT_ABSAXIS;
+        memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i], df->dwObjSize);
+        newDevice->axes[i] = idx;
+        newDevice->havemin[idx] = newDevice->wantmin[idx] = newDevice->joydev->axes[i][AXE_ABSMIN];
+        newDevice->havemax[idx] = newDevice->wantmax[idx] = newDevice->joydev->axes[i][AXE_ABSMAX];
+        newDevice->deadz[idx] = 0;
+        df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_ABSAXIS;
     }
     for (i = 0; i < 4; i++)
     {
         if (!test_bit(newDevice->joydev->absbits, ABS_HAT0X + i * 2) ||
-            !test_bit(newDevice->joydev->absbits, ABS_HAT0Y + i * 2))
-            continue;
+            !test_bit(newDevice->joydev->absbits, ABS_HAT0Y + i * 2)) {
+          newDevice->axes[ABS_HAT0X + i * 2] = newDevice->axes[ABS_HAT0Y + i * 2] = -1;
+          continue;
+        }
 
-        memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[pov + WINE_JOYSTICK_POV_BASE], df->dwObjSize);
-        df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(pov++) | DIDFT_POV;
+        memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + WINE_JOYSTICK_POV_BASE], df->dwObjSize);
+        newDevice->axes[ABS_HAT0X + i * 2] = newDevice->axes[ABS_HAT0Y + i * 2] = i;
+        df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV;
     }
     /* Buttons can be anywhere, so check all */
     for (i = 0; i < KEY_MAX && btn < 128; i++)
@@ -415,10 +403,13 @@ static JoystickImpl *alloc_device(REFGUID rguid, const void *jvt, IDirectInputIm
         if (!test_bit(newDevice->joydev->keybits, i)) continue;
 
         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[btn + WINE_JOYSTICK_BUTTON_BASE], df->dwObjSize);
+        newDevice->buttons[i] = 0x80 | btn;
         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(btn++) | DIDFT_PSHBUTTON;
     }
     df->dwNumObjs = idx;
 
+    fake_current_js_state(newDevice);
+
     newDevice->base.data_format.wine_df = df;
     IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->dinput);
     return newDevice;
@@ -583,23 +574,19 @@ static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
  */
 static int
 map_axis(JoystickImpl* This, int axis, int val) {
-    int	xmin = This->joydev->axes[axis][AXE_ABSMIN];
-    int	xmax = This->joydev->axes[axis][AXE_ABSMAX];
-    int hmax = This->joydev->havemax[axis];
-    int hmin = This->joydev->havemin[axis];
+    int hmin = This->havemin[axis];
+    int hmax = This->havemax[axis];
     int	wmin = This->wantmin[axis];
     int	wmax = This->wantmax[axis];
     int ret;
 
-    if (val > hmax) This->joydev->havemax[axis] = hmax = val;
-    if (val < hmin) This->joydev->havemin[axis] = hmin = val;
-
-    if (xmin == xmax) return val;
+    if (val < hmin) This->havemin[axis] = hmin = val;
+    if (val > hmax) This->havemax[axis] = hmax = val;
 
     /* map the value from the hmin-hmax range into the wmin-wmax range */
     ret = MulDiv( val - hmin, wmax - wmin, hmax - hmin ) + wmin;
 
-    TRACE("xmin=%d xmax=%d hmin=%d hmax=%d wmin=%d wmax=%d val=%d ret=%d\n", xmin, xmax, hmin, hmax, wmin, wmax, val, ret);
+    TRACE("hmin=%d hmax=%d wmin=%d wmax=%d val=%d ret=%d\n", hmin, hmax, wmin, wmax, val, ret);
 
 #if 0
     /* deadzone doesn't work comfortably enough right now. needs more testing*/
@@ -619,14 +606,14 @@ static void fake_current_js_state(JoystickImpl *ji)
 {
 	int i;
 	/* center the axes */
-	ji->js.lX           = test_bit(ji->joydev->absbits, ABS_X)        ? map_axis(ji, ABS_X,        ji->joydev->axes[ABS_X       ][AXE_ABS]) : 0;
-	ji->js.lY           = test_bit(ji->joydev->absbits, ABS_Y)        ? map_axis(ji, ABS_Y,        ji->joydev->axes[ABS_Y       ][AXE_ABS]) : 0;
-	ji->js.lZ           = test_bit(ji->joydev->absbits, ABS_Z)        ? map_axis(ji, ABS_Z,        ji->joydev->axes[ABS_Z       ][AXE_ABS]) : 0;
-	ji->js.lRx          = test_bit(ji->joydev->absbits, ABS_RX)       ? map_axis(ji, ABS_RX,       ji->joydev->axes[ABS_RX      ][AXE_ABS]) : 0;
-	ji->js.lRy          = test_bit(ji->joydev->absbits, ABS_RY)       ? map_axis(ji, ABS_RY,       ji->joydev->axes[ABS_RY      ][AXE_ABS]) : 0;
-	ji->js.lRz          = test_bit(ji->joydev->absbits, ABS_RZ)       ? map_axis(ji, ABS_RZ,       ji->joydev->axes[ABS_RZ      ][AXE_ABS]) : 0;
-	ji->js.rglSlider[0] = test_bit(ji->joydev->absbits, ABS_THROTTLE) ? map_axis(ji, ABS_THROTTLE, ji->joydev->axes[ABS_THROTTLE][AXE_ABS]) : 0;
-	ji->js.rglSlider[1] = test_bit(ji->joydev->absbits, ABS_RUDDER)   ? map_axis(ji, ABS_RUDDER,   ji->joydev->axes[ABS_RUDDER  ][AXE_ABS]) : 0;
+	ji->js.lX           = test_bit(ji->joydev->absbits, ABS_X)        ? map_axis(ji, ji->axes[ABS_X],        ji->joydev->axes[ABS_X       ][AXE_ABS]) : 0;
+	ji->js.lY           = test_bit(ji->joydev->absbits, ABS_Y)        ? map_axis(ji, ji->axes[ABS_Y],        ji->joydev->axes[ABS_Y       ][AXE_ABS]) : 0;
+	ji->js.lZ           = test_bit(ji->joydev->absbits, ABS_Z)        ? map_axis(ji, ji->axes[ABS_Z],        ji->joydev->axes[ABS_Z       ][AXE_ABS]) : 0;
+	ji->js.lRx          = test_bit(ji->joydev->absbits, ABS_RX)       ? map_axis(ji, ji->axes[ABS_RX],       ji->joydev->axes[ABS_RX      ][AXE_ABS]) : 0;
+	ji->js.lRy          = test_bit(ji->joydev->absbits, ABS_RY)       ? map_axis(ji, ji->axes[ABS_RY],       ji->joydev->axes[ABS_RY      ][AXE_ABS]) : 0;
+	ji->js.lRz          = test_bit(ji->joydev->absbits, ABS_RZ)       ? map_axis(ji, ji->axes[ABS_RZ],       ji->joydev->axes[ABS_RZ      ][AXE_ABS]) : 0;
+	ji->js.rglSlider[0] = test_bit(ji->joydev->absbits, ABS_THROTTLE) ? map_axis(ji, ji->axes[ABS_THROTTLE], ji->joydev->axes[ABS_THROTTLE][AXE_ABS]) : 0;
+	ji->js.rglSlider[1] = test_bit(ji->joydev->absbits, ABS_RUDDER)   ? map_axis(ji, ji->axes[ABS_RUDDER],   ji->joydev->axes[ABS_RUDDER  ][AXE_ABS]) : 0;
 	/* POV center is -1 */
 	for (i=0; i<4; i++) {
 		ji->js.rgdwPOV[i] = -1;
@@ -658,45 +645,6 @@ static DWORD map_pov(int event_value, int is_x)
 	return ret;
 }
 
-/* defines how the linux input system offset mappings into c_dfDIJoystick2 */
-static int lxinput_to_user_index(JoystickImpl *This, int ie_type, int ie_code )
-{
-  int offset = -1;
-  switch (ie_type) {
-    case EV_ABS:
-      switch (ie_code) {
-        case ABS_X:                     offset = 0; break;
-        case ABS_Y:                     offset = 1; break;
-        case ABS_Z:                     offset = 2; break;
-        case ABS_RX:                    offset = 3; break;
-        case ABS_RY:                    offset = 4; break;
-        case ABS_RZ:                    offset = 5; break;
-        case ABS_THROTTLE:              offset = 6; break;
-        case ABS_RUDDER:                offset = 7; break;
-        case ABS_HAT0X: case ABS_HAT0Y: offset = 8; break;
-        case ABS_HAT1X: case ABS_HAT1Y: offset = 9; break;
-        case ABS_HAT2X: case ABS_HAT2Y: offset = 10; break;
-        case ABS_HAT3X: case ABS_HAT3Y: offset = 11; break;
-        /* XXX when adding new axes here also fix the offset for the buttons bellow */
-        default:
-          FIXME("Unhandled EV_ABS(0x%02X)\n", ie_code);
-          return -1;
-      }
-      break;
-    case EV_KEY:
-      if (ie_code >= 128) {
-        WARN("DX8 does not support more than 128 buttons\n");
-        return -1;
-      }
-      offset = 12 + ie_code; /* XXX */
-      break;
-    default:
-      FIXME("Unhandled type(0x%02X)\n", ie_type);
-      return -1;
-  }
-  return offset;
-}
-
 /* convert wine format offset to user format object index */
 static void joy_polldev(JoystickImpl *This)
 {
@@ -725,7 +673,7 @@ static void joy_polldev(JoystickImpl *This)
 	switch (ie.type) {
 	case EV_KEY:	/* button */
         {
-            int btn = This->joydev->buttons[ie.code];
+            int btn = This->buttons[ie.code];
 
             TRACE("(%p) %d -> %d\n", This, ie.code, btn);
             if (btn & 0x80)
@@ -737,10 +685,13 @@ static void joy_polldev(JoystickImpl *This)
             break;
         }
 	case EV_ABS:
-            if ((inst_id = lxinput_to_user_index(This, ie.type, ie.code)) == -1)
-                return;
-            inst_id = DIDFT_MAKEINSTANCE(inst_id) | (inst_id < ABS_HAT0X ? DIDFT_AXIS : DIDFT_POV);
-            value = map_axis(This, ie.code, ie.value);
+        {
+            int axe = This->axes[ie.code];
+            if (axe==-1) {
+              break;
+            }
+            inst_id = DIDFT_MAKEINSTANCE(axe) | (ie.code < ABS_HAT0X ? DIDFT_ABSAXIS : DIDFT_POV);
+            value = map_axis(This, axe, ie.value);
 
 	    switch (ie.code) {
             case ABS_X:         This->js.lX  = value; break;
@@ -772,6 +723,7 @@ static void joy_polldev(JoystickImpl *This)
 		break;
 	    }
 	    break;
+        }
 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
 	case EV_FF_STATUS:
 	    This->ff_state = ie.value;
@@ -982,8 +934,8 @@ static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
       int obj = find_property(&This->base.data_format, pdiph);
 
       if (obj >= 0) {
-	pr->lMin = This->joydev->havemin[obj];
-	pr->lMax = This->joydev->havemax[obj];
+	pr->lMin = This->havemin[obj];
+	pr->lMax = This->havemax[obj];
 	TRACE("range(%d, %d) obj=%d\n", pr->lMin, pr->lMax, obj);
       }
       break;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 163 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-patches/attachments/20070111/af93ee0c/attachment-0001.pgp


More information about the wine-patches mailing list