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