gdi32: Disable the freetype mmap sharing on Mac OS.
[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     default:
1075       return IDirectInputDevice2AImpl_SetProperty(iface, rguid, ph);
1076     }
1077   }
1078   return DI_OK;
1079 }
1080
1081 static HRESULT WINAPI JoystickAImpl_GetCapabilities(
1082         LPDIRECTINPUTDEVICE8A iface,
1083         LPDIDEVCAPS lpDIDevCaps)
1084 {
1085     JoystickImpl *This = (JoystickImpl *)iface;
1086     int         i,axes,buttons,povs;
1087
1088     TRACE("%p->(%p)\n",iface,lpDIDevCaps);
1089
1090     if (!lpDIDevCaps) {
1091         WARN("invalid pointer\n");
1092         return E_POINTER;
1093     }
1094
1095     if (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) {
1096         WARN("invalid argument\n");
1097         return DIERR_INVALIDPARAM;
1098     }
1099
1100     lpDIDevCaps->dwFlags        = DIDC_ATTACHED;
1101     if (This->dinput->dwVersion >= 0x0800)
1102         lpDIDevCaps->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
1103     else
1104         lpDIDevCaps->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
1105
1106     axes=0;
1107     for (i=0;i<ABS_MAX;i++) {
1108       if (!test_bit(This->joydev->absbits,i)) continue;
1109       switch (i) {
1110       case ABS_HAT0X: case ABS_HAT0Y:
1111       case ABS_HAT1X: case ABS_HAT1Y:
1112       case ABS_HAT2X: case ABS_HAT2Y:
1113       case ABS_HAT3X: case ABS_HAT3Y:
1114         /* will be handled as POV - see below */
1115         break;
1116       default:
1117         axes++;
1118       }
1119     }
1120     buttons=0;
1121     for (i=0;i<KEY_MAX;i++) if (test_bit(This->joydev->keybits,i)) buttons++;
1122     povs=0;
1123     for (i=0; i<4; i++) {
1124       if (test_bit(This->joydev->absbits,ABS_HAT0X+(i<<1)) && test_bit(This->joydev->absbits,ABS_HAT0Y+(i<<1))) {
1125         povs ++;
1126       }
1127     }
1128
1129     if (This->joydev->has_ff) 
1130          lpDIDevCaps->dwFlags |= DIDC_FORCEFEEDBACK;
1131
1132     lpDIDevCaps->dwAxes = axes;
1133     lpDIDevCaps->dwButtons = buttons;
1134     lpDIDevCaps->dwPOVs = povs;
1135
1136     return DI_OK;
1137 }
1138
1139 static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) {
1140     JoystickImpl *This = (JoystickImpl *)iface;
1141     TRACE("(%p)\n",This);
1142
1143     if (This->joyfd==-1) {
1144       return DIERR_NOTACQUIRED;
1145     }
1146
1147     joy_polldev(This);
1148     return DI_OK;
1149 }
1150
1151 /******************************************************************************
1152   *     EnumObjects : enumerate the different buttons and axis...
1153   */
1154 static HRESULT WINAPI JoystickAImpl_EnumObjects(
1155         LPDIRECTINPUTDEVICE8A iface,
1156         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
1157         LPVOID lpvRef,
1158         DWORD dwFlags)
1159 {
1160   JoystickImpl *This = (JoystickImpl *)iface;
1161   DIDEVICEOBJECTINSTANCEA ddoi;
1162   int user_offset, user_object;
1163
1164   TRACE("(this=%p,%p,%p,%08x)\n", This, lpCallback, lpvRef, dwFlags);
1165   if (TRACE_ON(dinput)) {
1166     TRACE("  - flags = ");
1167     _dump_EnumObjects_flags(dwFlags);
1168     TRACE("\n");
1169   }
1170
1171   /* Only the fields till dwFFMaxForce are relevant */
1172   ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
1173
1174   /* For the joystick, do as is done in the GetCapabilities function */
1175   /* FIXME: needs more items */
1176   if ((dwFlags == DIDFT_ALL) ||
1177       (dwFlags & DIDFT_AXIS)) {
1178     BYTE i;
1179
1180     for (i = 0; i < ABS_MAX; i++) {
1181       if (!test_bit(This->joydev->absbits,i)) continue;
1182
1183       switch (i) {
1184       case ABS_X:
1185         ddoi.guidType = GUID_XAxis;
1186         break;
1187       case ABS_Y:
1188         ddoi.guidType = GUID_YAxis;
1189         break;
1190       case ABS_Z:
1191         ddoi.guidType = GUID_ZAxis;
1192         break;
1193       case ABS_RX:
1194         ddoi.guidType = GUID_RxAxis;
1195         break;
1196       case ABS_RY:
1197         ddoi.guidType = GUID_RyAxis;
1198         break;
1199       case ABS_RZ:
1200         ddoi.guidType = GUID_RzAxis;
1201         break;
1202       case ABS_THROTTLE:
1203       case ABS_RUDDER:
1204         ddoi.guidType = GUID_Slider;
1205         break;
1206       case ABS_HAT0X: case ABS_HAT0Y:
1207       case ABS_HAT1X: case ABS_HAT1Y:
1208       case ABS_HAT2X: case ABS_HAT2Y:
1209       case ABS_HAT3X: case ABS_HAT3Y:
1210         /* will be handled as POV - see below */
1211         continue;
1212       default:
1213         FIXME("unhandled abs axis 0x%02x, ignoring!\n",i);
1214         continue;
1215       }
1216       if ((user_offset = lxinput_to_user_offset(This, EV_ABS, i)) == -1) {
1217         continue;
1218       }
1219       user_object = offset_to_object(This, user_offset);
1220       ddoi.dwType = This->df->rgodf[user_object].dwType & 0x00ffffff;
1221       ddoi.dwOfs =  This->df->rgodf[user_object].dwOfs;
1222       /* Linux event force feedback supports only (and always) x and y axes */
1223       if (i == ABS_X || i == ABS_Y) {
1224         if (This->joydev->has_ff)
1225           ddoi.dwFlags |= DIDOI_FFACTUATOR;
1226       }
1227       sprintf(ddoi.tszName, "%d-Axis", i);
1228       _dump_OBJECTINSTANCEA(&ddoi);
1229       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) {
1230         return DI_OK;
1231       }
1232     }
1233   }
1234
1235   if ((dwFlags == DIDFT_ALL) ||
1236       (dwFlags & DIDFT_POV)) {
1237     int i;
1238     ddoi.guidType = GUID_POV;
1239     for (i=0; i<4; i++) {
1240       if (test_bit(This->joydev->absbits,ABS_HAT0X+(i<<1)) && test_bit(This->joydev->absbits,ABS_HAT0Y+(i<<1))) {
1241         if ((user_offset = lxinput_to_user_offset(This, EV_ABS, ABS_HAT0X+i))== -1) {
1242           continue;
1243         }
1244         user_object = offset_to_object(This, user_offset);
1245         ddoi.dwType = This->df->rgodf[user_object].dwType & 0x00ffffff;
1246         ddoi.dwOfs =  This->df->rgodf[user_object].dwOfs;
1247         sprintf(ddoi.tszName, "%d-POV", i);
1248         _dump_OBJECTINSTANCEA(&ddoi);
1249         if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) {
1250           return DI_OK;
1251         }
1252       }
1253     }
1254   }
1255
1256   if ((dwFlags == DIDFT_ALL) ||
1257       (dwFlags & DIDFT_BUTTON)) {
1258     int i, btncount=0;
1259
1260     /*The DInput SDK says that GUID_Button is only for mouse buttons but well*/
1261
1262     ddoi.guidType = GUID_Button;
1263
1264     for (i = 0; i < KEY_MAX; i++) {
1265       if (!test_bit(This->joydev->keybits,i)) continue;
1266       if ((user_offset = lxinput_to_user_offset(This, EV_KEY, btncount)) == -1) {
1267         continue;
1268       }
1269       user_object = offset_to_object(This, user_offset);
1270       ddoi.dwType = This->df->rgodf[user_object].dwType & 0x00ffffff;
1271       ddoi.dwOfs =  This->df->rgodf[user_object].dwOfs;
1272       sprintf(ddoi.tszName, "%d-Button", btncount);
1273       btncount++;
1274       _dump_OBJECTINSTANCEA(&ddoi);
1275       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) {
1276         return DI_OK;
1277       }
1278     }
1279   }
1280
1281   return DI_OK;
1282 }
1283
1284 static HRESULT WINAPI JoystickWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface,
1285                                                 LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback,
1286                                                 LPVOID lpvRef,
1287                                                 DWORD dwFlags)
1288 {
1289   JoystickImpl *This = (JoystickImpl *)iface;
1290
1291   device_enumobjects_AtoWcb_data data;
1292
1293   data.lpCallBack = lpCallback;
1294   data.lpvRef = lpvRef;
1295
1296   return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags);
1297 }
1298
1299 /******************************************************************************
1300   *     GetProperty : get input device properties
1301   */
1302 static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
1303                                                 REFGUID rguid,
1304                                                 LPDIPROPHEADER pdiph)
1305 {
1306   JoystickImpl *This = (JoystickImpl *)iface;
1307
1308   TRACE("(this=%p,%s,%p)\n",
1309         iface, debugstr_guid(rguid), pdiph);
1310
1311   if (TRACE_ON(dinput))
1312     _dump_DIPROPHEADER(pdiph);
1313
1314   if (!HIWORD(rguid)) {
1315     switch (LOWORD(rguid)) {
1316     case (DWORD) DIPROP_RANGE: {
1317       LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
1318       int obj = find_property_offset(This, pdiph);
1319       if (obj >= 0) {
1320         pr->lMin = This->joydev->havemin[obj];
1321         pr->lMax = This->joydev->havemax[obj];
1322         TRACE("range(%d, %d) obj=%d\n", pr->lMin, pr->lMax, obj);
1323       }
1324       break;
1325     }
1326
1327     default:
1328       return IDirectInputDevice2AImpl_GetProperty(iface, rguid, pdiph);
1329     }
1330   }
1331
1332
1333   return DI_OK;
1334 }
1335
1336 /****************************************************************************** 
1337   *     CreateEffect - Create a new FF effect with the specified params
1338   */
1339 static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface,
1340                                                  REFGUID rguid,
1341                                                  LPCDIEFFECT lpeff,
1342                                                  LPDIRECTINPUTEFFECT *ppdef,
1343                                                  LPUNKNOWN pUnkOuter)
1344 {
1345 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1346     EffectListItem* new = NULL;
1347     HRESULT retval = DI_OK;
1348 #endif
1349
1350     JoystickImpl* This = (JoystickImpl*)iface;
1351     TRACE("(this=%p,%p,%p,%p,%p)\n", This, rguid, lpeff, ppdef, pUnkOuter);
1352
1353 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
1354     TRACE("not available (compiled w/o ff support)\n");
1355     *ppdef = NULL;
1356     return DI_OK;
1357 #else
1358
1359     new = HeapAlloc(GetProcessHeap(), 0, sizeof(EffectListItem));
1360     new->next = This->top_effect;
1361     This->top_effect = new;
1362
1363     retval = linuxinput_create_effect(&(This->joyfd), rguid, &(new->ref));
1364     if (retval != DI_OK)
1365         return retval;
1366
1367     if (lpeff != NULL)
1368         retval = IDirectInputEffect_SetParameters(new->ref, lpeff, 0);
1369     if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED)
1370         return retval;
1371
1372     *ppdef = new->ref;
1373
1374     if (pUnkOuter != NULL)
1375         FIXME("Interface aggregation not implemented.\n");
1376
1377     return DI_OK;
1378
1379 #endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */
1380
1381
1382 /*******************************************************************************
1383  *      EnumEffects - Enumerate available FF effects
1384  */
1385 static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface,
1386                                                 LPDIENUMEFFECTSCALLBACKA lpCallback,
1387                                                 LPVOID pvRef,
1388                                                 DWORD dwEffType)
1389 {
1390 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1391     DIEFFECTINFOA dei; /* feif */
1392     DWORD type = DIEFT_GETTYPE(dwEffType);
1393     JoystickImpl* This = (JoystickImpl*)iface;
1394
1395     TRACE("(this=%p,%p,%d) type=%d\n", This, pvRef, dwEffType, type);
1396
1397     dei.dwSize = sizeof(DIEFFECTINFOA);          
1398
1399     if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1400         && test_bit(This->joydev->ffbits, FF_CONSTANT)) {
1401         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1402         (*lpCallback)(&dei, pvRef);
1403     }
1404
1405     if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1406         && test_bit(This->joydev->ffbits, FF_PERIODIC)) {
1407         if (test_bit(This->joydev->ffbits, FF_SQUARE)) {
1408             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1409             (*lpCallback)(&dei, pvRef);
1410         }
1411         if (test_bit(This->joydev->ffbits, FF_SINE)) {
1412             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1413             (*lpCallback)(&dei, pvRef);
1414         }
1415         if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) {
1416             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1417             (*lpCallback)(&dei, pvRef);
1418         }
1419         if (test_bit(This->joydev->ffbits, FF_SAW_UP)) {
1420             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1421             (*lpCallback)(&dei, pvRef);
1422         }
1423         if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) {
1424             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1425             (*lpCallback)(&dei, pvRef);
1426         }
1427     } 
1428
1429     if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1430         && test_bit(This->joydev->ffbits, FF_RAMP)) {
1431         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1432         (*lpCallback)(&dei, pvRef);
1433     }
1434
1435     if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1436         if (test_bit(This->joydev->ffbits, FF_SPRING)) {
1437             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1438             (*lpCallback)(&dei, pvRef);
1439         }
1440         if (test_bit(This->joydev->ffbits, FF_DAMPER)) {
1441             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1442             (*lpCallback)(&dei, pvRef);
1443         }
1444         if (test_bit(This->joydev->ffbits, FF_INERTIA)) {
1445             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1446             (*lpCallback)(&dei, pvRef);
1447         }
1448         if (test_bit(This->joydev->ffbits, FF_FRICTION)) {
1449             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1450             (*lpCallback)(&dei, pvRef);
1451         }
1452     }
1453
1454 #endif
1455
1456     return DI_OK;
1457 }
1458
1459 static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface,
1460                                                 LPDIENUMEFFECTSCALLBACKW lpCallback,
1461                                                 LPVOID pvRef,
1462                                                 DWORD dwEffType)
1463 {
1464 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1465     /* seems silly to duplicate all this code but all the structures and functions
1466      * are actually different (A/W) */
1467     DIEFFECTINFOW dei; /* feif */
1468     DWORD type = DIEFT_GETTYPE(dwEffType);
1469     JoystickImpl* This = (JoystickImpl*)iface;
1470     int xfd = This->joyfd;
1471
1472     TRACE("(this=%p,%p,%d) type=%d fd=%d\n", This, pvRef, dwEffType, type, xfd);
1473
1474     dei.dwSize = sizeof(DIEFFECTINFOW);          
1475
1476     if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1477         && test_bit(This->joydev->ffbits, FF_CONSTANT)) {
1478         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1479         (*lpCallback)(&dei, pvRef);
1480     }
1481
1482     if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1483         && test_bit(This->joydev->ffbits, FF_PERIODIC)) {
1484         if (test_bit(This->joydev->ffbits, FF_SQUARE)) {
1485             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1486             (*lpCallback)(&dei, pvRef);
1487         }
1488         if (test_bit(This->joydev->ffbits, FF_SINE)) {
1489             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1490             (*lpCallback)(&dei, pvRef);
1491         }
1492         if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) {
1493             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1494             (*lpCallback)(&dei, pvRef);
1495         }
1496         if (test_bit(This->joydev->ffbits, FF_SAW_UP)) {
1497             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1498             (*lpCallback)(&dei, pvRef);
1499         }
1500         if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) {
1501             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1502             (*lpCallback)(&dei, pvRef);
1503         }
1504     } 
1505
1506     if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1507         && test_bit(This->joydev->ffbits, FF_RAMP)) {
1508         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1509         (*lpCallback)(&dei, pvRef);
1510     }
1511
1512     if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1513         if (test_bit(This->joydev->ffbits, FF_SPRING)) {
1514             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1515             (*lpCallback)(&dei, pvRef);
1516         }
1517         if (test_bit(This->joydev->ffbits, FF_DAMPER)) {
1518             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1519             (*lpCallback)(&dei, pvRef);
1520         }
1521         if (test_bit(This->joydev->ffbits, FF_INERTIA)) {
1522             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1523             (*lpCallback)(&dei, pvRef);
1524         }
1525         if (test_bit(This->joydev->ffbits, FF_FRICTION)) {
1526             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1527             (*lpCallback)(&dei, pvRef);
1528         }
1529     }
1530
1531     /* return to unacquired state if that's where it was */
1532     if (xfd == -1)
1533         IDirectInputDevice8_Unacquire(iface);
1534 #endif
1535
1536     return DI_OK;
1537 }
1538
1539 /*******************************************************************************
1540  *      GetEffectInfo - Get information about a particular effect 
1541  */
1542 static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface,
1543                                                   LPDIEFFECTINFOA pdei,
1544                                                   REFGUID guid)
1545 {
1546     JoystickImpl* This = (JoystickImpl*)iface;
1547
1548     TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1549
1550 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1551     return linuxinput_get_info_A(This->joyfd, guid, pdei); 
1552 #else
1553     return DI_OK;
1554 #endif
1555 }
1556
1557 static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface,
1558                                                   LPDIEFFECTINFOW pdei,
1559                                                   REFGUID guid)
1560 {
1561     JoystickImpl* This = (JoystickImpl*)iface;
1562             
1563     TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1564         
1565 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1566     return linuxinput_get_info_W(This->joyfd, guid, pdei);
1567 #else
1568     return DI_OK;
1569 #endif
1570 }
1571
1572 /*******************************************************************************
1573  *      GetForceFeedbackState - Get information about the device's FF state 
1574  */
1575 static HRESULT WINAPI JoystickAImpl_GetForceFeedbackState(
1576         LPDIRECTINPUTDEVICE8A iface,
1577         LPDWORD pdwOut)
1578 {
1579     JoystickImpl* This = (JoystickImpl*)iface;
1580
1581     TRACE("(this=%p,%p)\n", This, pdwOut);
1582
1583     (*pdwOut) = 0;
1584
1585 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1586     /* DIGFFS_STOPPED is the only mandatory flag to report */
1587     if (This->ff_state == FF_STATUS_STOPPED)
1588         (*pdwOut) |= DIGFFS_STOPPED;
1589 #endif
1590
1591     return DI_OK;
1592 }
1593
1594 /*******************************************************************************
1595  *      SendForceFeedbackCommand - Send a command to the device's FF system
1596  */
1597 static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(
1598         LPDIRECTINPUTDEVICE8A iface,
1599         DWORD dwFlags)
1600 {
1601     JoystickImpl* This = (JoystickImpl*)iface;
1602     TRACE("(this=%p,%d)\n", This, dwFlags);
1603
1604 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1605     if (dwFlags == DISFFC_STOPALL) {
1606         /* Stop all effects */
1607         EffectListItem* itr = This->top_effect;
1608         while (itr) {
1609             IDirectInputEffect_Stop(itr->ref);
1610             itr = itr->next;
1611         }
1612     } else if (dwFlags == DISFFC_RESET) {
1613         /* Stop, unload, release and free all effects */
1614         /* This returns the device to its "bare" state */
1615         while (This->top_effect) {
1616             EffectListItem* temp = This->top_effect;
1617             IDirectInputEffect_Stop(temp->ref);
1618             IDirectInputEffect_Unload(temp->ref);
1619             IDirectInputEffect_Release(temp->ref);
1620             This->top_effect = temp->next;
1621             HeapFree(GetProcessHeap(), 0, temp);
1622         }
1623     } else if (dwFlags == DISFFC_PAUSE || dwFlags == DISFFC_CONTINUE) {
1624         FIXME("No support for Pause or Continue in linux\n");
1625     } else if (dwFlags == DISFFC_SETACTUATORSOFF 
1626                 || dwFlags == DISFFC_SETACTUATORSON) {
1627         FIXME("No direct actuator control in linux\n");
1628     } else {
1629         FIXME("Unknown Force Feedback Command!\n");
1630         return DIERR_INVALIDPARAM;
1631     }
1632     return DI_OK;
1633 #else
1634     return DIERR_UNSUPPORTED;
1635 #endif
1636 }
1637
1638 /*******************************************************************************
1639  *      EnumCreatedEffectObjects - Enumerate all the effects that have been
1640  *              created for this device.
1641  */
1642 static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects(
1643         LPDIRECTINPUTDEVICE8A iface,
1644         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
1645         LPVOID pvRef,
1646         DWORD dwFlags)
1647 {
1648     /* this function is safe to call on non-ff-enabled builds */
1649
1650     JoystickImpl* This = (JoystickImpl*)iface;
1651     EffectListItem* itr = This->top_effect;
1652     TRACE("(this=%p,%p,%p,%d)\n", This, lpCallback, pvRef, dwFlags);
1653
1654     if (!lpCallback)
1655         return DIERR_INVALIDPARAM;
1656
1657     if (dwFlags != 0)
1658         FIXME("Flags specified, but no flags exist yet (DX9)!\n");
1659
1660     while (itr) {
1661         (*lpCallback)(itr->ref, pvRef);
1662         itr = itr->next;
1663     }
1664
1665     return DI_OK;
1666 }
1667
1668 static const IDirectInputDevice8AVtbl JoystickAvt =
1669 {
1670         IDirectInputDevice2AImpl_QueryInterface,
1671         IDirectInputDevice2AImpl_AddRef,
1672         JoystickAImpl_Release,
1673         JoystickAImpl_GetCapabilities,
1674         JoystickAImpl_EnumObjects,
1675         JoystickAImpl_GetProperty,
1676         JoystickAImpl_SetProperty,
1677         JoystickAImpl_Acquire,
1678         JoystickAImpl_Unacquire,
1679         JoystickAImpl_GetDeviceState,
1680         IDirectInputDevice2AImpl_GetDeviceData,
1681         JoystickAImpl_SetDataFormat,
1682         IDirectInputDevice2AImpl_SetEventNotification,
1683         IDirectInputDevice2AImpl_SetCooperativeLevel,
1684         IDirectInputDevice2AImpl_GetObjectInfo,
1685         IDirectInputDevice2AImpl_GetDeviceInfo,
1686         IDirectInputDevice2AImpl_RunControlPanel,
1687         IDirectInputDevice2AImpl_Initialize,
1688         JoystickAImpl_CreateEffect,
1689         JoystickAImpl_EnumEffects,
1690         JoystickAImpl_GetEffectInfo,
1691         JoystickAImpl_GetForceFeedbackState,
1692         JoystickAImpl_SendForceFeedbackCommand,
1693         JoystickAImpl_EnumCreatedEffectObjects,
1694         IDirectInputDevice2AImpl_Escape,
1695         JoystickAImpl_Poll,
1696         IDirectInputDevice2AImpl_SendDeviceData,
1697         IDirectInputDevice7AImpl_EnumEffectsInFile,
1698         IDirectInputDevice7AImpl_WriteEffectToFile,
1699         IDirectInputDevice8AImpl_BuildActionMap,
1700         IDirectInputDevice8AImpl_SetActionMap,
1701         IDirectInputDevice8AImpl_GetImageInfo
1702 };
1703
1704 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
1705 # define XCAST(fun)     (typeof(JoystickWvt.fun))
1706 #else
1707 # define XCAST(fun)     (void*)
1708 #endif
1709
1710 static const IDirectInputDevice8WVtbl JoystickWvt =
1711 {
1712         IDirectInputDevice2WImpl_QueryInterface,
1713         XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
1714         XCAST(Release)JoystickAImpl_Release,
1715         XCAST(GetCapabilities)JoystickAImpl_GetCapabilities,
1716         JoystickWImpl_EnumObjects,
1717         XCAST(GetProperty)JoystickAImpl_GetProperty,
1718         XCAST(SetProperty)JoystickAImpl_SetProperty,
1719         XCAST(Acquire)JoystickAImpl_Acquire,
1720         XCAST(Unacquire)JoystickAImpl_Unacquire,
1721         XCAST(GetDeviceState)JoystickAImpl_GetDeviceState,
1722         XCAST(GetDeviceData)IDirectInputDevice2AImpl_GetDeviceData,
1723         XCAST(SetDataFormat)JoystickAImpl_SetDataFormat,
1724         XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification,
1725         XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
1726         IDirectInputDevice2WImpl_GetObjectInfo,
1727         IDirectInputDevice2WImpl_GetDeviceInfo,
1728         XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
1729         XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
1730         XCAST(CreateEffect)JoystickAImpl_CreateEffect,
1731         JoystickWImpl_EnumEffects,
1732         JoystickWImpl_GetEffectInfo,
1733         XCAST(GetForceFeedbackState)JoystickAImpl_GetForceFeedbackState,
1734         XCAST(SendForceFeedbackCommand)JoystickAImpl_SendForceFeedbackCommand,
1735         XCAST(EnumCreatedEffectObjects)JoystickAImpl_EnumCreatedEffectObjects,
1736         XCAST(Escape)IDirectInputDevice2AImpl_Escape,
1737         XCAST(Poll)JoystickAImpl_Poll,
1738         XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
1739         IDirectInputDevice7WImpl_EnumEffectsInFile,
1740         IDirectInputDevice7WImpl_WriteEffectToFile,
1741         IDirectInputDevice8WImpl_BuildActionMap,
1742         IDirectInputDevice8WImpl_SetActionMap,
1743         IDirectInputDevice8WImpl_GetImageInfo
1744 };
1745 #undef XCAST
1746
1747 #else  /* HAVE_CORRECT_LINUXINPUT_H */
1748
1749 const struct dinput_device joystick_linuxinput_device = {
1750   "Wine Linux-input joystick driver",
1751   NULL,
1752   NULL,
1753   NULL,
1754   NULL
1755 };
1756
1757 #endif  /* HAVE_CORRECT_LINUXINPUT_H */