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