Moved and adopted joystick_linux.c code into the
[wine] / dlls / dinput / joystick_linuxinput.c
1 /*              DirectInput Joystick device
2  *
3  * Copyright 1998,2000 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  * Copyright 2005 Daniel Remenak
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <time.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #ifdef HAVE_SYS_TIME_H
35 # include <sys/time.h>
36 #endif
37 #include <sys/fcntl.h>
38 #ifdef HAVE_SYS_IOCTL_H
39 # include <sys/ioctl.h>
40 #endif
41 #include <errno.h>
42 #ifdef HAVE_SYS_ERRNO_H
43 # include <sys/errno.h>
44 #endif
45 #ifdef HAVE_LINUX_INPUT_H
46 # include <linux/input.h>
47 # if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE)
48 #  define HAVE_CORRECT_LINUXINPUT_H
49 # endif
50 #endif
51
52 #include "wine/debug.h"
53 #include "wine/unicode.h"
54 #include "windef.h"
55 #include "winbase.h"
56 #include "winerror.h"
57 #include "dinput.h"
58
59 #include "dinput_private.h"
60 #include "device_private.h"
61
62 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
63
64 #ifdef HAVE_CORRECT_LINUXINPUT_H
65
66 #define EVDEVPREFIX     "/dev/input/event"
67
68 /* Wine joystick driver object instances */
69 #define WINE_JOYSTICK_AXIS_BASE   0
70 #define WINE_JOYSTICK_BUTTON_BASE 8
71
72 typedef struct EffectListItem EffectListItem;
73 struct EffectListItem
74 {
75         LPDIRECTINPUTEFFECT ref;
76         struct EffectListItem* next;
77 };
78
79 /* implemented in effect_linuxinput.c */
80 HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, LPDIRECTINPUTEFFECT* peff);
81 HRESULT linuxinput_get_info_A(int fd, REFGUID rguid, LPDIEFFECTINFOA info);
82 HRESULT linuxinput_get_info_W(int fd, REFGUID rguid, LPDIEFFECTINFOW info);
83
84 typedef struct JoystickImpl JoystickImpl;
85 static const IDirectInputDevice8AVtbl JoystickAvt;
86 static const IDirectInputDevice8WVtbl JoystickWvt;
87 struct JoystickImpl
88 {
89         const void                     *lpVtbl;
90         LONG                            ref;
91         GUID                            guid;
92
93
94         /* The 'parent' DInput */
95         IDirectInputImpl               *dinput;
96
97         /* joystick private */
98         /* what range and deadzone the game wants */
99         LONG                            wantmin[ABS_MAX];
100         LONG                            wantmax[ABS_MAX];
101         LONG                            deadz[ABS_MAX];
102
103         /* autodetecting ranges per axe by following movement */
104         LONG                            havemax[ABS_MAX];
105         LONG                            havemin[ABS_MAX];
106
107         int                             joyfd;
108
109         LPDIDATAFORMAT                  df;
110         HANDLE                          hEvent;
111         LPDIDEVICEOBJECTDATA            data_queue;
112         int                             queue_head, queue_tail, queue_len;
113         BOOL                            overflow;
114         DIJOYSTATE2                     js;
115
116         /* Force feedback variables */
117         BOOL                            has_ff;
118         int                             num_effects;
119         EffectListItem*                 top_effect;
120         int                             ff_state;
121
122         /* data returned by the EVIOCGABS() ioctl */
123         int                             axes[ABS_MAX+1][5];
124
125 #define AXE_ABS         0
126 #define AXE_ABSMIN      1
127 #define AXE_ABSMAX      2
128 #define AXE_ABSFUZZ     3
129 #define AXE_ABSFLAT     4
130
131
132         /* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */
133         BYTE                            evbits[(EV_MAX+7)/8];
134         BYTE                            absbits[(ABS_MAX+7)/8];
135         BYTE                            keybits[(KEY_MAX+7)/8];
136         BYTE                            ffbits[(FF_MAX+7)/8];   
137 };
138
139 /* This GUID is slightly different from the linux joystick one. Take note. */
140 static GUID DInput_Wine_Joystick_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */
141   0x9e573eda,
142   0x7734,
143   0x11d2,
144   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
145 };
146
147 static void fake_current_js_state(JoystickImpl *ji);
148 static int find_property_offset(JoystickImpl *This, LPCDIPROPHEADER ph);
149
150 #define test_bit(arr,bit) (((BYTE*)arr)[bit>>3]&(1<<(bit&7)))
151
152 static int joydev_have(BOOL require_ff)
153 {
154   int i, fd, flags, num_effects;
155   int havejoy = 0;
156
157   for (i=0;i<64;i++) {
158       char      buf[200];
159       BYTE      absbits[(ABS_MAX+7)/8],keybits[(KEY_MAX+7)/8];
160       BYTE      evbits[(EV_MAX+7)/8],ffbits[(FF_MAX+7)/8];
161
162       sprintf(buf,EVDEVPREFIX"%d",i);
163
164       if (require_ff) 
165           flags = O_RDWR;
166       else
167           flags = O_RDONLY;
168
169       if (-1!=(fd=open(buf,flags))) {
170           if (-1==ioctl(fd,EVIOCGBIT(EV_ABS,sizeof(absbits)),absbits)) {
171               perror("EVIOCGBIT EV_ABS");
172               close(fd);
173               continue;
174           }
175           if (-1==ioctl(fd,EVIOCGBIT(EV_KEY,sizeof(keybits)),keybits)) {
176               perror("EVIOCGBIT EV_KEY");
177               close(fd);
178               continue;
179           }
180
181           /* test for force feedback if it's required */
182           if (require_ff) {
183               if ((-1==ioctl(fd,EVIOCGBIT(0,sizeof(evbits)),evbits))) {
184                   perror("EVIOCGBIT 0");
185                   close(fd);
186                   continue; 
187               }
188               if (   (!test_bit(evbits,EV_FF))
189                   || (-1==ioctl(fd,EVIOCGBIT(EV_FF,sizeof(ffbits)),ffbits)) 
190                   || (-1==ioctl(fd,EVIOCGEFFECTS,&num_effects))
191                   || (num_effects <= 0)) {
192                   close(fd);
193                   continue;
194               }
195           }
196
197           /* A true joystick has at least axis X and Y, and at least 1
198            * button. copied from linux/drivers/input/joydev.c */
199           if (test_bit(absbits,ABS_X) && test_bit(absbits,ABS_Y) &&
200               (   test_bit(keybits,BTN_TRIGGER) ||
201                   test_bit(keybits,BTN_A)       ||
202                   test_bit(keybits,BTN_1)
203               )
204           ) {
205               FIXME("found a joystick at %s!\n",buf);
206               havejoy = 1;
207           }
208           close(fd);
209       }
210       if (havejoy || (errno==ENODEV))
211           break;
212   }
213   return havejoy;
214 }
215
216 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
217 {
218   int havejoy = 0;
219
220   if (id != 0)
221       return FALSE;
222
223   if (!((dwDevType == 0) ||
224         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 0x0800)) ||
225         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
226     return FALSE;
227
228 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
229   if (dwFlags & DIEDFL_FORCEFEEDBACK)
230     return FALSE;
231 #endif
232
233   havejoy = joydev_have(dwFlags & DIEDFL_FORCEFEEDBACK);
234
235   if (!havejoy)
236       return FALSE;
237
238   TRACE("Enumerating the linuxinput Joystick device\n");
239
240   /* Return joystick */
241   lpddi->guidInstance   = GUID_Joystick;
242   lpddi->guidProduct    = DInput_Wine_Joystick_GUID;
243
244   lpddi->guidFFDriver = GUID_NULL;
245   if (version >= 0x0800)
246     lpddi->dwDevType    = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
247   else
248     lpddi->dwDevType    = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
249
250   strcpy(lpddi->tszInstanceName, "Joystick");
251   /* ioctl JSIOCGNAME(len) */
252   strcpy(lpddi->tszProductName, "Wine Joystick");
253   return TRUE;
254 }
255
256 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
257 {
258   int havejoy = 0;
259
260   if (id != 0)
261       return FALSE;
262
263   if (!((dwDevType == 0) ||
264         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 0x0800)) ||
265         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
266     return FALSE;
267
268 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
269   if (dwFlags & DIEDFL_FORCEFEEDBACK)
270     return FALSE;
271 #endif
272
273   havejoy = joydev_have(dwFlags & DIEDFL_FORCEFEEDBACK);
274
275   if (!havejoy)
276       return FALSE;
277
278   TRACE("Enumerating the linuxinput Joystick device\n");
279
280   /* Return joystick */
281   lpddi->guidInstance   = GUID_Joystick;
282   lpddi->guidProduct    = DInput_Wine_Joystick_GUID;
283
284   lpddi->guidFFDriver = GUID_NULL;
285   if (version >= 0x0800)
286     lpddi->dwDevType    = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
287   else
288     lpddi->dwDevType    = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
289
290   MultiByteToWideChar(CP_ACP, 0, "Joystick", -1, lpddi->tszInstanceName, MAX_PATH);
291   /* ioctl JSIOCGNAME(len) */
292   MultiByteToWideChar(CP_ACP, 0, "Wine Joystick", -1, lpddi->tszProductName, MAX_PATH);
293   return TRUE;
294 }
295
296 static JoystickImpl *alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput)
297 {
298   JoystickImpl* newDevice;
299   int i;
300
301   newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
302   newDevice->lpVtbl = jvt;
303   newDevice->ref = 1;
304   newDevice->joyfd = -1;
305   newDevice->dinput = dinput;
306 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
307   newDevice->ff_state = FF_STATUS_STOPPED;
308 #endif
309   memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
310   for (i=0;i<ABS_MAX;i++) {
311     newDevice->wantmin[i] = -32768;
312     newDevice->wantmax[i] =  32767;
313     /* TODO: 
314      * direct input defines a default for the deadzone somewhere; but as long
315      * as in map_axis the code for the dead zone is commented out its no
316      * problem
317      */
318     newDevice->deadz[i]   =  0;
319   }
320   fake_current_js_state(newDevice);
321   return newDevice;
322 }
323
324 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
325 {
326   int havejoy = 0;
327
328   havejoy = joydev_have(FALSE);
329
330   if (!havejoy)
331       return DIERR_DEVICENOTREG;
332
333   if ((IsEqualGUID(&GUID_Joystick,rguid)) ||
334       (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) {
335     if ((riid == NULL) ||
336         IsEqualGUID(&IID_IDirectInputDeviceA,riid) ||
337         IsEqualGUID(&IID_IDirectInputDevice2A,riid) ||
338         IsEqualGUID(&IID_IDirectInputDevice7A,riid) ||
339         IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
340       *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &JoystickAvt, dinput);
341       TRACE("Creating a Joystick device (%p)\n", *pdev);
342       return DI_OK;
343     } else
344       return DIERR_NOINTERFACE;
345   }
346
347   return DIERR_DEVICENOTREG;
348 }
349
350
351 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
352 {
353   int havejoy = 0;
354
355   havejoy = joydev_have(FALSE);
356
357   if (!havejoy)
358       return DIERR_DEVICENOTREG;
359
360   if ((IsEqualGUID(&GUID_Joystick,rguid)) ||
361       (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) {
362     if ((riid == NULL) ||
363         IsEqualGUID(&IID_IDirectInputDeviceW,riid) ||
364         IsEqualGUID(&IID_IDirectInputDevice2W,riid) ||
365         IsEqualGUID(&IID_IDirectInputDevice7W,riid) ||
366         IsEqualGUID(&IID_IDirectInputDevice8W,riid)) {
367       *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &JoystickWvt, dinput);
368       TRACE("Creating a Joystick device (%p)\n", *pdev);
369       return DI_OK;
370     } else
371       return DIERR_NOINTERFACE;
372   }
373
374   return DIERR_DEVICENOTREG;
375 }
376
377 const struct dinput_device joystick_linuxinput_device = {
378   "Wine Linux-input joystick driver",
379   joydev_enum_deviceA,
380   joydev_enum_deviceW,
381   joydev_create_deviceA,
382   joydev_create_deviceW
383 };
384
385 /******************************************************************************
386  *      Joystick
387  */
388 static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface)
389 {
390         JoystickImpl *This = (JoystickImpl *)iface;
391         ULONG ref;
392
393         ref = InterlockedDecrement(&(This->ref));
394         if (ref)
395                 return ref;
396
397         /* Reset the FF state, free all effects, etc */
398         IDirectInputDevice8_SendForceFeedbackCommand(iface, DISFFC_RESET);
399
400         /* Free the data queue */
401         HeapFree(GetProcessHeap(),0,This->data_queue);
402
403         /* Free the DataFormat */
404         HeapFree(GetProcessHeap(), 0, This->df);
405
406         HeapFree(GetProcessHeap(),0,This);
407         return 0;
408 }
409
410 /******************************************************************************
411   *   SetDataFormat : the application can choose the format of the data
412   *   the device driver sends back with GetDeviceState.
413   */
414 static HRESULT WINAPI JoystickAImpl_SetDataFormat(
415         LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df
416 )
417 {
418   JoystickImpl *This = (JoystickImpl *)iface;
419
420   TRACE("(this=%p,%p)\n",This,df);
421
422   _dump_DIDATAFORMAT(df);
423   
424   if (df == NULL) {
425     WARN("invalid pointer\n");
426     return E_POINTER;
427   }
428
429   if (df->dwSize != sizeof(*df)) {
430     WARN("invalid argument\n");
431     return DIERR_INVALIDPARAM;
432   }
433
434   if (This->joyfd!=-1) {
435     WARN("acquired\n");
436     return DIERR_ACQUIRED;
437   }
438
439   /* Store the new data format */
440   This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
441   if (This->df==NULL) {
442     return DIERR_OUTOFMEMORY;
443   }
444   memcpy(This->df, df, df->dwSize);
445   This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
446   if (This->df->rgodf==NULL) {
447     HeapFree(GetProcessHeap(), 0, This->df);
448     return DIERR_OUTOFMEMORY;
449   }
450   memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
451
452   return DI_OK;
453 }
454
455 /******************************************************************************
456   *     Acquire : gets exclusive control of the joystick
457   */
458 static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
459 {
460     int         i;
461     JoystickImpl *This = (JoystickImpl *)iface;
462     char        buf[200];
463     BOOL        readonly = TRUE;
464
465     TRACE("(this=%p)\n",This);
466     if (This->joyfd!=-1)
467         return 0;
468     for (i=0;i<64;i++) {
469       sprintf(buf,EVDEVPREFIX"%d",i);
470       if (-1==(This->joyfd=open(buf,O_RDWR))) { 
471         if (-1==(This->joyfd=open(buf,O_RDONLY))) {
472           /* Couldn't open the device at all */ 
473           if (errno==ENODEV)
474             return DIERR_NOTFOUND;
475           perror(buf);
476           continue;
477         }
478         else {
479           /* Couldn't open in r/w but opened in read-only. */
480           WARN("Could not open %s in read-write mode.  Force feedback will be disabled.\n",buf);
481         }
482       }
483       else {
484         /* Opened device in read-write */
485         readonly = FALSE;
486       }
487       if ((-1!=ioctl(This->joyfd,EVIOCGBIT(0,sizeof(This->evbits)),This->evbits)) &&
488           (-1!=ioctl(This->joyfd,EVIOCGBIT(EV_ABS,sizeof(This->absbits)),This->absbits)) &&
489           (-1!=ioctl(This->joyfd,EVIOCGBIT(EV_KEY,sizeof(This->keybits)),This->keybits)) &&
490           (test_bit(This->absbits,ABS_X) && test_bit(This->absbits,ABS_Y) &&
491            (test_bit(This->keybits,BTN_TRIGGER)||
492             test_bit(This->keybits,BTN_A)        ||
493             test_bit(This->keybits,BTN_1)
494           )
495          )
496       )
497         break;
498       close(This->joyfd);
499       This->joyfd = -1;
500     }
501     if (This->joyfd==-1)
502         return DIERR_NOTFOUND;
503
504     This->has_ff = FALSE;
505     This->num_effects = 0;
506
507 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
508     if (!readonly && test_bit(This->evbits, EV_FF)) {
509         if (-1!=ioctl(This->joyfd,EVIOCGBIT(EV_FF,sizeof(This->ffbits)),This->ffbits)) {
510             if (-1!=ioctl(This->joyfd,EVIOCGEFFECTS,&This->num_effects) 
511                 && This->num_effects > 0) {
512                 This->has_ff = TRUE;
513                 TRACE("Joystick seems to be capable of force feedback.\n");
514             }
515             else {
516                 TRACE("Joystick does not support any effects, disabling force feedback.\n");
517             }
518         }
519         else {
520             TRACE("Could not get EV_FF bits; disabling force feedback.\n");
521         }
522     }
523     else {
524         TRACE("Force feedback disabled (device is readonly or joystick incapable).\n");
525     }
526 #endif
527
528     for (i=0;i<ABS_MAX;i++) {
529         if (test_bit(This->absbits,i)) {
530           if (-1==ioctl(This->joyfd,EVIOCGABS(i),&(This->axes[i])))
531             continue;
532           FIXME("axe %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n",
533               i,
534               This->axes[i][AXE_ABS],
535               This->axes[i][AXE_ABSMIN],
536               This->axes[i][AXE_ABSMAX],
537               This->axes[i][AXE_ABSFUZZ],
538               This->axes[i][AXE_ABSFLAT]
539           );
540           This->havemin[i] = This->axes[i][AXE_ABSMIN];
541           This->havemax[i] = This->axes[i][AXE_ABSMAX];
542         }
543     }
544     MESSAGE("\n");
545
546         fake_current_js_state(This);
547
548     return 0;
549 }
550
551 /******************************************************************************
552   *     Unacquire : frees the joystick
553   */
554 static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
555 {
556     JoystickImpl *This = (JoystickImpl *)iface;
557
558     TRACE("(this=%p)\n",This);
559     if (This->joyfd!=-1) {
560         close(This->joyfd);
561         This->joyfd = -1;
562         return DI_OK;
563     }
564     else 
565         return DI_NOEFFECT;
566 }
567
568 /*
569  * This maps the read value (from the input event) to a value in the
570  * 'wanted' range. It also autodetects the possible range of the axe and
571  * adapts values accordingly.
572  */
573 static int
574 map_axis(JoystickImpl* This, int axis, int val) {
575     int xmin = This->axes[axis][AXE_ABSMIN];
576     int xmax = This->axes[axis][AXE_ABSMAX];
577     int hmax = This->havemax[axis];
578     int hmin = This->havemin[axis];
579     int wmin = This->wantmin[axis];
580     int wmax = This->wantmax[axis];
581     int ret;
582
583     if (val > hmax) This->havemax[axis] = hmax = val;
584     if (val < hmin) This->havemin[axis] = hmin = val;
585
586     if (xmin == xmax) return val;
587
588     /* map the value from the hmin-hmax range into the wmin-wmax range */
589     ret = ((val-hmin) * (wmax-wmin)) / (hmax-hmin) + wmin;
590
591     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);
592
593 #if 0
594     /* deadzone doesn't work comfortably enough right now. needs more testing*/
595     if ((ret > -deadz/2 ) && (ret < deadz/2)) {
596         FIXME("%d in deadzone, return mid.\n",val);
597         return (wmax-wmin)/2+wmin;
598     }
599 #endif
600     return ret;
601 }
602
603 /* 
604  * set the current state of the js device as it would be with the middle
605  * values on the axes
606  */
607 static void fake_current_js_state(JoystickImpl *ji)
608 {
609         ji->js.lX  = map_axis(ji, ABS_X,  ji->axes[ABS_X ][AXE_ABS]);
610         ji->js.lY  = map_axis(ji, ABS_Y,  ji->axes[ABS_Y ][AXE_ABS]);
611         ji->js.lZ  = map_axis(ji, ABS_Z,  ji->axes[ABS_Z ][AXE_ABS]);
612         ji->js.lRx = map_axis(ji, ABS_RX, ji->axes[ABS_RX][AXE_ABS]);
613         ji->js.lRy = map_axis(ji, ABS_RY, ji->axes[ABS_RY][AXE_ABS]);
614         ji->js.lRz = map_axis(ji, ABS_RZ, ji->axes[ABS_RZ][AXE_ABS]);
615         ji->js.rglSlider[0] = map_axis(ji, ABS_THROTTLE, ji->axes[ABS_THROTTLE][AXE_ABS]);
616         ji->js.rglSlider[1] = map_axis(ji, ABS_RUDDER,   ji->axes[ABS_RUDDER  ][AXE_ABS]);
617 }
618
619 static int find_property_offset(JoystickImpl *This, LPCDIPROPHEADER ph)
620 {
621   int i,c;
622   switch (ph->dwHow) {
623     case DIPH_BYOFFSET:
624       for (i=0; i<This->df->dwNumObjs; i++) {
625         if (This->df->rgodf[i].dwOfs == ph->dwObj) {
626           return i;
627         }
628       }
629       break;
630     case DIPH_BYID:
631       /* XXX: this is a hack - see below */
632       c = DIDFT_GETINSTANCE(ph->dwObj)>>WINE_JOYSTICK_AXIS_BASE;
633       for (i=0; (c&1)==0 && i<0x0F; i++) {
634         c >>= 1;
635       }
636       if (i<0x0F) {
637         return i;
638       }
639
640       /* XXX - the following part wont work with LiveForSpeed
641        * - the game sets the dwTypes to something else then
642        * the ddoi.dwType set in EnumObjects
643        */
644 #if 0
645       for (i=0; i<This->df->dwNumObjs; i++) {
646         TRACE("dwType='%08x'\n", This->df->rgodf[i].dwType);
647         if ((This->df->rgodf[i].dwType & 0x00ffffff) == (ph->dwObj & 0x00ffffff)) {
648           return i;
649         }
650       }
651 #endif
652       break;
653     default:
654       FIXME("Unhandled ph->dwHow=='%04X'\n", (unsigned int)ph->dwHow);
655   }
656
657   return -1;
658 }
659
660 static void joy_polldev(JoystickImpl *This) {
661     struct timeval tv;
662     fd_set      readfds;
663     struct      input_event ie;
664
665     if (This->joyfd==-1)
666         return;
667
668     while (1) {
669         memset(&tv,0,sizeof(tv));
670         FD_ZERO(&readfds);
671         FD_SET(This->joyfd,&readfds);
672
673         if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv))
674             return;
675
676         /* we have one event, so we can read */
677         if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie)))
678             return;
679
680         TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value);
681         switch (ie.type) {
682         case EV_KEY:    /* button */
683             switch (ie.code) {
684             case BTN_TRIGGER:   /* normal flight stick */
685             case BTN_A:         /* gamepad */
686             case BTN_1:         /* generic */
687                 This->js.rgbButtons[0] = ie.value?0x80:0x00;
688                 GEN_EVENT(DIJOFS_BUTTON(0),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
689                 break;
690             case BTN_THUMB:
691             case BTN_B:
692             case BTN_2:
693                 This->js.rgbButtons[1] = ie.value?0x80:0x00;
694                 GEN_EVENT(DIJOFS_BUTTON(1),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
695                 break;
696             case BTN_THUMB2:
697             case BTN_C:
698             case BTN_3:
699                 This->js.rgbButtons[2] = ie.value?0x80:0x00;
700                 GEN_EVENT(DIJOFS_BUTTON(2),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
701                 break;
702             case BTN_TOP:
703             case BTN_X:
704             case BTN_4:
705                 This->js.rgbButtons[3] = ie.value?0x80:0x00;
706                 GEN_EVENT(DIJOFS_BUTTON(3),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
707                 break;
708             case BTN_TOP2:
709             case BTN_Y:
710             case BTN_5:
711                 This->js.rgbButtons[4] = ie.value?0x80:0x00;
712                 GEN_EVENT(DIJOFS_BUTTON(4),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
713                 break;
714             case BTN_PINKIE:
715             case BTN_Z:
716             case BTN_6:
717                 This->js.rgbButtons[5] = ie.value?0x80:0x00;
718                 GEN_EVENT(DIJOFS_BUTTON(5),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
719                 break;
720             case BTN_BASE:
721             case BTN_TL:
722             case BTN_7:
723                 This->js.rgbButtons[6] = ie.value?0x80:0x00;
724                 GEN_EVENT(DIJOFS_BUTTON(6),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
725                 break;
726             case BTN_BASE2:
727             case BTN_TR:
728             case BTN_8:
729                 This->js.rgbButtons[7] = ie.value?0x80:0x00;
730                 GEN_EVENT(DIJOFS_BUTTON(7),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
731                 break;
732             case BTN_BASE3:
733             case BTN_TL2:
734             case BTN_9:
735                 This->js.rgbButtons[8] = ie.value?0x80:0x00;
736                 GEN_EVENT(DIJOFS_BUTTON(8),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
737                 break;
738             case BTN_BASE4:
739             case BTN_TR2:
740                 This->js.rgbButtons[9] = ie.value?0x80:0x00;
741                 GEN_EVENT(DIJOFS_BUTTON(9),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
742                 break;
743             case BTN_BASE5:
744             case BTN_SELECT:
745                 This->js.rgbButtons[10] = ie.value?0x80:0x00;
746                 GEN_EVENT(DIJOFS_BUTTON(10),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
747                 break;
748             default:
749                 FIXME("unhandled joystick button %x, value %d\n",ie.code,ie.value);
750                 break;
751             }
752             break;
753         case EV_ABS:
754             switch (ie.code) {
755             case ABS_X:
756                 This->js.lX = map_axis(This,ABS_X,ie.value);
757                 GEN_EVENT(DIJOFS_X,This->js.lX,ie.time.tv_usec,(This->dinput->evsequence)++);
758                 break;
759             case ABS_Y:
760                 This->js.lY = map_axis(This,ABS_Y,ie.value);
761                 GEN_EVENT(DIJOFS_Y,This->js.lY,ie.time.tv_usec,(This->dinput->evsequence)++);
762                 break;
763             case ABS_Z:
764                 This->js.lZ = map_axis(This,ABS_Z,ie.value);
765                 GEN_EVENT(DIJOFS_Z,This->js.lZ,ie.time.tv_usec,(This->dinput->evsequence)++);
766                 break;
767             case ABS_RX:
768                 This->js.lRx = map_axis(This,ABS_RX,ie.value);
769                 GEN_EVENT(DIJOFS_RX,This->js.lRx,ie.time.tv_usec,(This->dinput->evsequence)++);
770                 break;
771             case ABS_RY:
772                 This->js.lRy = map_axis(This,ABS_RY,ie.value);
773                 GEN_EVENT(DIJOFS_RY,This->js.lRy,ie.time.tv_usec,(This->dinput->evsequence)++);
774                 break;
775             case ABS_RZ:
776                 This->js.lRz = map_axis(This,ABS_RZ,ie.value);
777                 GEN_EVENT(DIJOFS_RZ,This->js.lRz,ie.time.tv_usec,(This->dinput->evsequence)++);
778                 break;
779             case ABS_THROTTLE:
780                 This->js.rglSlider[0] = map_axis(This,ABS_THROTTLE,ie.value);
781                 GEN_EVENT(DIJOFS_SLIDER(0),This->js.rglSlider[0],ie.time.tv_usec,(This->dinput->evsequence)++);
782                 break;
783             case ABS_RUDDER:
784                 This->js.rglSlider[1] = map_axis(This,ABS_RUDDER,ie.value);
785                 GEN_EVENT(DIJOFS_SLIDER(1),This->js.rglSlider[1],ie.time.tv_usec,(This->dinput->evsequence)++);
786                 break;
787             default:
788                 FIXME("unhandled joystick axe event (code %d, value %d)\n",ie.code,ie.value);
789                 break;
790             }
791             break;
792 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
793         case EV_FF_STATUS:
794             This->ff_state = ie.value;
795             break;
796 #endif
797         default:
798             FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code);
799             break;
800         }
801     }
802 }
803
804 /******************************************************************************
805   *     GetDeviceState : returns the "state" of the joystick.
806   *
807   */
808 static HRESULT WINAPI JoystickAImpl_GetDeviceState(
809         LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr
810 ) {
811     JoystickImpl *This = (JoystickImpl *)iface;
812
813     joy_polldev(This);
814
815     TRACE("(this=%p,0x%08lx,%p)\n",This,len,ptr);
816     if ((len != sizeof(DIJOYSTATE)) && (len != sizeof(DIJOYSTATE2))) {
817         FIXME("len %ld is not sizeof(DIJOYSTATE) or DIJOYSTATE2, unsupported format.\n",len);
818         return E_FAIL;
819     }
820     memcpy(ptr,&(This->js),len);
821     This->queue_head = 0;
822     This->queue_tail = 0;
823     return 0;
824 }
825
826 /******************************************************************************
827   *     GetDeviceData : gets buffered input data.
828   */
829 static HRESULT WINAPI JoystickAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface,
830                                               DWORD dodsize,
831                                               LPDIDEVICEOBJECTDATA dod,
832                                               LPDWORD entries,
833                                               DWORD flags
834 ) {
835   JoystickImpl *This = (JoystickImpl *)iface;
836   DWORD len;
837   int nqtail;
838   HRESULT hr = DI_OK;
839
840   TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
841
842   if (This->joyfd==-!1) {
843     WARN("not acquired\n");
844     return DIERR_NOTACQUIRED;
845   }
846
847   joy_polldev(This);
848   if (flags & DIGDD_PEEK)
849     FIXME("DIGDD_PEEK\n");
850
851   len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
852     + (This->queue_head - This->queue_tail);
853   if (len > *entries)
854     len = *entries;
855
856   if (dod == NULL) {
857     if (len)
858       TRACE("Application discarding %ld event(s).\n", len);
859
860     *entries = len;
861     nqtail = This->queue_tail + len;
862     while (nqtail >= This->queue_len)
863       nqtail -= This->queue_len;
864   } else {
865     if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) {
866       ERR("Wrong structure size !\n");
867       return DIERR_INVALIDPARAM;
868   }
869
870     if (len)
871       TRACE("Application retrieving %ld event(s).\n", len);
872
873     *entries = 0;
874     nqtail = This->queue_tail;
875     while (len) {
876       /* Copy the buffered data into the application queue */
877       memcpy((char *)dod + *entries * dodsize, This->data_queue + nqtail, dodsize);
878       /* Advance position */
879       nqtail++;
880       if (nqtail >= This->queue_len)
881         nqtail -= This->queue_len;
882       (*entries)++;
883       len--;
884     }
885   }
886
887   if (This->overflow) {
888     hr = DI_BUFFEROVERFLOW;
889     if (!(flags & DIGDD_PEEK)) {
890       This->overflow = FALSE;
891     }
892   }
893
894   if (!(flags & DIGDD_PEEK))
895     This->queue_tail = nqtail;
896
897   return hr;
898 }
899
900 /******************************************************************************
901   *     SetProperty : change input device properties
902   */
903 static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface,
904                                             REFGUID rguid,
905                                             LPCDIPROPHEADER ph)
906 {
907   JoystickImpl *This = (JoystickImpl *)iface;
908
909   FIXME("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
910   FIXME("ph.dwSize = %ld, ph.dwHeaderSize =%ld, ph.dwObj = %ld, ph.dwHow= %ld\n",ph->dwSize, ph->dwHeaderSize,ph->dwObj,ph->dwHow);
911
912   if (!HIWORD(rguid)) {
913     switch (LOWORD(rguid)) {
914     case (DWORD) DIPROP_BUFFERSIZE: {
915       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
916
917       TRACE("buffersize = %ld\n",pd->dwData);
918       if (This->data_queue) {
919         This->data_queue = HeapReAlloc(GetProcessHeap(),0, This->data_queue, pd->dwData * sizeof(DIDEVICEOBJECTDATA));
920       } else {
921         This->data_queue = HeapAlloc(GetProcessHeap(),0, pd->dwData * sizeof(DIDEVICEOBJECTDATA));
922       }
923       This->queue_head = 0;
924       This->queue_tail = 0;
925       This->queue_len  = pd->dwData;
926       break;
927     }
928     case (DWORD)DIPROP_RANGE: {
929       LPCDIPROPRANGE    pr = (LPCDIPROPRANGE)ph;
930
931       if (ph->dwHow == DIPH_DEVICE) {
932         int i;
933         TRACE("proprange(%ld,%ld) all\n",pr->lMin,pr->lMax);
934         for (i = 0; i < This->df->dwNumObjs; i++) {
935           This->wantmin[i] = pr->lMin;
936           This->wantmax[i] = pr->lMax;
937         }
938       } else {
939         int obj = find_property_offset(This, ph);
940         TRACE("proprange(%ld,%ld) obj=%d\n",pr->lMin,pr->lMax,obj);
941         if (obj >= 0) {
942           This->wantmin[obj] = pr->lMin;
943           This->wantmax[obj] = pr->lMax;
944         }
945       }
946       return DI_OK;
947     }
948     case (DWORD)DIPROP_DEADZONE: {
949       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
950       if (ph->dwHow == DIPH_DEVICE) {
951         int i;
952         TRACE("deadzone(%ld) all\n",pd->dwData);
953         for (i = 0; i < This->df->dwNumObjs; i++) {
954           This->deadz[i] = pd->dwData;
955         }
956       } else {
957         int obj = find_property_offset(This, ph);
958         TRACE("deadzone(%ld) obj=%d\n",pd->dwData,obj);
959         if (obj >= 0) {
960           This->deadz[obj] = pd->dwData;
961         }
962       }
963       return DI_OK;
964     }
965     default:
966       FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid));
967       break;
968     }
969   }
970   fake_current_js_state(This);
971   return 0;
972 }
973
974 /******************************************************************************
975   *     SetEventNotification : specifies event to be sent on state change
976   */
977 static HRESULT WINAPI JoystickAImpl_SetEventNotification(
978         LPDIRECTINPUTDEVICE8A iface, HANDLE hnd
979 ) {
980     JoystickImpl *This = (JoystickImpl *)iface;
981
982     TRACE("(this=%p,%p)\n",This,hnd);
983     This->hEvent = hnd;
984     return DI_OK;
985 }
986
987 static HRESULT WINAPI JoystickAImpl_GetCapabilities(
988         LPDIRECTINPUTDEVICE8A iface,
989         LPDIDEVCAPS lpDIDevCaps)
990 {
991     JoystickImpl *This = (JoystickImpl *)iface;
992     int         xfd = This->joyfd;
993     int         i,axes,buttons;
994
995     TRACE("%p->(%p)\n",iface,lpDIDevCaps);
996     if (xfd==-1) {
997         /* yes, games assume we return something, even if unacquired */
998         JoystickAImpl_Acquire(iface);
999     }
1000
1001     lpDIDevCaps->dwFlags        = DIDC_ATTACHED;
1002     if (This->dinput->dwVersion >= 0x0800)
1003         lpDIDevCaps->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
1004     else
1005         lpDIDevCaps->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
1006
1007     axes=0;
1008     for (i=0;i<ABS_MAX;i++) if (test_bit(This->absbits,i)) axes++;
1009     buttons=0;
1010     for (i=0;i<KEY_MAX;i++) if (test_bit(This->keybits,i)) buttons++;
1011
1012     if (This->has_ff) 
1013          lpDIDevCaps->dwFlags |= DIDC_FORCEFEEDBACK;
1014
1015     lpDIDevCaps->dwAxes = axes;
1016     lpDIDevCaps->dwButtons = buttons;
1017
1018     if (xfd==-1) {
1019       JoystickAImpl_Unacquire(iface);
1020     }
1021
1022     return DI_OK;
1023 }
1024
1025 static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) {
1026     JoystickImpl *This = (JoystickImpl *)iface;
1027     TRACE("(%p)\n",This);
1028
1029     if (This->joyfd==-1) {
1030       return DIERR_NOTACQUIRED;
1031     }
1032
1033     joy_polldev(This);
1034     return DI_OK;
1035 }
1036
1037 /******************************************************************************
1038   *     EnumObjects : enumerate the different buttons and axis...
1039   */
1040 static HRESULT WINAPI JoystickAImpl_EnumObjects(
1041         LPDIRECTINPUTDEVICE8A iface,
1042         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
1043         LPVOID lpvRef,
1044         DWORD dwFlags)
1045 {
1046   JoystickImpl *This = (JoystickImpl *)iface;
1047   DIDEVICEOBJECTINSTANCEA ddoi;
1048   int xfd = This->joyfd;
1049
1050   TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
1051   if (TRACE_ON(dinput)) {
1052     TRACE("  - flags = ");
1053     _dump_EnumObjects_flags(dwFlags);
1054     TRACE("\n");
1055   }
1056
1057   /* We need to work even if we're not yet acquired */
1058   if (xfd == -1)
1059     IDirectInputDevice8_Acquire(iface);
1060
1061   /* Only the fields till dwFFMaxForce are relevant */
1062   ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
1063
1064   /* For the joystick, do as is done in the GetCapabilities function */
1065   /* FIXME: needs more items */
1066   if ((dwFlags == DIDFT_ALL) ||
1067       (dwFlags & DIDFT_AXIS)) {
1068     BYTE i;
1069
1070     for (i = 0; i < ABS_MAX; i++) {
1071       if (!test_bit(This->absbits,i)) continue;
1072
1073       switch (i) {
1074       case ABS_X:
1075         ddoi.guidType = GUID_XAxis;
1076         ddoi.dwOfs = DIJOFS_X;
1077         break;
1078       case ABS_Y:
1079         ddoi.guidType = GUID_YAxis;
1080         ddoi.dwOfs = DIJOFS_Y;
1081         break;
1082       case ABS_Z:
1083         ddoi.guidType = GUID_ZAxis;
1084         ddoi.dwOfs = DIJOFS_Z;
1085         break;
1086       case ABS_RX:
1087         ddoi.guidType = GUID_RxAxis;
1088         ddoi.dwOfs = DIJOFS_RX;
1089         break;
1090       case ABS_RY:
1091         ddoi.guidType = GUID_RyAxis;
1092         ddoi.dwOfs = DIJOFS_RY;
1093         break;
1094       case ABS_RZ:
1095         ddoi.guidType = GUID_RzAxis;
1096         ddoi.dwOfs = DIJOFS_RZ;
1097         break;
1098       case ABS_THROTTLE:
1099         ddoi.guidType = GUID_Slider;
1100         ddoi.dwOfs = DIJOFS_SLIDER(0);
1101         break;
1102       case ABS_RUDDER:
1103         ddoi.guidType = GUID_Slider;
1104         ddoi.dwOfs = DIJOFS_SLIDER(1);
1105         break;
1106       default:
1107         FIXME("unhandled abs axis %d, ignoring!\n",i);
1108       }
1109       ddoi.dwType = DIDFT_MAKEINSTANCE((1<<i) << WINE_JOYSTICK_AXIS_BASE) | DIDFT_ABSAXIS;
1110       /* Linux event force feedback supports only (and always) x and y axes */
1111       if (i == ABS_X || i == ABS_Y) {
1112         if (This->has_ff)
1113           ddoi.dwFlags |= DIDOI_FFACTUATOR;
1114       }
1115       sprintf(ddoi.tszName, "%d-Axis", i);
1116       _dump_OBJECTINSTANCEA(&ddoi);
1117       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) {
1118         /* return to unaquired state if that's where we were */
1119         if (xfd == -1)
1120           IDirectInputDevice8_Unacquire(iface);
1121         return DI_OK;
1122       }
1123     }
1124   }
1125
1126   if ((dwFlags == DIDFT_ALL) ||
1127       (dwFlags & DIDFT_BUTTON)) {
1128     int i;
1129
1130     /*The DInput SDK says that GUID_Button is only for mouse buttons but well*/
1131
1132     ddoi.guidType = GUID_Button;
1133
1134     for (i = 0; i < KEY_MAX; i++) {
1135       if (!test_bit(This->keybits,i)) continue;
1136
1137       switch (i) {
1138       case BTN_TRIGGER:
1139       case BTN_A:
1140       case BTN_1:
1141           ddoi.dwOfs = DIJOFS_BUTTON(0);
1142           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 0) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1143           break;
1144         case BTN_THUMB:
1145         case BTN_B:
1146         case BTN_2:
1147           ddoi.dwOfs = DIJOFS_BUTTON(1);
1148           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 1) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1149           break;
1150         case BTN_THUMB2:
1151         case BTN_C:
1152         case BTN_3:
1153           ddoi.dwOfs = DIJOFS_BUTTON(2);
1154           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 2) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1155           break;
1156         case BTN_TOP:
1157         case BTN_X:
1158         case BTN_4:
1159           ddoi.dwOfs = DIJOFS_BUTTON(3);
1160           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 3) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1161           break;
1162         case BTN_TOP2:
1163         case BTN_Y:
1164         case BTN_5:
1165           ddoi.dwOfs = DIJOFS_BUTTON(4);
1166           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 4) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1167           break;
1168         case BTN_PINKIE:
1169         case BTN_Z:
1170         case BTN_6:
1171           ddoi.dwOfs = DIJOFS_BUTTON(5);
1172           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 5) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1173           break;
1174         case BTN_BASE:
1175         case BTN_TL:
1176         case BTN_7:
1177           ddoi.dwOfs = DIJOFS_BUTTON(6);
1178           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 6) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1179           break;
1180         case BTN_BASE2:
1181         case BTN_TR:
1182         case BTN_8:
1183           ddoi.dwOfs = DIJOFS_BUTTON(7);
1184           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 7) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1185           break;
1186         case BTN_BASE3:
1187         case BTN_TL2:
1188         case BTN_9:
1189           ddoi.dwOfs = DIJOFS_BUTTON(8);
1190           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 8) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1191           break;
1192         case BTN_BASE4:
1193         case BTN_TR2:
1194           ddoi.dwOfs = DIJOFS_BUTTON(9);
1195           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 9) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1196           break;
1197         case BTN_BASE5:
1198         case BTN_SELECT:
1199           ddoi.dwOfs = DIJOFS_BUTTON(10);
1200           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 10) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1201           break;
1202       }
1203       sprintf(ddoi.tszName, "%d-Button", i);
1204       _dump_OBJECTINSTANCEA(&ddoi);
1205       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) {
1206         /* return to unaquired state if that's where we were */
1207         if (xfd == -1)
1208           IDirectInputDevice8_Unacquire(iface);
1209         return DI_OK;
1210       }
1211     }
1212   }
1213
1214   /* return to unaquired state if that's where we were */
1215   if (xfd == -1)
1216     IDirectInputDevice8_Unacquire(iface);
1217
1218   return DI_OK;
1219 }
1220
1221 static HRESULT WINAPI JoystickWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface,
1222                                                 LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback,
1223                                                 LPVOID lpvRef,
1224                                                 DWORD dwFlags)
1225 {
1226   JoystickImpl *This = (JoystickImpl *)iface;
1227
1228   device_enumobjects_AtoWcb_data data;
1229
1230   data.lpCallBack = lpCallback;
1231   data.lpvRef = lpvRef;
1232
1233   return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags);
1234 }
1235
1236 /******************************************************************************
1237   *     GetProperty : get input device properties
1238   */
1239 static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
1240                                                 REFGUID rguid,
1241                                                 LPDIPROPHEADER pdiph)
1242 {
1243   JoystickImpl *This = (JoystickImpl *)iface;
1244
1245   TRACE("(this=%p,%s,%p)\n",
1246         iface, debugstr_guid(rguid), pdiph);
1247
1248   if (TRACE_ON(dinput))
1249     _dump_DIPROPHEADER(pdiph);
1250
1251   if (!HIWORD(rguid)) {
1252     switch (LOWORD(rguid)) {
1253     case (DWORD) DIPROP_BUFFERSIZE: {
1254       LPDIPROPDWORD     pd = (LPDIPROPDWORD)pdiph;
1255
1256       TRACE(" return buffersize = %d\n",This->queue_len);
1257       pd->dwData = This->queue_len;
1258       break;
1259     }
1260
1261     case (DWORD) DIPROP_RANGE: {
1262       /* LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; */
1263       if ((pdiph->dwHow == DIPH_BYID) &&
1264           (pdiph->dwObj & DIDFT_ABSAXIS)) {
1265         /* The app is querying the current range of the axis : return the lMin and lMax values */
1266         FIXME("unimplemented axis range query.\n");
1267       }
1268
1269       break;
1270     }
1271
1272     default:
1273       FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid));
1274       break;
1275     }
1276   }
1277
1278
1279   return DI_OK;
1280 }
1281
1282 /****************************************************************************** 
1283   *     CreateEffect - Create a new FF effect with the specified params
1284   */
1285 static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface,
1286                                                  REFGUID rguid,
1287                                                  LPCDIEFFECT lpeff,
1288                                                  LPDIRECTINPUTEFFECT *ppdef,
1289                                                  LPUNKNOWN pUnkOuter)
1290 {
1291 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1292     EffectListItem* new = NULL;
1293     HRESULT retval = DI_OK;
1294 #endif
1295
1296     JoystickImpl* This = (JoystickImpl*)iface;
1297     TRACE("(this=%p,%p,%p,%p,%p)\n", This, rguid, lpeff, ppdef, pUnkOuter);
1298
1299 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
1300     TRACE("not available (compiled w/o ff support)\n");
1301     *ppdef = NULL;
1302     return DI_OK; 
1303 #else
1304
1305     new = malloc(sizeof(EffectListItem));
1306     new->next = This->top_effect;
1307     This->top_effect = new;
1308
1309     retval = linuxinput_create_effect(&(This->joyfd), rguid, &(new->ref));
1310     if (retval != DI_OK)
1311         return retval;
1312  
1313     if (lpeff != NULL)
1314         retval = IDirectInputEffect_SetParameters(new->ref, lpeff, 0);
1315     if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED)
1316         return retval;
1317
1318     *ppdef = new->ref;
1319
1320     if (pUnkOuter != NULL)
1321         FIXME("Interface aggregation not implemented.\n");
1322
1323     return DI_OK;
1324
1325 #endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */
1326
1327
1328 /*******************************************************************************
1329  *      EnumEffects - Enumerate available FF effects
1330  */
1331 static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface,
1332                                                 LPDIENUMEFFECTSCALLBACKA lpCallback,
1333                                                 LPVOID pvRef,
1334                                                 DWORD dwEffType)
1335 {
1336 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1337     DIEFFECTINFOA dei; /* feif */
1338     DWORD type = DIEFT_GETTYPE(dwEffType);
1339     JoystickImpl* This = (JoystickImpl*)iface;
1340     int xfd = This->joyfd;
1341
1342     TRACE("(this=%p,%p,%ld) type=%ld fd=%d\n", This, pvRef, dwEffType, type, xfd);
1343
1344     dei.dwSize = sizeof(DIEFFECTINFOA);          
1345
1346     /* We need to return something even if we're not yet acquired */
1347     if (xfd == -1)
1348         IDirectInputDevice8_Acquire(iface);
1349
1350     if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1351         && test_bit(This->ffbits, FF_CONSTANT)) {
1352         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1353         (*lpCallback)(&dei, pvRef);
1354     }
1355
1356     if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1357         && test_bit(This->ffbits, FF_PERIODIC)) {
1358         if (test_bit(This->ffbits, FF_SQUARE)) {
1359             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1360             (*lpCallback)(&dei, pvRef);
1361         }
1362         if (test_bit(This->ffbits, FF_SINE)) {
1363             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1364             (*lpCallback)(&dei, pvRef);
1365         }
1366         if (test_bit(This->ffbits, FF_TRIANGLE)) {
1367             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1368             (*lpCallback)(&dei, pvRef);
1369         }
1370         if (test_bit(This->ffbits, FF_SAW_UP)) {
1371             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1372             (*lpCallback)(&dei, pvRef);
1373         }
1374         if (test_bit(This->ffbits, FF_SAW_DOWN)) {
1375             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1376             (*lpCallback)(&dei, pvRef);
1377         }
1378     } 
1379
1380     if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1381         && test_bit(This->ffbits, FF_RAMP)) {
1382         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1383         (*lpCallback)(&dei, pvRef);
1384     }
1385
1386     if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1387         if (test_bit(This->ffbits, FF_SPRING)) {
1388             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1389             (*lpCallback)(&dei, pvRef);
1390         }
1391         if (test_bit(This->ffbits, FF_DAMPER)) {
1392             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1393             (*lpCallback)(&dei, pvRef);
1394         }
1395         if (test_bit(This->ffbits, FF_INERTIA)) {
1396             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1397             (*lpCallback)(&dei, pvRef);
1398         }
1399         if (test_bit(This->ffbits, FF_FRICTION)) {
1400             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1401             (*lpCallback)(&dei, pvRef);
1402         }
1403     }
1404
1405     /* return to unaquired state if that's where it was */
1406     if (xfd == -1)
1407         IDirectInputDevice8_Unacquire(iface);
1408 #endif
1409
1410     return DI_OK;
1411 }
1412
1413 static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface,
1414                                                 LPDIENUMEFFECTSCALLBACKW lpCallback,
1415                                                 LPVOID pvRef,
1416                                                 DWORD dwEffType)
1417 {
1418 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1419     /* seems silly to duplicate all this code but all the structures and functions
1420      * are actually different (A/W) */
1421     DIEFFECTINFOW dei; /* feif */
1422     DWORD type = DIEFT_GETTYPE(dwEffType);
1423     JoystickImpl* This = (JoystickImpl*)iface;
1424     int xfd = This->joyfd;
1425
1426     TRACE("(this=%p,%p,%ld) type=%ld fd=%d\n", This, pvRef, dwEffType, type, xfd);
1427
1428     dei.dwSize = sizeof(DIEFFECTINFOW);          
1429
1430     /* We need to return something even if we're not yet acquired */
1431     if (xfd == -1)
1432         IDirectInputDevice8_Acquire(iface);
1433
1434     if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1435         && test_bit(This->ffbits, FF_CONSTANT)) {
1436         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1437         (*lpCallback)(&dei, pvRef);
1438     }
1439
1440     if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1441         && test_bit(This->ffbits, FF_PERIODIC)) {
1442         if (test_bit(This->ffbits, FF_SQUARE)) {
1443             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1444             (*lpCallback)(&dei, pvRef);
1445         }
1446         if (test_bit(This->ffbits, FF_SINE)) {
1447             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1448             (*lpCallback)(&dei, pvRef);
1449         }
1450         if (test_bit(This->ffbits, FF_TRIANGLE)) {
1451             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1452             (*lpCallback)(&dei, pvRef);
1453         }
1454         if (test_bit(This->ffbits, FF_SAW_UP)) {
1455             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1456             (*lpCallback)(&dei, pvRef);
1457         }
1458         if (test_bit(This->ffbits, FF_SAW_DOWN)) {
1459             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1460             (*lpCallback)(&dei, pvRef);
1461         }
1462     } 
1463
1464     if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1465         && test_bit(This->ffbits, FF_RAMP)) {
1466         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1467         (*lpCallback)(&dei, pvRef);
1468     }
1469
1470     if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1471         if (test_bit(This->ffbits, FF_SPRING)) {
1472             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1473             (*lpCallback)(&dei, pvRef);
1474         }
1475         if (test_bit(This->ffbits, FF_DAMPER)) {
1476             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1477             (*lpCallback)(&dei, pvRef);
1478         }
1479         if (test_bit(This->ffbits, FF_INERTIA)) {
1480             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1481             (*lpCallback)(&dei, pvRef);
1482         }
1483         if (test_bit(This->ffbits, FF_FRICTION)) {
1484             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1485             (*lpCallback)(&dei, pvRef);
1486         }
1487     }
1488
1489     /* return to unaquired state if that's where it was */
1490     if (xfd == -1)
1491         IDirectInputDevice8_Unacquire(iface);
1492 #endif
1493
1494     return DI_OK;
1495 }
1496
1497 /*******************************************************************************
1498  *      GetEffectInfo - Get information about a particular effect 
1499  */
1500 static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface,
1501                                                   LPDIEFFECTINFOA pdei,
1502                                                   REFGUID guid)
1503 {
1504     JoystickImpl* This = (JoystickImpl*)iface;
1505
1506     TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1507
1508 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1509     return linuxinput_get_info_A(This->joyfd, guid, pdei); 
1510 #else
1511     return DI_OK;
1512 #endif
1513 }
1514
1515 static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface,
1516                                                   LPDIEFFECTINFOW pdei,
1517                                                   REFGUID guid)
1518 {
1519     JoystickImpl* This = (JoystickImpl*)iface;
1520             
1521     TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1522         
1523 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1524     return linuxinput_get_info_W(This->joyfd, guid, pdei);
1525 #else
1526     return DI_OK;
1527 #endif
1528 }
1529
1530 /*******************************************************************************
1531  *      GetForceFeedbackState - Get information about the device's FF state 
1532  */
1533 static HRESULT WINAPI JoystickAImpl_GetForceFeedbackState(
1534         LPDIRECTINPUTDEVICE8A iface,
1535         LPDWORD pdwOut)
1536 {
1537     JoystickImpl* This = (JoystickImpl*)iface;
1538
1539     TRACE("(this=%p,%p)\n", This, pdwOut);
1540
1541     (*pdwOut) = 0;
1542
1543 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1544     /* DIGFFS_STOPPED is the only mandatory flag to report */
1545     if (This->ff_state == FF_STATUS_STOPPED)
1546         (*pdwOut) |= DIGFFS_STOPPED;
1547 #endif
1548
1549     return DI_OK;
1550 }
1551
1552 /*******************************************************************************
1553  *      SendForceFeedbackCommand - Send a command to the device's FF system
1554  */
1555 static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(
1556         LPDIRECTINPUTDEVICE8A iface,
1557         DWORD dwFlags)
1558 {
1559     JoystickImpl* This = (JoystickImpl*)iface;
1560     TRACE("(this=%p,%ld)\n", This, dwFlags);
1561
1562 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1563     if (dwFlags == DISFFC_STOPALL) {
1564         /* Stop all effects */
1565         EffectListItem* itr = This->top_effect;
1566         while (itr) {
1567             IDirectInputEffect_Stop(itr->ref);
1568             itr = itr->next;
1569         }
1570     } else if (dwFlags == DISFFC_RESET) {
1571         /* Stop, unload, release and free all effects */
1572         /* This returns the device to its "bare" state */
1573         while (This->top_effect) {
1574             EffectListItem* temp = This->top_effect; 
1575             IDirectInputEffect_Stop(temp->ref);
1576             IDirectInputEffect_Unload(temp->ref);
1577             IDirectInputEffect_Release(temp->ref);
1578             This->top_effect = temp->next; 
1579             free(temp);
1580         }
1581     } else if (dwFlags == DISFFC_PAUSE || dwFlags == DISFFC_CONTINUE) {
1582         FIXME("No support for Pause or Continue in linux\n");
1583     } else if (dwFlags == DISFFC_SETACTUATORSOFF 
1584                 || dwFlags == DISFFC_SETACTUATORSON) {
1585         FIXME("No direct actuator control in linux\n");
1586     } else {
1587         FIXME("Unknown Force Feedback Command!\n");
1588         return DIERR_INVALIDPARAM;
1589     }
1590     return DI_OK;
1591 #else
1592     return DIERR_UNSUPPORTED;
1593 #endif
1594 }
1595
1596 /*******************************************************************************
1597  *      EnumCreatedEffectObjects - Enumerate all the effects that have been
1598  *              created for this device.
1599  */
1600 static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects(
1601         LPDIRECTINPUTDEVICE8A iface,
1602         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
1603         LPVOID pvRef,
1604         DWORD dwFlags)
1605 {
1606     /* this function is safe to call on non-ff-enabled builds */
1607
1608     JoystickImpl* This = (JoystickImpl*)iface;
1609     EffectListItem* itr = This->top_effect;
1610     TRACE("(this=%p,%p,%p,%ld)\n", This, lpCallback, pvRef, dwFlags);
1611
1612     if (!lpCallback)
1613         return DIERR_INVALIDPARAM;
1614
1615     if (dwFlags != 0)
1616         FIXME("Flags specified, but no flags exist yet (DX9)!");
1617
1618     while (itr) {
1619         (*lpCallback)(itr->ref, pvRef);
1620         itr = itr->next;
1621     }
1622
1623     return DI_OK;
1624 }
1625
1626 static const IDirectInputDevice8AVtbl JoystickAvt =
1627 {
1628         IDirectInputDevice2AImpl_QueryInterface,
1629         IDirectInputDevice2AImpl_AddRef,
1630         JoystickAImpl_Release,
1631         JoystickAImpl_GetCapabilities,
1632         JoystickAImpl_EnumObjects,
1633         JoystickAImpl_GetProperty,
1634         JoystickAImpl_SetProperty,
1635         JoystickAImpl_Acquire,
1636         JoystickAImpl_Unacquire,
1637         JoystickAImpl_GetDeviceState,
1638         JoystickAImpl_GetDeviceData,
1639         JoystickAImpl_SetDataFormat,
1640         JoystickAImpl_SetEventNotification,
1641         IDirectInputDevice2AImpl_SetCooperativeLevel,
1642         IDirectInputDevice2AImpl_GetObjectInfo,
1643         IDirectInputDevice2AImpl_GetDeviceInfo,
1644         IDirectInputDevice2AImpl_RunControlPanel,
1645         IDirectInputDevice2AImpl_Initialize,
1646         JoystickAImpl_CreateEffect,
1647         JoystickAImpl_EnumEffects,
1648         JoystickAImpl_GetEffectInfo,
1649         JoystickAImpl_GetForceFeedbackState,
1650         JoystickAImpl_SendForceFeedbackCommand,
1651         JoystickAImpl_EnumCreatedEffectObjects,
1652         IDirectInputDevice2AImpl_Escape,
1653         JoystickAImpl_Poll,
1654         IDirectInputDevice2AImpl_SendDeviceData,
1655         IDirectInputDevice7AImpl_EnumEffectsInFile,
1656         IDirectInputDevice7AImpl_WriteEffectToFile,
1657         IDirectInputDevice8AImpl_BuildActionMap,
1658         IDirectInputDevice8AImpl_SetActionMap,
1659         IDirectInputDevice8AImpl_GetImageInfo
1660 };
1661
1662 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
1663 # define XCAST(fun)     (typeof(JoystickWvt.fun))
1664 #else
1665 # define XCAST(fun)     (void*)
1666 #endif
1667
1668 static const IDirectInputDevice8WVtbl JoystickWvt =
1669 {
1670         IDirectInputDevice2WImpl_QueryInterface,
1671         XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
1672         XCAST(Release)JoystickAImpl_Release,
1673         XCAST(GetCapabilities)JoystickAImpl_GetCapabilities,
1674         JoystickWImpl_EnumObjects,
1675         XCAST(GetProperty)JoystickAImpl_GetProperty,
1676         XCAST(SetProperty)JoystickAImpl_SetProperty,
1677         XCAST(Acquire)JoystickAImpl_Acquire,
1678         XCAST(Unacquire)JoystickAImpl_Unacquire,
1679         XCAST(GetDeviceState)JoystickAImpl_GetDeviceState,
1680         XCAST(GetDeviceData)JoystickAImpl_GetDeviceData,
1681         XCAST(SetDataFormat)JoystickAImpl_SetDataFormat,
1682         XCAST(SetEventNotification)JoystickAImpl_SetEventNotification,
1683         XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
1684         IDirectInputDevice2WImpl_GetObjectInfo,
1685         IDirectInputDevice2WImpl_GetDeviceInfo,
1686         XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
1687         XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
1688         XCAST(CreateEffect)JoystickAImpl_CreateEffect,
1689         JoystickWImpl_EnumEffects,
1690         JoystickWImpl_GetEffectInfo,
1691         XCAST(GetForceFeedbackState)JoystickAImpl_GetForceFeedbackState,
1692         XCAST(SendForceFeedbackCommand)JoystickAImpl_SendForceFeedbackCommand,
1693         XCAST(EnumCreatedEffectObjects)JoystickAImpl_EnumCreatedEffectObjects,
1694         XCAST(Escape)IDirectInputDevice2AImpl_Escape,
1695         XCAST(Poll)JoystickAImpl_Poll,
1696         XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
1697         IDirectInputDevice7WImpl_EnumEffectsInFile,
1698         IDirectInputDevice7WImpl_WriteEffectToFile,
1699         IDirectInputDevice8WImpl_BuildActionMap,
1700         IDirectInputDevice8WImpl_SetActionMap,
1701         IDirectInputDevice8WImpl_GetImageInfo
1702 };
1703 #undef XCAST
1704
1705 #else  /* HAVE_CORRECT_LINUXINPUT_H */
1706
1707 const struct dinput_device joystick_linuxinput_device = {
1708   "Wine Linux-input joystick driver",
1709   NULL,
1710   NULL,
1711   NULL,
1712   NULL
1713 };
1714
1715 #endif  /* HAVE_CORRECT_LINUXINPUT_H */