Removed some unused or redundant configure checks.
[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 JoystickImpl JoystickImpl;
73 static const IDirectInputDevice8AVtbl JoystickAvt;
74 static const IDirectInputDevice8WVtbl JoystickWvt;
75 struct JoystickImpl
76 {
77         const void                     *lpVtbl;
78         LONG                            ref;
79         GUID                            guid;
80
81
82         /* The 'parent' DInput */
83         IDirectInputImpl               *dinput;
84
85         /* joystick private */
86         /* what range and deadzone the game wants */
87         LONG                            wantmin[ABS_MAX];
88         LONG                            wantmax[ABS_MAX];
89         LONG                            deadz[ABS_MAX];
90
91         /* autodetecting ranges per axe by following movement */
92         LONG                            havemax[ABS_MAX];
93         LONG                            havemin[ABS_MAX];
94
95         int                             joyfd;
96
97         LPDIDATAFORMAT                  df;
98         HANDLE                          hEvent;
99         LPDIDEVICEOBJECTDATA            data_queue;
100         int                             queue_head, queue_tail, queue_len;
101         BOOL                            overflow;
102         DIJOYSTATE2                     js;
103
104         /* Force feedback variables */
105         BOOL                            has_ff;
106         int                             num_effects;
107
108         /* data returned by the EVIOCGABS() ioctl */
109         int                             axes[ABS_MAX+1][5];
110
111 #define AXE_ABS         0
112 #define AXE_ABSMIN      1
113 #define AXE_ABSMAX      2
114 #define AXE_ABSFUZZ     3
115 #define AXE_ABSFLAT     4
116
117
118         /* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */
119         BYTE                            evbits[(EV_MAX+7)/8];
120         BYTE                            absbits[(ABS_MAX+7)/8];
121         BYTE                            keybits[(KEY_MAX+7)/8];
122         BYTE                            ffbits[(FF_MAX+7)/8];   
123 };
124
125 /* This GUID is slightly different from the linux joystick one. Take note. */
126 static GUID DInput_Wine_Joystick_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */
127   0x9e573eda,
128   0x7734,
129   0x11d2,
130   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
131 };
132
133 static void fake_current_js_state(JoystickImpl *ji);
134
135 #define test_bit(arr,bit) (((BYTE*)arr)[bit>>3]&(1<<(bit&7)))
136
137 static int joydev_have(BOOL require_ff)
138 {
139   int i, fd, flags, num_effects;
140   int havejoy = 0;
141
142   for (i=0;i<64;i++) {
143       char      buf[200];
144       BYTE      absbits[(ABS_MAX+7)/8],keybits[(KEY_MAX+7)/8];
145       BYTE      evbits[(EV_MAX+7)/8],ffbits[(FF_MAX+7)/8];
146
147       sprintf(buf,EVDEVPREFIX"%d",i);
148
149       if (require_ff) 
150           flags = O_RDWR;
151       else
152           flags = O_RDONLY;
153
154       if (-1!=(fd=open(buf,flags))) {
155           if (-1==ioctl(fd,EVIOCGBIT(EV_ABS,sizeof(absbits)),absbits)) {
156               perror("EVIOCGBIT EV_ABS");
157               close(fd);
158               continue;
159           }
160           if (-1==ioctl(fd,EVIOCGBIT(EV_KEY,sizeof(keybits)),keybits)) {
161               perror("EVIOCGBIT EV_KEY");
162               close(fd);
163               continue;
164           }
165
166           /* test for force feedback if it's required */
167           if (require_ff) {
168               if ((-1==ioctl(fd,EVIOCGBIT(0,sizeof(evbits)),evbits))) {
169                   perror("EVIOCGBIT 0");
170                   close(fd);
171                   continue; 
172               }
173               if (   (!test_bit(evbits,EV_FF))
174                   || (-1==ioctl(fd,EVIOCGBIT(EV_FF,sizeof(ffbits)),ffbits)) 
175                   || (-1==ioctl(fd,EVIOCGEFFECTS,&num_effects))
176                   || (num_effects <= 0)) {
177                   close(fd);
178                   continue;
179               }
180           }
181
182           /* A true joystick has at least axis X and Y, and at least 1
183            * button. copied from linux/drivers/input/joydev.c */
184           if (test_bit(absbits,ABS_X) && test_bit(absbits,ABS_Y) &&
185               (   test_bit(keybits,BTN_TRIGGER) ||
186                   test_bit(keybits,BTN_A)       ||
187                   test_bit(keybits,BTN_1)
188               )
189           ) {
190               FIXME("found a joystick at %s!\n",buf);
191               havejoy = 1;
192           }
193           close(fd);
194       }
195       if (havejoy || (errno==ENODEV))
196           break;
197   }
198   return havejoy;
199 }
200
201 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
202 {
203   int havejoy = 0;
204
205   if (id != 0)
206       return FALSE;
207
208   if (!((dwDevType == 0) ||
209         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 0x0800)) ||
210         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
211     return FALSE;
212
213 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
214   if (dwFlags & DIEDFL_FORCEFEEDBACK)
215     return FALSE;
216 #endif
217
218   havejoy = joydev_have(dwFlags & DIEDFL_FORCEFEEDBACK);
219
220   if (!havejoy)
221       return FALSE;
222
223   TRACE("Enumerating the linuxinput Joystick device\n");
224
225   /* Return joystick */
226   lpddi->guidInstance   = GUID_Joystick;
227   lpddi->guidProduct    = DInput_Wine_Joystick_GUID;
228
229   lpddi->guidFFDriver = GUID_NULL;
230   if (version >= 0x0800)
231     lpddi->dwDevType    = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
232   else
233     lpddi->dwDevType    = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
234
235   strcpy(lpddi->tszInstanceName, "Joystick");
236   /* ioctl JSIOCGNAME(len) */
237   strcpy(lpddi->tszProductName, "Wine Joystick");
238   return TRUE;
239 }
240
241 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
242 {
243   int havejoy = 0;
244
245   if (id != 0)
246       return FALSE;
247
248   if (!((dwDevType == 0) ||
249         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 0x0800)) ||
250         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
251     return FALSE;
252
253 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
254   if (dwFlags & DIEDFL_FORCEFEEDBACK)
255     return FALSE;
256 #endif
257
258   havejoy = joydev_have(dwFlags & DIEDFL_FORCEFEEDBACK);
259
260   if (!havejoy)
261       return FALSE;
262
263   TRACE("Enumerating the linuxinput Joystick device\n");
264
265   /* Return joystick */
266   lpddi->guidInstance   = GUID_Joystick;
267   lpddi->guidProduct    = DInput_Wine_Joystick_GUID;
268
269   lpddi->guidFFDriver = GUID_NULL;
270   if (version >= 0x0800)
271     lpddi->dwDevType    = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
272   else
273     lpddi->dwDevType    = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
274
275   MultiByteToWideChar(CP_ACP, 0, "Joystick", -1, lpddi->tszInstanceName, MAX_PATH);
276   /* ioctl JSIOCGNAME(len) */
277   MultiByteToWideChar(CP_ACP, 0, "Wine Joystick", -1, lpddi->tszProductName, MAX_PATH);
278   return TRUE;
279 }
280
281 static JoystickImpl *alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput)
282 {
283   JoystickImpl* newDevice;
284   int i;
285
286   newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
287   newDevice->lpVtbl = jvt;
288   newDevice->ref = 1;
289   newDevice->joyfd = -1;
290   newDevice->dinput = dinput;
291   memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
292   for (i=0;i<ABS_MAX;i++) {
293     newDevice->wantmin[i] = -32768;
294     newDevice->wantmax[i] =  32767;
295     /* TODO: 
296      * direct input defines a default for the deadzone somewhere; but as long
297      * as in map_axis the code for the dead zone is commented out its no
298      * problem
299      */
300     newDevice->deadz[i]   =  0;
301   }
302   fake_current_js_state(newDevice);
303   return newDevice;
304 }
305
306 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
307 {
308   int havejoy = 0;
309
310   havejoy = joydev_have(FALSE);
311
312   if (!havejoy)
313       return DIERR_DEVICENOTREG;
314
315   if ((IsEqualGUID(&GUID_Joystick,rguid)) ||
316       (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) {
317     if ((riid == NULL) ||
318         IsEqualGUID(&IID_IDirectInputDeviceA,riid) ||
319         IsEqualGUID(&IID_IDirectInputDevice2A,riid) ||
320         IsEqualGUID(&IID_IDirectInputDevice7A,riid) ||
321         IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
322       *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &JoystickAvt, dinput);
323       TRACE("Creating a Joystick device (%p)\n", *pdev);
324       return DI_OK;
325     } else
326       return DIERR_NOINTERFACE;
327   }
328
329   return DIERR_DEVICENOTREG;
330 }
331
332
333 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
334 {
335   int havejoy = 0;
336
337   havejoy = joydev_have(FALSE);
338
339   if (!havejoy)
340       return DIERR_DEVICENOTREG;
341
342   if ((IsEqualGUID(&GUID_Joystick,rguid)) ||
343       (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) {
344     if ((riid == NULL) ||
345         IsEqualGUID(&IID_IDirectInputDeviceW,riid) ||
346         IsEqualGUID(&IID_IDirectInputDevice2W,riid) ||
347         IsEqualGUID(&IID_IDirectInputDevice7W,riid) ||
348         IsEqualGUID(&IID_IDirectInputDevice8W,riid)) {
349       *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &JoystickWvt, dinput);
350       TRACE("Creating a Joystick device (%p)\n", *pdev);
351       return DI_OK;
352     } else
353       return DIERR_NOINTERFACE;
354   }
355
356   return DIERR_DEVICENOTREG;
357 }
358
359 const struct dinput_device joystick_linuxinput_device = {
360   "Wine Linux-input joystick driver",
361   joydev_enum_deviceA,
362   joydev_enum_deviceW,
363   joydev_create_deviceA,
364   joydev_create_deviceW
365 };
366
367 /******************************************************************************
368  *      Joystick
369  */
370 static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface)
371 {
372         JoystickImpl *This = (JoystickImpl *)iface;
373         ULONG ref;
374
375         ref = InterlockedDecrement(&(This->ref));
376         if (ref)
377                 return ref;
378
379         /* Free the data queue */
380         HeapFree(GetProcessHeap(),0,This->data_queue);
381
382         /* Free the DataFormat */
383         HeapFree(GetProcessHeap(), 0, This->df);
384
385         HeapFree(GetProcessHeap(),0,This);
386         return 0;
387 }
388
389 /******************************************************************************
390   *   SetDataFormat : the application can choose the format of the data
391   *   the device driver sends back with GetDeviceState.
392   */
393 static HRESULT WINAPI JoystickAImpl_SetDataFormat(
394         LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df
395 )
396 {
397   JoystickImpl *This = (JoystickImpl *)iface;
398
399   TRACE("(this=%p,%p)\n",This,df);
400
401   _dump_DIDATAFORMAT(df);
402   
403   /* Store the new data format */
404   This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
405   memcpy(This->df, df, df->dwSize);
406   This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
407   memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
408
409   return 0;
410 }
411
412 /******************************************************************************
413   *     Acquire : gets exclusive control of the joystick
414   */
415 static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
416 {
417     int         i;
418     JoystickImpl *This = (JoystickImpl *)iface;
419     char        buf[200];
420     BOOL        readonly = TRUE;
421
422     TRACE("(this=%p)\n",This);
423     if (This->joyfd!=-1)
424         return 0;
425     for (i=0;i<64;i++) {
426       sprintf(buf,EVDEVPREFIX"%d",i);
427       if (-1==(This->joyfd=open(buf,O_RDWR))) { 
428         if (-1==(This->joyfd=open(buf,O_RDONLY))) {
429           /* Couldn't open the device at all */ 
430           if (errno==ENODEV)
431             return DIERR_NOTFOUND;
432           perror(buf);
433           continue;
434         }
435         else {
436           /* Couldn't open in r/w but opened in read-only. */
437           WARN("Could not open %s in read-write mode.  Force feedback will be disabled.\n",buf);
438         }
439       }
440       else {
441         /* Opened device in read-write */
442         readonly = FALSE;
443       }
444       if ((-1!=ioctl(This->joyfd,EVIOCGBIT(0,sizeof(This->evbits)),This->evbits)) &&
445           (-1!=ioctl(This->joyfd,EVIOCGBIT(EV_ABS,sizeof(This->absbits)),This->absbits)) &&
446           (-1!=ioctl(This->joyfd,EVIOCGBIT(EV_KEY,sizeof(This->keybits)),This->keybits)) &&
447           (test_bit(This->absbits,ABS_X) && test_bit(This->absbits,ABS_Y) &&
448            (test_bit(This->keybits,BTN_TRIGGER)||
449             test_bit(This->keybits,BTN_A)        ||
450             test_bit(This->keybits,BTN_1)
451           )
452          )
453       )
454         break;
455       close(This->joyfd);
456       This->joyfd = -1;
457     }
458     if (This->joyfd==-1)
459         return DIERR_NOTFOUND;
460
461     This->has_ff = FALSE;
462     This->num_effects = 0;
463
464 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
465     if (!readonly && test_bit(This->evbits, EV_FF)) {
466         if (-1!=ioctl(This->joyfd,EVIOCGBIT(EV_FF,sizeof(This->ffbits)),This->ffbits)) {
467             if (-1!=ioctl(This->joyfd,EVIOCGEFFECTS,&This->num_effects) 
468                 && This->num_effects > 0) {
469                 This->has_ff = TRUE;
470                 TRACE("Joystick seems to be capable of force feedback.\n");
471             }
472             else {
473                 TRACE("Joystick does not support any effects, disabling force feedback.\n");
474             }
475         }
476         else {
477             TRACE("Could not get EV_FF bits; disabling force feedback.\n");
478         }
479     }
480     else {
481         TRACE("Force feedback disabled (device is readonly or joystick incapable).\n");
482     }
483 #endif
484
485     for (i=0;i<ABS_MAX;i++) {
486         if (test_bit(This->absbits,i)) {
487           if (-1==ioctl(This->joyfd,EVIOCGABS(i),&(This->axes[i])))
488             continue;
489           FIXME("axe %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n",
490               i,
491               This->axes[i][AXE_ABS],
492               This->axes[i][AXE_ABSMIN],
493               This->axes[i][AXE_ABSMAX],
494               This->axes[i][AXE_ABSFUZZ],
495               This->axes[i][AXE_ABSFLAT]
496           );
497           This->havemin[i] = This->axes[i][AXE_ABSMIN];
498           This->havemax[i] = This->axes[i][AXE_ABSMAX];
499         }
500     }
501     MESSAGE("\n");
502
503         fake_current_js_state(This);
504
505     return 0;
506 }
507
508 /******************************************************************************
509   *     Unacquire : frees the joystick
510   */
511 static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
512 {
513     JoystickImpl *This = (JoystickImpl *)iface;
514
515     TRACE("(this=%p)\n",This);
516     if (This->joyfd!=-1) {
517         close(This->joyfd);
518         This->joyfd = -1;
519         return DI_OK;
520     }
521     else 
522         return DI_NOEFFECT;
523 }
524
525 /*
526  * This maps the read value (from the input event) to a value in the
527  * 'wanted' range. It also autodetects the possible range of the axe and
528  * adapts values accordingly.
529  */
530 static int
531 map_axis(JoystickImpl* This, int axis, int val) {
532     int xmin = This->axes[axis][AXE_ABSMIN];
533     int xmax = This->axes[axis][AXE_ABSMAX];
534     int hmax = This->havemax[axis];
535     int hmin = This->havemin[axis];
536     int wmin = This->wantmin[axis];
537     int wmax = This->wantmax[axis];
538     int ret;
539
540     if (val > hmax) This->havemax[axis] = hmax = val;
541     if (val < hmin) This->havemin[axis] = hmin = val;
542
543     if (xmin == xmax) return val;
544
545     /* map the value from the hmin-hmax range into the wmin-wmax range */
546     ret = ((val-hmin) * (wmax-wmin)) / (hmax-hmin) + wmin;
547
548     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);
549
550 #if 0
551     /* deadzone doesn't work comfortably enough right now. needs more testing*/
552     if ((ret > -deadz/2 ) && (ret < deadz/2)) {
553         FIXME("%d in deadzone, return mid.\n",val);
554         return (wmax-wmin)/2+wmin;
555     }
556 #endif
557     return ret;
558 }
559
560 /* 
561  * set the current state of the js device as it would be with the middle
562  * values on the axes
563  */
564 static void fake_current_js_state(JoystickImpl *ji)
565 {
566         ji->js.lX  = map_axis(ji, ABS_X,  ji->axes[ABS_X ][AXE_ABS]);
567         ji->js.lY  = map_axis(ji, ABS_Y,  ji->axes[ABS_Y ][AXE_ABS]);
568         ji->js.lZ  = map_axis(ji, ABS_Z,  ji->axes[ABS_Z ][AXE_ABS]);
569         ji->js.lRx = map_axis(ji, ABS_RX, ji->axes[ABS_RX][AXE_ABS]);
570         ji->js.lRy = map_axis(ji, ABS_RY, ji->axes[ABS_RY][AXE_ABS]);
571         ji->js.lRz = map_axis(ji, ABS_RZ, ji->axes[ABS_RZ][AXE_ABS]);
572         ji->js.rglSlider[0] = map_axis(ji, ABS_THROTTLE, ji->axes[ABS_THROTTLE][AXE_ABS]);
573         ji->js.rglSlider[1] = map_axis(ji, ABS_RUDDER,   ji->axes[ABS_RUDDER  ][AXE_ABS]);
574 }
575
576 static void joy_polldev(JoystickImpl *This) {
577     struct timeval tv;
578     fd_set      readfds;
579     struct      input_event ie;
580
581     if (This->joyfd==-1)
582         return;
583
584     while (1) {
585         memset(&tv,0,sizeof(tv));
586         FD_ZERO(&readfds);
587         FD_SET(This->joyfd,&readfds);
588
589         if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv))
590             return;
591
592         /* we have one event, so we can read */
593         if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie)))
594             return;
595
596         TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value);
597         switch (ie.type) {
598         case EV_KEY:    /* button */
599             switch (ie.code) {
600             case BTN_TRIGGER:   /* normal flight stick */
601             case BTN_A:         /* gamepad */
602             case BTN_1:         /* generic */
603                 This->js.rgbButtons[0] = ie.value?0x80:0x00;
604                 GEN_EVENT(DIJOFS_BUTTON(0),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
605                 break;
606             case BTN_THUMB:
607             case BTN_B:
608             case BTN_2:
609                 This->js.rgbButtons[1] = ie.value?0x80:0x00;
610                 GEN_EVENT(DIJOFS_BUTTON(1),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
611                 break;
612             case BTN_THUMB2:
613             case BTN_C:
614             case BTN_3:
615                 This->js.rgbButtons[2] = ie.value?0x80:0x00;
616                 GEN_EVENT(DIJOFS_BUTTON(2),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
617                 break;
618             case BTN_TOP:
619             case BTN_X:
620             case BTN_4:
621                 This->js.rgbButtons[3] = ie.value?0x80:0x00;
622                 GEN_EVENT(DIJOFS_BUTTON(3),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
623                 break;
624             case BTN_TOP2:
625             case BTN_Y:
626             case BTN_5:
627                 This->js.rgbButtons[4] = ie.value?0x80:0x00;
628                 GEN_EVENT(DIJOFS_BUTTON(4),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
629                 break;
630             case BTN_PINKIE:
631             case BTN_Z:
632             case BTN_6:
633                 This->js.rgbButtons[5] = ie.value?0x80:0x00;
634                 GEN_EVENT(DIJOFS_BUTTON(5),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
635                 break;
636             case BTN_BASE:
637             case BTN_TL:
638             case BTN_7:
639                 This->js.rgbButtons[6] = ie.value?0x80:0x00;
640                 GEN_EVENT(DIJOFS_BUTTON(6),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
641                 break;
642             case BTN_BASE2:
643             case BTN_TR:
644             case BTN_8:
645                 This->js.rgbButtons[7] = ie.value?0x80:0x00;
646                 GEN_EVENT(DIJOFS_BUTTON(7),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
647                 break;
648             case BTN_BASE3:
649             case BTN_TL2:
650             case BTN_9:
651                 This->js.rgbButtons[8] = ie.value?0x80:0x00;
652                 GEN_EVENT(DIJOFS_BUTTON(8),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
653                 break;
654             case BTN_BASE4:
655             case BTN_TR2:
656                 This->js.rgbButtons[9] = ie.value?0x80:0x00;
657                 GEN_EVENT(DIJOFS_BUTTON(9),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
658                 break;
659             case BTN_BASE5:
660             case BTN_SELECT:
661                 This->js.rgbButtons[10] = ie.value?0x80:0x00;
662                 GEN_EVENT(DIJOFS_BUTTON(10),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++);
663                 break;
664             default:
665                 FIXME("unhandled joystick button %x, value %d\n",ie.code,ie.value);
666                 break;
667             }
668             break;
669         case EV_ABS:
670             switch (ie.code) {
671             case ABS_X:
672                 This->js.lX = map_axis(This,ABS_X,ie.value);
673                 GEN_EVENT(DIJOFS_X,This->js.lX,ie.time.tv_usec,(This->dinput->evsequence)++);
674                 break;
675             case ABS_Y:
676                 This->js.lY = map_axis(This,ABS_Y,ie.value);
677                 GEN_EVENT(DIJOFS_Y,This->js.lY,ie.time.tv_usec,(This->dinput->evsequence)++);
678                 break;
679             case ABS_Z:
680                 This->js.lZ = map_axis(This,ABS_Z,ie.value);
681                 GEN_EVENT(DIJOFS_Z,This->js.lZ,ie.time.tv_usec,(This->dinput->evsequence)++);
682                 break;
683             case ABS_RX:
684                 This->js.lRx = map_axis(This,ABS_RX,ie.value);
685                 GEN_EVENT(DIJOFS_RX,This->js.lRx,ie.time.tv_usec,(This->dinput->evsequence)++);
686                 break;
687             case ABS_RY:
688                 This->js.lRy = map_axis(This,ABS_RY,ie.value);
689                 GEN_EVENT(DIJOFS_RY,This->js.lRy,ie.time.tv_usec,(This->dinput->evsequence)++);
690                 break;
691             case ABS_RZ:
692                 This->js.lRz = map_axis(This,ABS_RZ,ie.value);
693                 GEN_EVENT(DIJOFS_RZ,This->js.lRz,ie.time.tv_usec,(This->dinput->evsequence)++);
694                 break;
695             case ABS_THROTTLE:
696                 This->js.rglSlider[0] = map_axis(This,ABS_THROTTLE,ie.value);
697                 GEN_EVENT(DIJOFS_SLIDER(0),This->js.rglSlider[0],ie.time.tv_usec,(This->dinput->evsequence)++);
698                 break;
699             case ABS_RUDDER:
700                 This->js.rglSlider[1] = map_axis(This,ABS_RUDDER,ie.value);
701                 GEN_EVENT(DIJOFS_SLIDER(1),This->js.rglSlider[1],ie.time.tv_usec,(This->dinput->evsequence)++);
702                 break;
703             default:
704                 FIXME("unhandled joystick axe event (code %d, value %d)\n",ie.code,ie.value);
705                 break;
706             }
707             break;
708         default:
709             FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code);
710             break;
711         }
712     }
713 }
714
715 /******************************************************************************
716   *     GetDeviceState : returns the "state" of the joystick.
717   *
718   */
719 static HRESULT WINAPI JoystickAImpl_GetDeviceState(
720         LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr
721 ) {
722     JoystickImpl *This = (JoystickImpl *)iface;
723
724     joy_polldev(This);
725
726     TRACE("(this=%p,0x%08lx,%p)\n",This,len,ptr);
727     if ((len != sizeof(DIJOYSTATE)) && (len != sizeof(DIJOYSTATE2))) {
728         FIXME("len %ld is not sizeof(DIJOYSTATE) or DIJOYSTATE2, unsupported format.\n",len);
729         return E_FAIL;
730     }
731     memcpy(ptr,&(This->js),len);
732     This->queue_head = 0;
733     This->queue_tail = 0;
734     return 0;
735 }
736
737 /******************************************************************************
738   *     GetDeviceData : gets buffered input data.
739   */
740 static HRESULT WINAPI JoystickAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface,
741                                               DWORD dodsize,
742                                               LPDIDEVICEOBJECTDATA dod,
743                                               LPDWORD entries,
744                                               DWORD flags
745 ) {
746   JoystickImpl *This = (JoystickImpl *)iface;
747
748   FIXME("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx),STUB!\n",This,dodsize,*entries,flags);
749
750   joy_polldev(This);
751   if (flags & DIGDD_PEEK)
752     FIXME("DIGDD_PEEK\n");
753
754   if (dod == NULL) {
755   } else {
756   }
757   return 0;
758 }
759
760 /******************************************************************************
761   *     SetProperty : change input device properties
762   */
763 static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface,
764                                             REFGUID rguid,
765                                             LPCDIPROPHEADER ph)
766 {
767   JoystickImpl *This = (JoystickImpl *)iface;
768
769   FIXME("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
770   FIXME("ph.dwSize = %ld, ph.dwHeaderSize =%ld, ph.dwObj = %ld, ph.dwHow= %ld\n",ph->dwSize, ph->dwHeaderSize,ph->dwObj,ph->dwHow);
771
772   if (!HIWORD(rguid)) {
773     switch ((DWORD)rguid) {
774     case (DWORD) DIPROP_BUFFERSIZE: {
775       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
776
777       FIXME("buffersize = %ld\n",pd->dwData);
778       break;
779     }
780     case (DWORD)DIPROP_RANGE: {
781       LPCDIPROPRANGE    pr = (LPCDIPROPRANGE)ph;
782
783       FIXME("proprange(%ld,%ld)\n",pr->lMin,pr->lMax);
784       switch (ph->dwObj) {
785       case 0:   /* X */
786       case 4:   /* Y */
787       case 8:   /* Z */
788       case 12:  /* Rx */
789       case 16:  /* Ry */
790       case 20:  /* Rz */
791       case 24:  /* Slider 0 -> Throttle */
792       case 28:  /* Slider 1 -> Rudder */
793           This->wantmin[ph->dwObj/4] = pr->lMin;
794           This->wantmax[ph->dwObj/4] = pr->lMax;
795           break;
796       default:
797           FIXME("setting proprange %ld - %ld for dwObj %ld\n",pr->lMin,pr->lMax,ph->dwObj);
798       }
799       break;
800     }
801     case (DWORD)DIPROP_DEADZONE: {
802       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
803
804       FIXME("setting deadzone(%ld)\n",pd->dwData);
805       This->deadz[ph->dwObj/4] = pd->dwData;
806       break;
807     }
808     default:
809       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
810       break;
811     }
812   }
813   fake_current_js_state(This);
814   return 0;
815 }
816
817 /******************************************************************************
818   *     SetEventNotification : specifies event to be sent on state change
819   */
820 static HRESULT WINAPI JoystickAImpl_SetEventNotification(
821         LPDIRECTINPUTDEVICE8A iface, HANDLE hnd
822 ) {
823     JoystickImpl *This = (JoystickImpl *)iface;
824
825     TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
826     This->hEvent = hnd;
827     return DI_OK;
828 }
829
830 static HRESULT WINAPI JoystickAImpl_GetCapabilities(
831         LPDIRECTINPUTDEVICE8A iface,
832         LPDIDEVCAPS lpDIDevCaps)
833 {
834     JoystickImpl *This = (JoystickImpl *)iface;
835     int         xfd = This->joyfd;
836     int         i,axes,buttons;
837     int         wasacquired = 1;
838
839     TRACE("%p->(%p)\n",iface,lpDIDevCaps);
840     if (xfd==-1) {
841         /* yes, games assume we return something, even if unacquired */
842         JoystickAImpl_Acquire(iface);
843         xfd = This->joyfd;
844         wasacquired = 0;
845     }
846     lpDIDevCaps->dwFlags        = DIDC_ATTACHED;
847     if (This->dinput->dwVersion >= 0x0800)
848         lpDIDevCaps->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
849     else
850         lpDIDevCaps->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
851
852     axes=0;
853     for (i=0;i<ABS_MAX;i++) if (test_bit(This->absbits,i)) axes++;
854     buttons=0;
855     for (i=0;i<KEY_MAX;i++) if (test_bit(This->keybits,i)) buttons++;
856
857     if (This->has_ff) 
858          lpDIDevCaps->dwFlags |= DIDC_FORCEFEEDBACK;
859
860     lpDIDevCaps->dwAxes = axes;
861     lpDIDevCaps->dwButtons = buttons;
862
863     if (!wasacquired)
864         JoystickAImpl_Unacquire(iface);
865
866     return DI_OK;
867 }
868
869 static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) {
870     JoystickImpl *This = (JoystickImpl *)iface;
871     TRACE("(),stub!\n");
872
873     joy_polldev(This);
874     return DI_OK;
875 }
876
877 /******************************************************************************
878   *     EnumObjects : enumerate the different buttons and axis...
879   */
880 static HRESULT WINAPI JoystickAImpl_EnumObjects(
881         LPDIRECTINPUTDEVICE8A iface,
882         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
883         LPVOID lpvRef,
884         DWORD dwFlags)
885 {
886   JoystickImpl *This = (JoystickImpl *)iface;
887   DIDEVICEOBJECTINSTANCEA ddoi;
888   int xfd = This->joyfd;
889
890
891   TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
892   if (TRACE_ON(dinput)) {
893     TRACE("  - flags = ");
894     _dump_EnumObjects_flags(dwFlags);
895     TRACE("\n");
896   }
897
898   if (xfd == -1) return DIERR_NOTACQUIRED;
899
900   /* Only the fields till dwFFMaxForce are relevant */
901   ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
902
903   /* For the joystick, do as is done in the GetCapabilities function */
904   /* FIXME: needs more items */
905   if ((dwFlags == DIDFT_ALL) ||
906       (dwFlags & DIDFT_AXIS)) {
907     BYTE i;
908
909     for (i = 0; i < ABS_MAX; i++) {
910       if (!test_bit(This->absbits,i)) continue;
911
912       switch (i) {
913       case ABS_X:
914         ddoi.guidType = GUID_XAxis;
915         ddoi.dwOfs = DIJOFS_X;
916         break;
917       case ABS_Y:
918         ddoi.guidType = GUID_YAxis;
919         ddoi.dwOfs = DIJOFS_Y;
920         break;
921       case ABS_Z:
922         ddoi.guidType = GUID_ZAxis;
923         ddoi.dwOfs = DIJOFS_Z;
924         break;
925       case ABS_RX:
926         ddoi.guidType = GUID_RxAxis;
927         ddoi.dwOfs = DIJOFS_RX;
928         break;
929       case ABS_RY:
930         ddoi.guidType = GUID_RyAxis;
931         ddoi.dwOfs = DIJOFS_RY;
932         break;
933       case ABS_RZ:
934         ddoi.guidType = GUID_RzAxis;
935         ddoi.dwOfs = DIJOFS_RZ;
936         break;
937       case ABS_THROTTLE:
938         ddoi.guidType = GUID_Slider;
939         ddoi.dwOfs = DIJOFS_SLIDER(0);
940         break;
941       case ABS_RUDDER:
942         ddoi.guidType = GUID_Slider;
943         ddoi.dwOfs = DIJOFS_SLIDER(1);
944         break;
945       default:
946         FIXME("unhandled abs axis %d, ignoring!\n",i);
947       }
948       ddoi.dwType = DIDFT_MAKEINSTANCE((1<<i) << WINE_JOYSTICK_AXIS_BASE) | DIDFT_ABSAXIS;
949       sprintf(ddoi.tszName, "%d-Axis", i);
950       _dump_OBJECTINSTANCEA(&ddoi);
951       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE)
952           return DI_OK;
953     }
954   }
955
956   if ((dwFlags == DIDFT_ALL) ||
957       (dwFlags & DIDFT_BUTTON)) {
958     int i;
959
960     /*The DInput SDK says that GUID_Button is only for mouse buttons but well*/
961
962     ddoi.guidType = GUID_Button;
963
964     for (i = 0; i < KEY_MAX; i++) {
965       if (!test_bit(This->keybits,i)) continue;
966
967       switch (i) {
968       case BTN_TRIGGER:
969       case BTN_A:
970       case BTN_1:
971           ddoi.dwOfs = DIJOFS_BUTTON(0);
972           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 0) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
973           break;
974         case BTN_THUMB:
975         case BTN_B:
976         case BTN_2:
977           ddoi.dwOfs = DIJOFS_BUTTON(1);
978           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 1) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
979           break;
980         case BTN_THUMB2:
981         case BTN_C:
982         case BTN_3:
983           ddoi.dwOfs = DIJOFS_BUTTON(2);
984           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 2) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
985           break;
986         case BTN_TOP:
987         case BTN_X:
988         case BTN_4:
989           ddoi.dwOfs = DIJOFS_BUTTON(3);
990           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 3) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
991           break;
992         case BTN_TOP2:
993         case BTN_Y:
994         case BTN_5:
995           ddoi.dwOfs = DIJOFS_BUTTON(4);
996           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 4) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
997           break;
998         case BTN_PINKIE:
999         case BTN_Z:
1000         case BTN_6:
1001           ddoi.dwOfs = DIJOFS_BUTTON(5);
1002           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 5) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1003           break;
1004         case BTN_BASE:
1005         case BTN_TL:
1006         case BTN_7:
1007           ddoi.dwOfs = DIJOFS_BUTTON(6);
1008           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 6) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1009           break;
1010         case BTN_BASE2:
1011         case BTN_TR:
1012         case BTN_8:
1013           ddoi.dwOfs = DIJOFS_BUTTON(7);
1014           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 7) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1015           break;
1016         case BTN_BASE3:
1017         case BTN_TL2:
1018         case BTN_9:
1019           ddoi.dwOfs = DIJOFS_BUTTON(8);
1020           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 8) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1021           break;
1022         case BTN_BASE4:
1023         case BTN_TR2:
1024           ddoi.dwOfs = DIJOFS_BUTTON(9);
1025           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 9) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1026           break;
1027         case BTN_BASE5:
1028         case BTN_SELECT:
1029           ddoi.dwOfs = DIJOFS_BUTTON(10);
1030           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 10) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1031           break;
1032       }
1033       sprintf(ddoi.tszName, "%d-Button", i);
1034       _dump_OBJECTINSTANCEA(&ddoi);
1035       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE)
1036           return DI_OK;
1037     }
1038   }
1039
1040   if (xfd!=This->joyfd)
1041     close(xfd);
1042
1043   return DI_OK;
1044 }
1045
1046 static HRESULT WINAPI JoystickWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface,
1047                                                 LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback,
1048                                                 LPVOID lpvRef,
1049                                                 DWORD dwFlags)
1050 {
1051   JoystickImpl *This = (JoystickImpl *)iface;
1052
1053   device_enumobjects_AtoWcb_data data;
1054
1055   data.lpCallBack = lpCallback;
1056   data.lpvRef = lpvRef;
1057
1058   return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags);
1059 }
1060
1061 /******************************************************************************
1062   *     GetProperty : get input device properties
1063   */
1064 static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
1065                                                 REFGUID rguid,
1066                                                 LPDIPROPHEADER pdiph)
1067 {
1068   JoystickImpl *This = (JoystickImpl *)iface;
1069
1070   TRACE("(this=%p,%s,%p)\n",
1071         iface, debugstr_guid(rguid), pdiph);
1072
1073   if (TRACE_ON(dinput))
1074     _dump_DIPROPHEADER(pdiph);
1075
1076   if (!HIWORD(rguid)) {
1077     switch ((DWORD)rguid) {
1078     case (DWORD) DIPROP_BUFFERSIZE: {
1079       LPDIPROPDWORD     pd = (LPDIPROPDWORD)pdiph;
1080
1081       TRACE(" return buffersize = %d\n",This->queue_len);
1082       pd->dwData = This->queue_len;
1083       break;
1084     }
1085
1086     case (DWORD) DIPROP_RANGE: {
1087       /* LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; */
1088       if ((pdiph->dwHow == DIPH_BYID) &&
1089           (pdiph->dwObj & DIDFT_ABSAXIS)) {
1090         /* The app is querying the current range of the axis : return the lMin and lMax values */
1091         FIXME("unimplemented axis range query.\n");
1092       }
1093
1094       break;
1095     }
1096
1097     default:
1098       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
1099       break;
1100     }
1101   }
1102
1103
1104   return DI_OK;
1105 }
1106
1107 static const IDirectInputDevice8AVtbl JoystickAvt =
1108 {
1109         IDirectInputDevice2AImpl_QueryInterface,
1110         IDirectInputDevice2AImpl_AddRef,
1111         JoystickAImpl_Release,
1112         JoystickAImpl_GetCapabilities,
1113         JoystickAImpl_EnumObjects,
1114         JoystickAImpl_GetProperty,
1115         JoystickAImpl_SetProperty,
1116         JoystickAImpl_Acquire,
1117         JoystickAImpl_Unacquire,
1118         JoystickAImpl_GetDeviceState,
1119         JoystickAImpl_GetDeviceData,
1120         JoystickAImpl_SetDataFormat,
1121         JoystickAImpl_SetEventNotification,
1122         IDirectInputDevice2AImpl_SetCooperativeLevel,
1123         IDirectInputDevice2AImpl_GetObjectInfo,
1124         IDirectInputDevice2AImpl_GetDeviceInfo,
1125         IDirectInputDevice2AImpl_RunControlPanel,
1126         IDirectInputDevice2AImpl_Initialize,
1127         IDirectInputDevice2AImpl_CreateEffect,
1128         IDirectInputDevice2AImpl_EnumEffects,
1129         IDirectInputDevice2AImpl_GetEffectInfo,
1130         IDirectInputDevice2AImpl_GetForceFeedbackState,
1131         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1132         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1133         IDirectInputDevice2AImpl_Escape,
1134         JoystickAImpl_Poll,
1135         IDirectInputDevice2AImpl_SendDeviceData,
1136         IDirectInputDevice7AImpl_EnumEffectsInFile,
1137         IDirectInputDevice7AImpl_WriteEffectToFile,
1138         IDirectInputDevice8AImpl_BuildActionMap,
1139         IDirectInputDevice8AImpl_SetActionMap,
1140         IDirectInputDevice8AImpl_GetImageInfo
1141 };
1142
1143 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
1144 # define XCAST(fun)     (typeof(JoystickWvt.fun))
1145 #else
1146 # define XCAST(fun)     (void*)
1147 #endif
1148
1149 static const IDirectInputDevice8WVtbl JoystickWvt =
1150 {
1151         IDirectInputDevice2WImpl_QueryInterface,
1152         XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
1153         XCAST(Release)JoystickAImpl_Release,
1154         XCAST(GetCapabilities)JoystickAImpl_GetCapabilities,
1155         JoystickWImpl_EnumObjects,
1156         XCAST(GetProperty)JoystickAImpl_GetProperty,
1157         XCAST(SetProperty)JoystickAImpl_SetProperty,
1158         XCAST(Acquire)JoystickAImpl_Acquire,
1159         XCAST(Unacquire)JoystickAImpl_Unacquire,
1160         XCAST(GetDeviceState)JoystickAImpl_GetDeviceState,
1161         XCAST(GetDeviceData)JoystickAImpl_GetDeviceData,
1162         XCAST(SetDataFormat)JoystickAImpl_SetDataFormat,
1163         XCAST(SetEventNotification)JoystickAImpl_SetEventNotification,
1164         XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
1165         IDirectInputDevice2WImpl_GetObjectInfo,
1166         IDirectInputDevice2WImpl_GetDeviceInfo,
1167         XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
1168         XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
1169         XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
1170         IDirectInputDevice2WImpl_EnumEffects,
1171         IDirectInputDevice2WImpl_GetEffectInfo,
1172         XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
1173         XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1174         XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1175         XCAST(Escape)IDirectInputDevice2AImpl_Escape,
1176         XCAST(Poll)JoystickAImpl_Poll,
1177         XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
1178         IDirectInputDevice7WImpl_EnumEffectsInFile,
1179         IDirectInputDevice7WImpl_WriteEffectToFile,
1180         IDirectInputDevice8WImpl_BuildActionMap,
1181         IDirectInputDevice8WImpl_SetActionMap,
1182         IDirectInputDevice8WImpl_GetImageInfo
1183 };
1184 #undef XCAST
1185
1186 #else  /* HAVE_CORRECT_LINUXINPUT_H */
1187
1188 const struct dinput_device joystick_linuxinput_device = {
1189   "Wine Linux-input joystick driver",
1190   NULL,
1191   NULL,
1192   NULL,
1193   NULL
1194 };
1195
1196 #endif  /* HAVE_CORRECT_LINUXINPUT_H */