comctl32: Fix error handling in PSM_ADDPAGE in case of memory
[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   if (df == NULL) {
423     WARN("invalid pointer\n");
424     return E_POINTER;
425   }
426
427   if (df->dwSize != sizeof(*df)) {
428     WARN("invalid argument\n");
429     return DIERR_INVALIDPARAM;
430   }
431
432   _dump_DIDATAFORMAT(df);
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 won't 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   if (!ph) {
910     WARN("invalid argument\n");
911     return DIERR_INVALIDPARAM;
912   }
913
914   TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
915   TRACE("ph.dwSize = %ld, ph.dwHeaderSize =%ld, ph.dwObj = %ld, ph.dwHow= %ld\n",ph->dwSize, ph->dwHeaderSize,ph->dwObj,ph->dwHow);
916
917   if (!HIWORD(rguid)) {
918     switch (LOWORD(rguid)) {
919     case (DWORD) DIPROP_BUFFERSIZE: {
920       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
921
922       TRACE("buffersize = %ld\n",pd->dwData);
923       if (This->data_queue) {
924         This->data_queue = HeapReAlloc(GetProcessHeap(),0, This->data_queue, pd->dwData * sizeof(DIDEVICEOBJECTDATA));
925       } else {
926         This->data_queue = HeapAlloc(GetProcessHeap(),0, pd->dwData * sizeof(DIDEVICEOBJECTDATA));
927       }
928       This->queue_head = 0;
929       This->queue_tail = 0;
930       This->queue_len  = pd->dwData;
931       break;
932     }
933     case (DWORD)DIPROP_RANGE: {
934       LPCDIPROPRANGE    pr = (LPCDIPROPRANGE)ph;
935
936       if (ph->dwHow == DIPH_DEVICE) {
937         int i;
938         TRACE("proprange(%ld,%ld) all\n",pr->lMin,pr->lMax);
939         for (i = 0; i < This->df->dwNumObjs; i++) {
940           This->wantmin[i] = pr->lMin;
941           This->wantmax[i] = pr->lMax;
942         }
943       } else {
944         int obj = find_property_offset(This, ph);
945         TRACE("proprange(%ld,%ld) obj=%d\n",pr->lMin,pr->lMax,obj);
946         if (obj >= 0) {
947           This->wantmin[obj] = pr->lMin;
948           This->wantmax[obj] = pr->lMax;
949         }
950       }
951       return DI_OK;
952     }
953     case (DWORD)DIPROP_DEADZONE: {
954       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
955       if (ph->dwHow == DIPH_DEVICE) {
956         int i;
957         TRACE("deadzone(%ld) all\n",pd->dwData);
958         for (i = 0; i < This->df->dwNumObjs; i++) {
959           This->deadz[i] = pd->dwData;
960         }
961       } else {
962         int obj = find_property_offset(This, ph);
963         TRACE("deadzone(%ld) obj=%d\n",pd->dwData,obj);
964         if (obj >= 0) {
965           This->deadz[obj] = pd->dwData;
966         }
967       }
968       return DI_OK;
969     }
970     default:
971       FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid));
972       break;
973     }
974   }
975   fake_current_js_state(This);
976   return 0;
977 }
978
979 /******************************************************************************
980   *     SetEventNotification : specifies event to be sent on state change
981   */
982 static HRESULT WINAPI JoystickAImpl_SetEventNotification(
983         LPDIRECTINPUTDEVICE8A iface, HANDLE hnd
984 ) {
985     JoystickImpl *This = (JoystickImpl *)iface;
986
987     TRACE("(this=%p,%p)\n",This,hnd);
988     This->hEvent = hnd;
989     return DI_OK;
990 }
991
992 static HRESULT WINAPI JoystickAImpl_GetCapabilities(
993         LPDIRECTINPUTDEVICE8A iface,
994         LPDIDEVCAPS lpDIDevCaps)
995 {
996     JoystickImpl *This = (JoystickImpl *)iface;
997     int         xfd = This->joyfd;
998     int         i,axes,buttons;
999
1000     TRACE("%p->(%p)\n",iface,lpDIDevCaps);
1001
1002     if (!lpDIDevCaps) {
1003         WARN("invalid pointer\n");
1004         return E_POINTER;
1005     }
1006
1007     if (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) {
1008         WARN("invalid argument\n");
1009         return DIERR_INVALIDPARAM;
1010     }
1011
1012     if (xfd==-1) {
1013         /* yes, games assume we return something, even if unacquired */
1014         JoystickAImpl_Acquire(iface);
1015     }
1016
1017     lpDIDevCaps->dwFlags        = DIDC_ATTACHED;
1018     if (This->dinput->dwVersion >= 0x0800)
1019         lpDIDevCaps->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
1020     else
1021         lpDIDevCaps->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
1022
1023     axes=0;
1024     for (i=0;i<ABS_MAX;i++) if (test_bit(This->absbits,i)) axes++;
1025     buttons=0;
1026     for (i=0;i<KEY_MAX;i++) if (test_bit(This->keybits,i)) buttons++;
1027
1028     if (This->has_ff) 
1029          lpDIDevCaps->dwFlags |= DIDC_FORCEFEEDBACK;
1030
1031     lpDIDevCaps->dwAxes = axes;
1032     lpDIDevCaps->dwButtons = buttons;
1033
1034     if (xfd==-1) {
1035       JoystickAImpl_Unacquire(iface);
1036     }
1037
1038     return DI_OK;
1039 }
1040
1041 static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) {
1042     JoystickImpl *This = (JoystickImpl *)iface;
1043     TRACE("(%p)\n",This);
1044
1045     if (This->joyfd==-1) {
1046       return DIERR_NOTACQUIRED;
1047     }
1048
1049     joy_polldev(This);
1050     return DI_OK;
1051 }
1052
1053 /******************************************************************************
1054   *     EnumObjects : enumerate the different buttons and axis...
1055   */
1056 static HRESULT WINAPI JoystickAImpl_EnumObjects(
1057         LPDIRECTINPUTDEVICE8A iface,
1058         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
1059         LPVOID lpvRef,
1060         DWORD dwFlags)
1061 {
1062   JoystickImpl *This = (JoystickImpl *)iface;
1063   DIDEVICEOBJECTINSTANCEA ddoi;
1064   int xfd = This->joyfd;
1065
1066   TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
1067   if (TRACE_ON(dinput)) {
1068     TRACE("  - flags = ");
1069     _dump_EnumObjects_flags(dwFlags);
1070     TRACE("\n");
1071   }
1072
1073   /* We need to work even if we're not yet acquired */
1074   if (xfd == -1)
1075     IDirectInputDevice8_Acquire(iface);
1076
1077   /* Only the fields till dwFFMaxForce are relevant */
1078   ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
1079
1080   /* For the joystick, do as is done in the GetCapabilities function */
1081   /* FIXME: needs more items */
1082   if ((dwFlags == DIDFT_ALL) ||
1083       (dwFlags & DIDFT_AXIS)) {
1084     BYTE i;
1085
1086     for (i = 0; i < ABS_MAX; i++) {
1087       if (!test_bit(This->absbits,i)) continue;
1088
1089       switch (i) {
1090       case ABS_X:
1091         ddoi.guidType = GUID_XAxis;
1092         ddoi.dwOfs = DIJOFS_X;
1093         break;
1094       case ABS_Y:
1095         ddoi.guidType = GUID_YAxis;
1096         ddoi.dwOfs = DIJOFS_Y;
1097         break;
1098       case ABS_Z:
1099         ddoi.guidType = GUID_ZAxis;
1100         ddoi.dwOfs = DIJOFS_Z;
1101         break;
1102       case ABS_RX:
1103         ddoi.guidType = GUID_RxAxis;
1104         ddoi.dwOfs = DIJOFS_RX;
1105         break;
1106       case ABS_RY:
1107         ddoi.guidType = GUID_RyAxis;
1108         ddoi.dwOfs = DIJOFS_RY;
1109         break;
1110       case ABS_RZ:
1111         ddoi.guidType = GUID_RzAxis;
1112         ddoi.dwOfs = DIJOFS_RZ;
1113         break;
1114       case ABS_THROTTLE:
1115         ddoi.guidType = GUID_Slider;
1116         ddoi.dwOfs = DIJOFS_SLIDER(0);
1117         break;
1118       case ABS_RUDDER:
1119         ddoi.guidType = GUID_Slider;
1120         ddoi.dwOfs = DIJOFS_SLIDER(1);
1121         break;
1122       default:
1123         FIXME("unhandled abs axis %d, ignoring!\n",i);
1124       }
1125       ddoi.dwType = DIDFT_MAKEINSTANCE((1<<i) << WINE_JOYSTICK_AXIS_BASE) | DIDFT_ABSAXIS;
1126       /* Linux event force feedback supports only (and always) x and y axes */
1127       if (i == ABS_X || i == ABS_Y) {
1128         if (This->has_ff)
1129           ddoi.dwFlags |= DIDOI_FFACTUATOR;
1130       }
1131       sprintf(ddoi.tszName, "%d-Axis", i);
1132       _dump_OBJECTINSTANCEA(&ddoi);
1133       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) {
1134         /* return to unaquired state if that's where we were */
1135         if (xfd == -1)
1136           IDirectInputDevice8_Unacquire(iface);
1137         return DI_OK;
1138       }
1139     }
1140   }
1141
1142   if ((dwFlags == DIDFT_ALL) ||
1143       (dwFlags & DIDFT_BUTTON)) {
1144     int i;
1145
1146     /*The DInput SDK says that GUID_Button is only for mouse buttons but well*/
1147
1148     ddoi.guidType = GUID_Button;
1149
1150     for (i = 0; i < KEY_MAX; i++) {
1151       if (!test_bit(This->keybits,i)) continue;
1152
1153       switch (i) {
1154       case BTN_TRIGGER:
1155       case BTN_A:
1156       case BTN_1:
1157           ddoi.dwOfs = DIJOFS_BUTTON(0);
1158           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 0) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1159           break;
1160         case BTN_THUMB:
1161         case BTN_B:
1162         case BTN_2:
1163           ddoi.dwOfs = DIJOFS_BUTTON(1);
1164           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 1) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1165           break;
1166         case BTN_THUMB2:
1167         case BTN_C:
1168         case BTN_3:
1169           ddoi.dwOfs = DIJOFS_BUTTON(2);
1170           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 2) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1171           break;
1172         case BTN_TOP:
1173         case BTN_X:
1174         case BTN_4:
1175           ddoi.dwOfs = DIJOFS_BUTTON(3);
1176           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 3) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1177           break;
1178         case BTN_TOP2:
1179         case BTN_Y:
1180         case BTN_5:
1181           ddoi.dwOfs = DIJOFS_BUTTON(4);
1182           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 4) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1183           break;
1184         case BTN_PINKIE:
1185         case BTN_Z:
1186         case BTN_6:
1187           ddoi.dwOfs = DIJOFS_BUTTON(5);
1188           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 5) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1189           break;
1190         case BTN_BASE:
1191         case BTN_TL:
1192         case BTN_7:
1193           ddoi.dwOfs = DIJOFS_BUTTON(6);
1194           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 6) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1195           break;
1196         case BTN_BASE2:
1197         case BTN_TR:
1198         case BTN_8:
1199           ddoi.dwOfs = DIJOFS_BUTTON(7);
1200           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 7) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1201           break;
1202         case BTN_BASE3:
1203         case BTN_TL2:
1204         case BTN_9:
1205           ddoi.dwOfs = DIJOFS_BUTTON(8);
1206           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 8) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1207           break;
1208         case BTN_BASE4:
1209         case BTN_TR2:
1210           ddoi.dwOfs = DIJOFS_BUTTON(9);
1211           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 9) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1212           break;
1213         case BTN_BASE5:
1214         case BTN_SELECT:
1215           ddoi.dwOfs = DIJOFS_BUTTON(10);
1216           ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 10) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
1217           break;
1218       }
1219       sprintf(ddoi.tszName, "%d-Button", i);
1220       _dump_OBJECTINSTANCEA(&ddoi);
1221       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) {
1222         /* return to unaquired state if that's where we were */
1223         if (xfd == -1)
1224           IDirectInputDevice8_Unacquire(iface);
1225         return DI_OK;
1226       }
1227     }
1228   }
1229
1230   /* return to unaquired state if that's where we were */
1231   if (xfd == -1)
1232     IDirectInputDevice8_Unacquire(iface);
1233
1234   return DI_OK;
1235 }
1236
1237 static HRESULT WINAPI JoystickWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface,
1238                                                 LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback,
1239                                                 LPVOID lpvRef,
1240                                                 DWORD dwFlags)
1241 {
1242   JoystickImpl *This = (JoystickImpl *)iface;
1243
1244   device_enumobjects_AtoWcb_data data;
1245
1246   data.lpCallBack = lpCallback;
1247   data.lpvRef = lpvRef;
1248
1249   return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags);
1250 }
1251
1252 /******************************************************************************
1253   *     GetProperty : get input device properties
1254   */
1255 static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
1256                                                 REFGUID rguid,
1257                                                 LPDIPROPHEADER pdiph)
1258 {
1259   JoystickImpl *This = (JoystickImpl *)iface;
1260
1261   TRACE("(this=%p,%s,%p)\n",
1262         iface, debugstr_guid(rguid), pdiph);
1263
1264   if (TRACE_ON(dinput))
1265     _dump_DIPROPHEADER(pdiph);
1266
1267   if (!HIWORD(rguid)) {
1268     switch (LOWORD(rguid)) {
1269     case (DWORD) DIPROP_BUFFERSIZE: {
1270       LPDIPROPDWORD     pd = (LPDIPROPDWORD)pdiph;
1271
1272       TRACE(" return buffersize = %d\n",This->queue_len);
1273       pd->dwData = This->queue_len;
1274       break;
1275     }
1276
1277     case (DWORD) DIPROP_RANGE: {
1278       /* LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; */
1279       if ((pdiph->dwHow == DIPH_BYID) &&
1280           (pdiph->dwObj & DIDFT_ABSAXIS)) {
1281         /* The app is querying the current range of the axis : return the lMin and lMax values */
1282         FIXME("unimplemented axis range query.\n");
1283       }
1284
1285       break;
1286     }
1287
1288     default:
1289       FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid));
1290       break;
1291     }
1292   }
1293
1294
1295   return DI_OK;
1296 }
1297
1298 /****************************************************************************** 
1299   *     CreateEffect - Create a new FF effect with the specified params
1300   */
1301 static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface,
1302                                                  REFGUID rguid,
1303                                                  LPCDIEFFECT lpeff,
1304                                                  LPDIRECTINPUTEFFECT *ppdef,
1305                                                  LPUNKNOWN pUnkOuter)
1306 {
1307 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1308     EffectListItem* new = NULL;
1309     HRESULT retval = DI_OK;
1310 #endif
1311
1312     JoystickImpl* This = (JoystickImpl*)iface;
1313     TRACE("(this=%p,%p,%p,%p,%p)\n", This, rguid, lpeff, ppdef, pUnkOuter);
1314
1315 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
1316     TRACE("not available (compiled w/o ff support)\n");
1317     *ppdef = NULL;
1318     return DI_OK; 
1319 #else
1320
1321     new = malloc(sizeof(EffectListItem));
1322     new->next = This->top_effect;
1323     This->top_effect = new;
1324
1325     retval = linuxinput_create_effect(&(This->joyfd), rguid, &(new->ref));
1326     if (retval != DI_OK)
1327         return retval;
1328  
1329     if (lpeff != NULL)
1330         retval = IDirectInputEffect_SetParameters(new->ref, lpeff, 0);
1331     if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED)
1332         return retval;
1333
1334     *ppdef = new->ref;
1335
1336     if (pUnkOuter != NULL)
1337         FIXME("Interface aggregation not implemented.\n");
1338
1339     return DI_OK;
1340
1341 #endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */
1342
1343
1344 /*******************************************************************************
1345  *      EnumEffects - Enumerate available FF effects
1346  */
1347 static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface,
1348                                                 LPDIENUMEFFECTSCALLBACKA lpCallback,
1349                                                 LPVOID pvRef,
1350                                                 DWORD dwEffType)
1351 {
1352 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1353     DIEFFECTINFOA dei; /* feif */
1354     DWORD type = DIEFT_GETTYPE(dwEffType);
1355     JoystickImpl* This = (JoystickImpl*)iface;
1356     int xfd = This->joyfd;
1357
1358     TRACE("(this=%p,%p,%ld) type=%ld fd=%d\n", This, pvRef, dwEffType, type, xfd);
1359
1360     dei.dwSize = sizeof(DIEFFECTINFOA);          
1361
1362     /* We need to return something even if we're not yet acquired */
1363     if (xfd == -1)
1364         IDirectInputDevice8_Acquire(iface);
1365
1366     if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1367         && test_bit(This->ffbits, FF_CONSTANT)) {
1368         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1369         (*lpCallback)(&dei, pvRef);
1370     }
1371
1372     if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1373         && test_bit(This->ffbits, FF_PERIODIC)) {
1374         if (test_bit(This->ffbits, FF_SQUARE)) {
1375             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1376             (*lpCallback)(&dei, pvRef);
1377         }
1378         if (test_bit(This->ffbits, FF_SINE)) {
1379             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1380             (*lpCallback)(&dei, pvRef);
1381         }
1382         if (test_bit(This->ffbits, FF_TRIANGLE)) {
1383             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1384             (*lpCallback)(&dei, pvRef);
1385         }
1386         if (test_bit(This->ffbits, FF_SAW_UP)) {
1387             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1388             (*lpCallback)(&dei, pvRef);
1389         }
1390         if (test_bit(This->ffbits, FF_SAW_DOWN)) {
1391             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1392             (*lpCallback)(&dei, pvRef);
1393         }
1394     } 
1395
1396     if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1397         && test_bit(This->ffbits, FF_RAMP)) {
1398         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1399         (*lpCallback)(&dei, pvRef);
1400     }
1401
1402     if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1403         if (test_bit(This->ffbits, FF_SPRING)) {
1404             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1405             (*lpCallback)(&dei, pvRef);
1406         }
1407         if (test_bit(This->ffbits, FF_DAMPER)) {
1408             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1409             (*lpCallback)(&dei, pvRef);
1410         }
1411         if (test_bit(This->ffbits, FF_INERTIA)) {
1412             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1413             (*lpCallback)(&dei, pvRef);
1414         }
1415         if (test_bit(This->ffbits, FF_FRICTION)) {
1416             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1417             (*lpCallback)(&dei, pvRef);
1418         }
1419     }
1420
1421     /* return to unaquired state if that's where it was */
1422     if (xfd == -1)
1423         IDirectInputDevice8_Unacquire(iface);
1424 #endif
1425
1426     return DI_OK;
1427 }
1428
1429 static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface,
1430                                                 LPDIENUMEFFECTSCALLBACKW lpCallback,
1431                                                 LPVOID pvRef,
1432                                                 DWORD dwEffType)
1433 {
1434 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1435     /* seems silly to duplicate all this code but all the structures and functions
1436      * are actually different (A/W) */
1437     DIEFFECTINFOW dei; /* feif */
1438     DWORD type = DIEFT_GETTYPE(dwEffType);
1439     JoystickImpl* This = (JoystickImpl*)iface;
1440     int xfd = This->joyfd;
1441
1442     TRACE("(this=%p,%p,%ld) type=%ld fd=%d\n", This, pvRef, dwEffType, type, xfd);
1443
1444     dei.dwSize = sizeof(DIEFFECTINFOW);          
1445
1446     /* We need to return something even if we're not yet acquired */
1447     if (xfd == -1)
1448         IDirectInputDevice8_Acquire(iface);
1449
1450     if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1451         && test_bit(This->ffbits, FF_CONSTANT)) {
1452         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1453         (*lpCallback)(&dei, pvRef);
1454     }
1455
1456     if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1457         && test_bit(This->ffbits, FF_PERIODIC)) {
1458         if (test_bit(This->ffbits, FF_SQUARE)) {
1459             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1460             (*lpCallback)(&dei, pvRef);
1461         }
1462         if (test_bit(This->ffbits, FF_SINE)) {
1463             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1464             (*lpCallback)(&dei, pvRef);
1465         }
1466         if (test_bit(This->ffbits, FF_TRIANGLE)) {
1467             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1468             (*lpCallback)(&dei, pvRef);
1469         }
1470         if (test_bit(This->ffbits, FF_SAW_UP)) {
1471             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1472             (*lpCallback)(&dei, pvRef);
1473         }
1474         if (test_bit(This->ffbits, FF_SAW_DOWN)) {
1475             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1476             (*lpCallback)(&dei, pvRef);
1477         }
1478     } 
1479
1480     if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1481         && test_bit(This->ffbits, FF_RAMP)) {
1482         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1483         (*lpCallback)(&dei, pvRef);
1484     }
1485
1486     if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1487         if (test_bit(This->ffbits, FF_SPRING)) {
1488             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1489             (*lpCallback)(&dei, pvRef);
1490         }
1491         if (test_bit(This->ffbits, FF_DAMPER)) {
1492             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1493             (*lpCallback)(&dei, pvRef);
1494         }
1495         if (test_bit(This->ffbits, FF_INERTIA)) {
1496             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1497             (*lpCallback)(&dei, pvRef);
1498         }
1499         if (test_bit(This->ffbits, FF_FRICTION)) {
1500             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1501             (*lpCallback)(&dei, pvRef);
1502         }
1503     }
1504
1505     /* return to unaquired state if that's where it was */
1506     if (xfd == -1)
1507         IDirectInputDevice8_Unacquire(iface);
1508 #endif
1509
1510     return DI_OK;
1511 }
1512
1513 /*******************************************************************************
1514  *      GetEffectInfo - Get information about a particular effect 
1515  */
1516 static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface,
1517                                                   LPDIEFFECTINFOA pdei,
1518                                                   REFGUID guid)
1519 {
1520     JoystickImpl* This = (JoystickImpl*)iface;
1521
1522     TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1523
1524 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1525     return linuxinput_get_info_A(This->joyfd, guid, pdei); 
1526 #else
1527     return DI_OK;
1528 #endif
1529 }
1530
1531 static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface,
1532                                                   LPDIEFFECTINFOW pdei,
1533                                                   REFGUID guid)
1534 {
1535     JoystickImpl* This = (JoystickImpl*)iface;
1536             
1537     TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1538         
1539 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1540     return linuxinput_get_info_W(This->joyfd, guid, pdei);
1541 #else
1542     return DI_OK;
1543 #endif
1544 }
1545
1546 /*******************************************************************************
1547  *      GetForceFeedbackState - Get information about the device's FF state 
1548  */
1549 static HRESULT WINAPI JoystickAImpl_GetForceFeedbackState(
1550         LPDIRECTINPUTDEVICE8A iface,
1551         LPDWORD pdwOut)
1552 {
1553     JoystickImpl* This = (JoystickImpl*)iface;
1554
1555     TRACE("(this=%p,%p)\n", This, pdwOut);
1556
1557     (*pdwOut) = 0;
1558
1559 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1560     /* DIGFFS_STOPPED is the only mandatory flag to report */
1561     if (This->ff_state == FF_STATUS_STOPPED)
1562         (*pdwOut) |= DIGFFS_STOPPED;
1563 #endif
1564
1565     return DI_OK;
1566 }
1567
1568 /*******************************************************************************
1569  *      SendForceFeedbackCommand - Send a command to the device's FF system
1570  */
1571 static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(
1572         LPDIRECTINPUTDEVICE8A iface,
1573         DWORD dwFlags)
1574 {
1575     JoystickImpl* This = (JoystickImpl*)iface;
1576     TRACE("(this=%p,%ld)\n", This, dwFlags);
1577
1578 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1579     if (dwFlags == DISFFC_STOPALL) {
1580         /* Stop all effects */
1581         EffectListItem* itr = This->top_effect;
1582         while (itr) {
1583             IDirectInputEffect_Stop(itr->ref);
1584             itr = itr->next;
1585         }
1586     } else if (dwFlags == DISFFC_RESET) {
1587         /* Stop, unload, release and free all effects */
1588         /* This returns the device to its "bare" state */
1589         while (This->top_effect) {
1590             EffectListItem* temp = This->top_effect; 
1591             IDirectInputEffect_Stop(temp->ref);
1592             IDirectInputEffect_Unload(temp->ref);
1593             IDirectInputEffect_Release(temp->ref);
1594             This->top_effect = temp->next; 
1595             free(temp);
1596         }
1597     } else if (dwFlags == DISFFC_PAUSE || dwFlags == DISFFC_CONTINUE) {
1598         FIXME("No support for Pause or Continue in linux\n");
1599     } else if (dwFlags == DISFFC_SETACTUATORSOFF 
1600                 || dwFlags == DISFFC_SETACTUATORSON) {
1601         FIXME("No direct actuator control in linux\n");
1602     } else {
1603         FIXME("Unknown Force Feedback Command!\n");
1604         return DIERR_INVALIDPARAM;
1605     }
1606     return DI_OK;
1607 #else
1608     return DIERR_UNSUPPORTED;
1609 #endif
1610 }
1611
1612 /*******************************************************************************
1613  *      EnumCreatedEffectObjects - Enumerate all the effects that have been
1614  *              created for this device.
1615  */
1616 static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects(
1617         LPDIRECTINPUTDEVICE8A iface,
1618         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
1619         LPVOID pvRef,
1620         DWORD dwFlags)
1621 {
1622     /* this function is safe to call on non-ff-enabled builds */
1623
1624     JoystickImpl* This = (JoystickImpl*)iface;
1625     EffectListItem* itr = This->top_effect;
1626     TRACE("(this=%p,%p,%p,%ld)\n", This, lpCallback, pvRef, dwFlags);
1627
1628     if (!lpCallback)
1629         return DIERR_INVALIDPARAM;
1630
1631     if (dwFlags != 0)
1632         FIXME("Flags specified, but no flags exist yet (DX9)!");
1633
1634     while (itr) {
1635         (*lpCallback)(itr->ref, pvRef);
1636         itr = itr->next;
1637     }
1638
1639     return DI_OK;
1640 }
1641
1642 static const IDirectInputDevice8AVtbl JoystickAvt =
1643 {
1644         IDirectInputDevice2AImpl_QueryInterface,
1645         IDirectInputDevice2AImpl_AddRef,
1646         JoystickAImpl_Release,
1647         JoystickAImpl_GetCapabilities,
1648         JoystickAImpl_EnumObjects,
1649         JoystickAImpl_GetProperty,
1650         JoystickAImpl_SetProperty,
1651         JoystickAImpl_Acquire,
1652         JoystickAImpl_Unacquire,
1653         JoystickAImpl_GetDeviceState,
1654         JoystickAImpl_GetDeviceData,
1655         JoystickAImpl_SetDataFormat,
1656         JoystickAImpl_SetEventNotification,
1657         IDirectInputDevice2AImpl_SetCooperativeLevel,
1658         IDirectInputDevice2AImpl_GetObjectInfo,
1659         IDirectInputDevice2AImpl_GetDeviceInfo,
1660         IDirectInputDevice2AImpl_RunControlPanel,
1661         IDirectInputDevice2AImpl_Initialize,
1662         JoystickAImpl_CreateEffect,
1663         JoystickAImpl_EnumEffects,
1664         JoystickAImpl_GetEffectInfo,
1665         JoystickAImpl_GetForceFeedbackState,
1666         JoystickAImpl_SendForceFeedbackCommand,
1667         JoystickAImpl_EnumCreatedEffectObjects,
1668         IDirectInputDevice2AImpl_Escape,
1669         JoystickAImpl_Poll,
1670         IDirectInputDevice2AImpl_SendDeviceData,
1671         IDirectInputDevice7AImpl_EnumEffectsInFile,
1672         IDirectInputDevice7AImpl_WriteEffectToFile,
1673         IDirectInputDevice8AImpl_BuildActionMap,
1674         IDirectInputDevice8AImpl_SetActionMap,
1675         IDirectInputDevice8AImpl_GetImageInfo
1676 };
1677
1678 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
1679 # define XCAST(fun)     (typeof(JoystickWvt.fun))
1680 #else
1681 # define XCAST(fun)     (void*)
1682 #endif
1683
1684 static const IDirectInputDevice8WVtbl JoystickWvt =
1685 {
1686         IDirectInputDevice2WImpl_QueryInterface,
1687         XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
1688         XCAST(Release)JoystickAImpl_Release,
1689         XCAST(GetCapabilities)JoystickAImpl_GetCapabilities,
1690         JoystickWImpl_EnumObjects,
1691         XCAST(GetProperty)JoystickAImpl_GetProperty,
1692         XCAST(SetProperty)JoystickAImpl_SetProperty,
1693         XCAST(Acquire)JoystickAImpl_Acquire,
1694         XCAST(Unacquire)JoystickAImpl_Unacquire,
1695         XCAST(GetDeviceState)JoystickAImpl_GetDeviceState,
1696         XCAST(GetDeviceData)JoystickAImpl_GetDeviceData,
1697         XCAST(SetDataFormat)JoystickAImpl_SetDataFormat,
1698         XCAST(SetEventNotification)JoystickAImpl_SetEventNotification,
1699         XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
1700         IDirectInputDevice2WImpl_GetObjectInfo,
1701         IDirectInputDevice2WImpl_GetDeviceInfo,
1702         XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
1703         XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
1704         XCAST(CreateEffect)JoystickAImpl_CreateEffect,
1705         JoystickWImpl_EnumEffects,
1706         JoystickWImpl_GetEffectInfo,
1707         XCAST(GetForceFeedbackState)JoystickAImpl_GetForceFeedbackState,
1708         XCAST(SendForceFeedbackCommand)JoystickAImpl_SendForceFeedbackCommand,
1709         XCAST(EnumCreatedEffectObjects)JoystickAImpl_EnumCreatedEffectObjects,
1710         XCAST(Escape)IDirectInputDevice2AImpl_Escape,
1711         XCAST(Poll)JoystickAImpl_Poll,
1712         XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
1713         IDirectInputDevice7WImpl_EnumEffectsInFile,
1714         IDirectInputDevice7WImpl_WriteEffectToFile,
1715         IDirectInputDevice8WImpl_BuildActionMap,
1716         IDirectInputDevice8WImpl_SetActionMap,
1717         IDirectInputDevice8WImpl_GetImageInfo
1718 };
1719 #undef XCAST
1720
1721 #else  /* HAVE_CORRECT_LINUXINPUT_H */
1722
1723 const struct dinput_device joystick_linuxinput_device = {
1724   "Wine Linux-input joystick driver",
1725   NULL,
1726   NULL,
1727   NULL,
1728   NULL
1729 };
1730
1731 #endif  /* HAVE_CORRECT_LINUXINPUT_H */