mshtml: Implement HTMLElement_insertAdjacentHTML and HTMLElement_insertAdjacentText.
[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 # undef SW_MAX
48 # if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE)
49 #  define HAVE_CORRECT_LINUXINPUT_H
50 # endif
51 #endif
52 #ifdef HAVE_SYS_POLL_H
53 # include <sys/poll.h>
54 #endif
55
56 #include "wine/debug.h"
57 #include "wine/unicode.h"
58 #include "windef.h"
59 #include "winbase.h"
60 #include "winerror.h"
61 #include "dinput.h"
62
63 #include "dinput_private.h"
64 #include "device_private.h"
65
66 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
67
68 #ifdef HAVE_CORRECT_LINUXINPUT_H
69
70 #define EVDEVPREFIX     "/dev/input/event"
71
72 /* Wine joystick driver object instances */
73 #define WINE_JOYSTICK_MAX_AXES    8
74 #define WINE_JOYSTICK_MAX_POVS    4
75 #define WINE_JOYSTICK_MAX_BUTTONS 128
76
77 typedef struct EffectListItem EffectListItem;
78 struct EffectListItem
79 {
80         LPDIRECTINPUTEFFECT ref;
81         struct EffectListItem* next;
82 };
83
84 /* implemented in effect_linuxinput.c */
85 HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, LPDIRECTINPUTEFFECT* peff);
86 HRESULT linuxinput_get_info_A(int fd, REFGUID rguid, LPDIEFFECTINFOA info);
87 HRESULT linuxinput_get_info_W(int fd, REFGUID rguid, LPDIEFFECTINFOW info);
88
89 typedef struct JoystickImpl JoystickImpl;
90 static const IDirectInputDevice8AVtbl JoystickAvt;
91 static const IDirectInputDevice8WVtbl JoystickWvt;
92
93 struct JoyDev {
94         char *device;
95         char *name;
96         GUID guid;
97
98         int has_ff;
99         int num_effects;
100
101         /* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */
102         BYTE                            evbits[(EV_MAX+7)/8];
103         BYTE                            absbits[(ABS_MAX+7)/8];
104         BYTE                            keybits[(KEY_MAX+7)/8];
105         BYTE                            ffbits[(FF_MAX+7)/8];   
106
107 #define AXIS_ABS     0
108 #define AXIS_ABSMIN  1
109 #define AXIS_ABSMAX  2
110 #define AXIS_ABSFUZZ 3
111 #define AXIS_ABSFLAT 4
112
113         /* data returned by the EVIOCGABS() ioctl */
114         int                             axes[ABS_MAX][5];
115 };
116
117 struct ObjProps
118 {
119         /* what we have */
120         LONG                            havemax;
121         LONG                            havemin;
122         /* what range and deadzone the game wants */
123         LONG                            wantmin;
124         LONG                            wantmax;
125         LONG                            deadzone;
126 };
127
128 struct JoystickImpl
129 {
130         struct IDirectInputDevice2AImpl base;
131
132         struct JoyDev                  *joydev;
133
134         /* joystick private */
135         int                             joyfd;
136
137         DIJOYSTATE2                     js;
138
139         struct ObjProps                 props[ABS_MAX];
140
141         int                             axes[ABS_MAX];
142
143         /* LUT for KEY_ to offset in rgbButtons */
144         BYTE                            buttons[KEY_MAX];
145
146         DWORD                           numAxes;
147         DWORD                           numPOVs;
148         DWORD                           numButtons;
149
150         /* Force feedback variables */
151         EffectListItem*                 top_effect;
152         int                             ff_state;
153 };
154
155 static void fake_current_js_state(JoystickImpl *ji);
156 static DWORD map_pov(int event_value, int is_x);
157 static void find_joydevs(void);
158
159 /* This GUID is slightly different from the linux joystick one. Take note. */
160 static const GUID DInput_Wine_Joystick_Base_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */
161   0x9e573eda,
162   0x7734,
163   0x11d2,
164   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
165 };
166
167 #define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7)))
168
169 #define MAX_JOYDEV 64
170
171 static int have_joydevs = -1;
172 static struct JoyDev *joydevs = NULL;
173
174 static void find_joydevs(void)
175 {
176   int i;
177
178   if (have_joydevs!=-1) {
179     return;
180   }
181
182   have_joydevs = 0;
183
184   for (i=0;i<MAX_JOYDEV;i++) {
185     char        buf[MAX_PATH];
186     struct JoyDev joydev = {0};
187     int fd;
188     int no_ff_check = 0;
189     int j;
190
191     snprintf(buf,MAX_PATH,EVDEVPREFIX"%d",i);
192     buf[MAX_PATH-1] = 0;
193
194     if ((fd=open(buf, O_RDWR))==-1) {
195       fd = open(buf, O_RDONLY);
196       no_ff_check = 1;
197     }
198
199     if (fd!=-1) {
200       if ((-1==ioctl(fd,EVIOCGBIT(0,sizeof(joydev.evbits)),joydev.evbits))) {
201         perror("EVIOCGBIT 0");
202         close(fd);
203         continue; 
204       }
205       if (-1==ioctl(fd,EVIOCGBIT(EV_ABS,sizeof(joydev.absbits)),joydev.absbits)) {
206         perror("EVIOCGBIT EV_ABS");
207         close(fd);
208         continue;
209       }
210       if (-1==ioctl(fd,EVIOCGBIT(EV_KEY,sizeof(joydev.keybits)),joydev.keybits)) {
211         perror("EVIOCGBIT EV_KEY");
212         close(fd);
213         continue;
214       }
215       /* A true joystick has at least axis X and Y, and at least 1
216        * button. copied from linux/drivers/input/joydev.c */
217       if (test_bit(joydev.absbits,ABS_X) && test_bit(joydev.absbits,ABS_Y) &&
218           (   test_bit(joydev.keybits,BTN_TRIGGER)      ||
219               test_bit(joydev.keybits,BTN_A)    ||
220               test_bit(joydev.keybits,BTN_1)
221           )
222          ) {
223
224         joydev.device = strdup(buf);
225
226         if (-1!=ioctl(fd, EVIOCGNAME(MAX_PATH-1), buf)) {
227           buf[MAX_PATH-1] = 0;
228           joydev.name = strdup(buf);
229         } else {
230           joydev.name = joydev.device;
231         }
232
233         joydev.guid = DInput_Wine_Joystick_Base_GUID;
234         joydev.guid.Data3 += have_joydevs;
235
236         TRACE("Found a joystick on %s: %s (%s)\n", 
237             joydev.device, joydev.name, 
238             debugstr_guid(&joydev.guid)
239             );
240
241 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
242         if (!no_ff_check &&
243             test_bit(joydev.evbits, EV_FF) &&
244             ioctl(fd, EVIOCGBIT(EV_FF, sizeof(joydev.ffbits)), joydev.ffbits) != -1 &&
245             ioctl(fd, EVIOCGEFFECTS, &joydev.num_effects) != -1 &&
246             joydev.num_effects > 0)
247         {
248             TRACE(" ... with force feedback\n");
249             joydev.has_ff = 1;
250         }
251 #endif
252
253         for (j=0;j<ABS_MAX;j++) {
254           if (test_bit(joydev.absbits,j)) {
255             if (-1!=ioctl(fd,EVIOCGABS(j),&(joydev.axes[j]))) {
256               TRACE(" ... with axis %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n",
257                   j,
258                   joydev.axes[j][AXIS_ABS],
259                   joydev.axes[j][AXIS_ABSMIN],
260                   joydev.axes[j][AXIS_ABSMAX],
261                   joydev.axes[j][AXIS_ABSFUZZ],
262                   joydev.axes[j][AXIS_ABSFLAT]
263                   );
264             }
265           }
266         }
267
268         if (have_joydevs==0) {
269           joydevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct JoyDev));
270         } else {
271           HeapReAlloc(GetProcessHeap(), 0, joydevs, (1+have_joydevs) * sizeof(struct JoyDev));
272         }
273         memcpy(joydevs+have_joydevs, &joydev, sizeof(struct JoyDev));
274         have_joydevs++;
275       }
276
277       close(fd);
278     }
279   }
280 }
281
282 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
283 {
284   find_joydevs();
285
286   if (id >= have_joydevs) {
287     return FALSE;
288   }
289  
290   if (!((dwDevType == 0) ||
291         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 0x0800)) ||
292         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
293     return FALSE;
294
295 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
296   if (dwFlags & DIEDFL_FORCEFEEDBACK)
297     return FALSE;
298 #endif
299
300   if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) {
301     lpddi->guidInstance = joydevs[id].guid;
302     lpddi->guidProduct  = DInput_Wine_Joystick_Base_GUID;
303
304     lpddi->guidFFDriver = GUID_NULL;
305     if (version >= 0x0800)
306       lpddi->dwDevType    = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
307     else
308       lpddi->dwDevType    = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
309
310     strcpy(lpddi->tszInstanceName, joydevs[id].name);
311     strcpy(lpddi->tszProductName, joydevs[id].device);
312     return TRUE;
313   }
314   return FALSE;
315 }
316
317 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
318 {
319   find_joydevs();
320
321   if (id >= have_joydevs) {
322     return FALSE;
323   }
324
325   if (!((dwDevType == 0) ||
326         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 0x0800)) ||
327         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
328     return FALSE;
329
330 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
331   if (dwFlags & DIEDFL_FORCEFEEDBACK)
332     return FALSE;
333 #endif
334
335   if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) {
336     lpddi->guidInstance = joydevs[id].guid;
337     lpddi->guidProduct  = DInput_Wine_Joystick_Base_GUID;
338
339     lpddi->guidFFDriver = GUID_NULL;
340     if (version >= 0x0800)
341       lpddi->dwDevType    = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
342     else
343       lpddi->dwDevType    = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
344
345     MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
346     MultiByteToWideChar(CP_ACP, 0, joydevs[id].device, -1, lpddi->tszProductName, MAX_PATH);
347     return TRUE;
348   }
349   return FALSE;
350 }
351
352 static JoystickImpl *alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput, struct JoyDev *joydev)
353 {
354     JoystickImpl* newDevice;
355     LPDIDATAFORMAT df = NULL;
356     int i, idx = 0;
357
358     newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl));
359     if (!newDevice) return NULL;
360
361   newDevice->base.lpVtbl = jvt;
362   newDevice->base.ref = 1;
363   memcpy(&newDevice->base.guid, rguid, sizeof(*rguid));
364   InitializeCriticalSection(&newDevice->base.crit);
365   newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit");
366   newDevice->joyfd = -1;
367   newDevice->base.dinput = dinput;
368   newDevice->joydev = joydev;
369 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
370   newDevice->ff_state = FF_STATUS_STOPPED;
371 #endif
372
373     /* Create copy of default data format */
374     if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto failed;
375     memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
376     if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed;
377
378     /* Supported Axis & POVs should map 1-to-1 */
379     for (i = 0; i < WINE_JOYSTICK_MAX_AXES; i++)
380     {
381         if (!test_bit(newDevice->joydev->absbits, i)) {
382             newDevice->axes[i] = -1;
383             continue;
384         }
385
386         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i], df->dwObjSize);
387         newDevice->axes[i] = idx;
388         newDevice->props[idx].havemin = newDevice->joydev->axes[i][AXIS_ABSMIN];
389         newDevice->props[idx].havemax = newDevice->joydev->axes[i][AXIS_ABSMAX];
390         newDevice->props[idx].wantmin = 0;
391         newDevice->props[idx].wantmax = 0xffff;
392         newDevice->props[idx].deadzone = 0;
393         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(newDevice->numAxes++) | DIDFT_ABSAXIS;
394     }
395
396     for (i = 0; i < WINE_JOYSTICK_MAX_POVS; i++)
397     {
398         if (!test_bit(newDevice->joydev->absbits, ABS_HAT0X + i * 2) ||
399             !test_bit(newDevice->joydev->absbits, ABS_HAT0Y + i * 2)) {
400             newDevice->axes[ABS_HAT0X + i * 2] = newDevice->axes[ABS_HAT0Y + i * 2] = -1;
401             continue;
402         }
403
404         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + WINE_JOYSTICK_MAX_AXES], df->dwObjSize);
405         newDevice->axes[ABS_HAT0X + i * 2] = newDevice->axes[ABS_HAT0Y + i * 2] = i;
406         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(newDevice->numPOVs++) | DIDFT_POV;
407     }
408
409     /* Buttons can be anywhere, so check all */
410     for (i = 0; i < KEY_MAX && newDevice->numButtons < WINE_JOYSTICK_MAX_BUTTONS; i++)
411     {
412         if (!test_bit(newDevice->joydev->keybits, i)) continue;
413
414         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[newDevice->numButtons + WINE_JOYSTICK_MAX_AXES + WINE_JOYSTICK_MAX_POVS], df->dwObjSize);
415         newDevice->buttons[i] = 0x80 | newDevice->numButtons;
416         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(newDevice->numButtons++) | DIDFT_PSHBUTTON;
417     }
418     df->dwNumObjs = idx;
419
420     fake_current_js_state(newDevice);
421
422     newDevice->base.data_format.wine_df = df;
423     IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->base.dinput);
424     return newDevice;
425
426 failed:
427     if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
428     HeapFree(GetProcessHeap(), 0, df);
429     HeapFree(GetProcessHeap(), 0, newDevice);
430     return NULL;
431 }
432
433 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
434 {
435   int i;
436
437   find_joydevs();
438
439   for (i=0; i<have_joydevs; i++) {
440     if (IsEqualGUID(&GUID_Joystick,rguid) ||
441         IsEqualGUID(&joydevs[i].guid,rguid)
442         ) {
443       if ((riid == NULL) ||
444           IsEqualGUID(&IID_IDirectInputDeviceA,riid) ||
445           IsEqualGUID(&IID_IDirectInputDevice2A,riid) ||
446           IsEqualGUID(&IID_IDirectInputDevice7A,riid) ||
447           IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
448         *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &JoystickAvt, dinput, &joydevs[i]);
449         TRACE("Creating a Joystick device (%p)\n", *pdev);
450         if (*pdev==0) {
451           ERR("out of memory\n");
452           return DIERR_OUTOFMEMORY;
453         }
454         return DI_OK;
455       } else {
456         return DIERR_NOINTERFACE;
457       }
458     }
459   }
460
461   return DIERR_DEVICENOTREG;
462 }
463
464
465 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
466 {
467   int i;
468
469   find_joydevs();
470
471   for (i=0; i<have_joydevs; i++) {
472     if (IsEqualGUID(&GUID_Joystick,rguid) ||
473         IsEqualGUID(&joydevs[i].guid,rguid)
474         ) {
475       if ((riid == NULL) ||
476           IsEqualGUID(&IID_IDirectInputDeviceW,riid) ||
477           IsEqualGUID(&IID_IDirectInputDevice2W,riid) ||
478           IsEqualGUID(&IID_IDirectInputDevice7W,riid) ||
479           IsEqualGUID(&IID_IDirectInputDevice8W,riid)) {
480         *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &JoystickWvt, dinput, &joydevs[i]);
481         TRACE("Creating a Joystick device (%p)\n", *pdev);
482         if (*pdev==0) {
483           ERR("out of memory\n");
484           return DIERR_OUTOFMEMORY;
485         }
486         return DI_OK;
487       } else {
488         return DIERR_NOINTERFACE;
489       }
490     }
491   }
492
493   return DIERR_DEVICENOTREG;
494 }
495
496 const struct dinput_device joystick_linuxinput_device = {
497   "Wine Linux-input joystick driver",
498   joydev_enum_deviceA,
499   joydev_enum_deviceW,
500   joydev_create_deviceA,
501   joydev_create_deviceW
502 };
503
504 /******************************************************************************
505   *     Acquire : gets exclusive control of the joystick
506   */
507 static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
508 {
509     JoystickImpl *This = (JoystickImpl *)iface;
510     HRESULT res;
511
512     TRACE("(this=%p)\n",This);
513
514     res = IDirectInputDevice2AImpl_Acquire(iface);
515     if (res==DI_OK) {
516       if (-1==(This->joyfd=open(This->joydev->device,O_RDWR))) {
517         if (-1==(This->joyfd=open(This->joydev->device,O_RDONLY))) {
518           /* Couldn't open the device at all */
519           perror(This->joydev->device);
520           IDirectInputDevice2AImpl_Unacquire(iface);
521           return DIERR_NOTFOUND;
522         } else {
523           /* Couldn't open in r/w but opened in read-only. */
524           WARN("Could not open %s in read-write mode.  Force feedback will be disabled.\n", This->joydev->device);
525         }
526       }
527     }
528
529     return res;
530 }
531
532 /******************************************************************************
533   *     Unacquire : frees the joystick
534   */
535 static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
536 {
537     JoystickImpl *This = (JoystickImpl *)iface;
538     HRESULT res;
539
540     TRACE("(this=%p)\n",This);
541     res = IDirectInputDevice2AImpl_Unacquire(iface);
542     if (res==DI_OK && This->joyfd!=-1) {
543       close(This->joyfd);
544       This->joyfd = -1;
545     }
546     return res;
547 }
548
549 /*
550  * This maps the read value (from the input event) to a value in the
551  * 'wanted' range. It also autodetects the possible range of the axis and
552  * adapts values accordingly.
553  */
554 static int
555 map_axis(JoystickImpl* This, int axis, int val) {
556     int hmax = This->props[axis].havemax;
557     int hmin = This->props[axis].havemin;
558     int wmin = This->props[axis].wantmin;
559     int wmax = This->props[axis].wantmax;
560     int ret;
561
562     /* map the value from the hmin-hmax range into the wmin-wmax range */
563     ret = MulDiv( val - hmin, wmax - wmin, hmax - hmin ) + wmin;
564
565     TRACE("hmin=%d hmax=%d wmin=%d wmax=%d val=%d ret=%d\n", hmin, hmax, wmin, wmax, val, ret);
566
567 #if 0
568     /* deadzone doesn't work comfortably enough right now. needs more testing*/
569     if ((ret > -deadz/2 ) && (ret < deadz/2)) {
570         FIXME("%d in deadzone, return mid.\n",val);
571         return (wmax-wmin)/2+wmin;
572     }
573 #endif
574     return ret;
575 }
576
577 /* 
578  * set the current state of the js device as it would be with the middle
579  * values on the axes
580  */
581 static void fake_current_js_state(JoystickImpl *ji)
582 {
583         int i;
584         /* center the axes */
585         ji->js.lX           = ji->axes[ABS_X]!=-1        ? map_axis(ji, ji->axes[ABS_X],        ji->joydev->axes[ABS_X       ][AXIS_ABS]) : 0;
586         ji->js.lY           = ji->axes[ABS_Y]!=-1        ? map_axis(ji, ji->axes[ABS_Y],        ji->joydev->axes[ABS_Y       ][AXIS_ABS]) : 0;
587         ji->js.lZ           = ji->axes[ABS_Z]!=-1        ? map_axis(ji, ji->axes[ABS_Z],        ji->joydev->axes[ABS_Z       ][AXIS_ABS]) : 0;
588         ji->js.lRx          = ji->axes[ABS_RX]!=-1       ? map_axis(ji, ji->axes[ABS_RX],       ji->joydev->axes[ABS_RX      ][AXIS_ABS]) : 0;
589         ji->js.lRy          = ji->axes[ABS_RY]!=-1       ? map_axis(ji, ji->axes[ABS_RY],       ji->joydev->axes[ABS_RY      ][AXIS_ABS]) : 0;
590         ji->js.lRz          = ji->axes[ABS_RZ]!=-1       ? map_axis(ji, ji->axes[ABS_RZ],       ji->joydev->axes[ABS_RZ      ][AXIS_ABS]) : 0;
591         ji->js.rglSlider[0] = ji->axes[ABS_THROTTLE]!=-1 ? map_axis(ji, ji->axes[ABS_THROTTLE], ji->joydev->axes[ABS_THROTTLE][AXIS_ABS]) : 0;
592         ji->js.rglSlider[1] = ji->axes[ABS_RUDDER]!=-1   ? map_axis(ji, ji->axes[ABS_RUDDER],   ji->joydev->axes[ABS_RUDDER  ][AXIS_ABS]) : 0;
593         /* POV center is -1 */
594         for (i=0; i<4; i++) {
595                 ji->js.rgdwPOV[i] = -1;
596         }
597 }
598
599 /*
600  * Maps an event value to a DX "clock" position:
601  *           0
602  * 27000    -1 9000
603  *       18000
604  */
605 static DWORD map_pov(int event_value, int is_x) 
606 {
607         DWORD ret = -1;
608         if (is_x) {
609                 if (event_value<0) {
610                         ret = 27000;
611                 } else if (event_value>0) {
612                         ret = 9000;
613                 }
614         } else {
615                 if (event_value<0) {
616                         ret = 0;
617                 } else if (event_value>0) {
618                         ret = 18000;
619                 }
620         }
621         return ret;
622 }
623
624 /* convert wine format offset to user format object index */
625 static void joy_polldev(JoystickImpl *This)
626 {
627     struct pollfd plfd;
628     struct input_event ie;
629
630     if (This->joyfd==-1)
631         return;
632
633     while (1)
634     {
635         LONG value = 0;
636         int inst_id = -1;
637
638         plfd.fd = This->joyfd;
639         plfd.events = POLLIN;
640
641         if (poll(&plfd,1,0) != 1)
642             return;
643
644         /* we have one event, so we can read */
645         if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie)))
646             return;
647
648         TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value);
649         switch (ie.type) {
650         case EV_KEY:    /* button */
651         {
652             int btn = This->buttons[ie.code];
653
654             TRACE("(%p) %d -> %d\n", This, ie.code, btn);
655             if (btn & 0x80)
656             {
657                 btn &= 0x7F;
658                 inst_id = DIDFT_MAKEINSTANCE(btn) | DIDFT_PSHBUTTON;
659                 This->js.rgbButtons[btn] = value = ie.value ? 0x80 : 0x00;
660             }
661             break;
662         }
663         case EV_ABS:
664         {
665             int axis = This->axes[ie.code];
666             if (axis==-1) {
667                 break;
668             }
669             inst_id = DIDFT_MAKEINSTANCE(axis) | (ie.code < ABS_HAT0X ? DIDFT_ABSAXIS : DIDFT_POV);
670             value = map_axis(This, axis, ie.value);
671
672             switch (ie.code) {
673             case ABS_X:         This->js.lX  = value; break;
674             case ABS_Y:         This->js.lY  = value; break;
675             case ABS_Z:         This->js.lZ  = value; break;
676             case ABS_RX:        This->js.lRx = value; break;
677             case ABS_RY:        This->js.lRy = value; break;
678             case ABS_RZ:        This->js.lRz = value; break;
679             case ABS_THROTTLE:  This->js.rglSlider[0] = value; break;
680             case ABS_RUDDER:    This->js.rglSlider[1] = value; break;
681             case ABS_HAT0X:
682             case ABS_HAT0Y:
683                 This->js.rgdwPOV[0] = value = map_pov(ie.value, ie.code==ABS_HAT0X);
684                 break;
685             case ABS_HAT1X:
686             case ABS_HAT1Y:
687                 This->js.rgdwPOV[1] = value = map_pov(ie.value, ie.code==ABS_HAT1X);
688                 break;
689             case ABS_HAT2X:
690             case ABS_HAT2Y:
691                 This->js.rgdwPOV[2] = value  = map_pov(ie.value, ie.code==ABS_HAT2X);
692                 break;
693             case ABS_HAT3X:
694             case ABS_HAT3Y:
695                 This->js.rgdwPOV[3] = value  = map_pov(ie.value, ie.code==ABS_HAT3X);
696                 break;
697             default:
698                 FIXME("unhandled joystick axis event (code %d, value %d)\n",ie.code,ie.value);
699                 break;
700             }
701             break;
702         }
703 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
704         case EV_FF_STATUS:
705             This->ff_state = ie.value;
706             break;
707 #endif
708 #ifdef EV_SYN
709         case EV_SYN:
710             /* there is nothing to do */
711             break;
712 #endif
713         default:
714             FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code);
715             break;
716         }
717         if (inst_id >= 0)
718             queue_event((LPDIRECTINPUTDEVICE8A)This,
719                         id_to_offset(&This->base.data_format, inst_id),
720                         value, ie.time.tv_usec, This->base.dinput->evsequence++);
721     }
722 }
723
724 /******************************************************************************
725   *     GetDeviceState : returns the "state" of the joystick.
726   *
727   */
728 static HRESULT WINAPI JoystickAImpl_GetDeviceState(
729         LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr
730 ) {
731     JoystickImpl *This = (JoystickImpl *)iface;
732
733     TRACE("(this=%p,0x%08x,%p)\n", This, len, ptr);
734
735     if (This->joyfd==-1) {
736         WARN("not acquired\n");
737         return DIERR_NOTACQUIRED;
738     }
739
740     joy_polldev(This);
741
742     /* convert and copy data to user supplied buffer */
743     fill_DataFormat(ptr, &This->js, &This->base.data_format);
744
745     return DI_OK;
746 }
747
748 /******************************************************************************
749   *     SetProperty : change input device properties
750   */
751 static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface,
752                                             REFGUID rguid,
753                                             LPCDIPROPHEADER ph)
754 {
755   JoystickImpl *This = (JoystickImpl *)iface;
756
757   if (!ph) {
758     WARN("invalid argument\n");
759     return DIERR_INVALIDPARAM;
760   }
761
762   TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
763   TRACE("ph.dwSize = %d, ph.dwHeaderSize =%d, ph.dwObj = %d, ph.dwHow= %d\n",
764         ph->dwSize, ph->dwHeaderSize, ph->dwObj, ph->dwHow);
765
766   if (!HIWORD(rguid)) {
767     switch (LOWORD(rguid)) {
768     case (DWORD)DIPROP_RANGE: {
769       LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph;
770
771       if (ph->dwHow == DIPH_DEVICE) {
772         int i;
773         TRACE("proprange(%d,%d) all\n", pr->lMin, pr->lMax);
774         for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) {
775           This->props[i].wantmin = pr->lMin;
776           This->props[i].wantmax = pr->lMax;
777         }
778       } else {
779         int obj = find_property(&This->base.data_format, ph);
780
781         TRACE("proprange(%d,%d) obj=%d\n", pr->lMin, pr->lMax, obj);
782         if (obj >= 0) {
783           This->props[obj].wantmin = pr->lMin;
784           This->props[obj].wantmax = pr->lMax;
785         }
786       }
787       fake_current_js_state(This);
788       break;
789     }
790     case (DWORD)DIPROP_DEADZONE: {
791       LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
792       if (ph->dwHow == DIPH_DEVICE) {
793         int i;
794         TRACE("deadzone(%d) all\n", pd->dwData);
795         for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) {
796           This->props[i].deadzone = pd->dwData;
797         }
798       } else {
799         int obj = find_property(&This->base.data_format, ph);
800
801         TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj);
802         if (obj >= 0) {
803           This->props[obj].deadzone = pd->dwData;
804         }
805       }
806       fake_current_js_state(This);
807       break;
808     }
809     case (DWORD)DIPROP_CALIBRATIONMODE: {
810       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
811       FIXME("DIPROP_CALIBRATIONMODE(%d)\n", pd->dwData);
812       break;
813     }
814     default:
815       return IDirectInputDevice2AImpl_SetProperty(iface, rguid, ph);
816     }
817   }
818   return DI_OK;
819 }
820
821 static HRESULT WINAPI JoystickAImpl_GetCapabilities(
822         LPDIRECTINPUTDEVICE8A iface,
823         LPDIDEVCAPS lpDIDevCaps)
824 {
825     JoystickImpl *This = (JoystickImpl *)iface;
826
827     TRACE("%p->(%p)\n",iface,lpDIDevCaps);
828
829     if (!lpDIDevCaps) {
830         WARN("invalid pointer\n");
831         return E_POINTER;
832     }
833
834     if (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) {
835         WARN("invalid argument\n");
836         return DIERR_INVALIDPARAM;
837     }
838
839     lpDIDevCaps->dwFlags        = DIDC_ATTACHED;
840     if (This->base.dinput->dwVersion >= 0x0800)
841         lpDIDevCaps->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
842     else
843         lpDIDevCaps->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
844
845     if (This->joydev->has_ff) 
846          lpDIDevCaps->dwFlags |= DIDC_FORCEFEEDBACK;
847
848     lpDIDevCaps->dwAxes = This->numAxes;
849     lpDIDevCaps->dwButtons = This->numButtons;
850     lpDIDevCaps->dwPOVs = This->numPOVs;
851
852     return DI_OK;
853 }
854
855 static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) {
856     JoystickImpl *This = (JoystickImpl *)iface;
857     TRACE("(%p)\n",This);
858
859     if (This->joyfd==-1) {
860       return DIERR_NOTACQUIRED;
861     }
862
863     joy_polldev(This);
864     return DI_OK;
865 }
866
867 /******************************************************************************
868   *     GetProperty : get input device properties
869   */
870 static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
871                                                 REFGUID rguid,
872                                                 LPDIPROPHEADER pdiph)
873 {
874     JoystickImpl *This = (JoystickImpl *)iface;
875
876     TRACE("(this=%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph);
877     _dump_DIPROPHEADER(pdiph);
878
879     if (HIWORD(rguid)) return DI_OK;
880
881     switch (LOWORD(rguid)) {
882     case (DWORD) DIPROP_RANGE:
883     {
884         LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
885         int obj = find_property(&This->base.data_format, pdiph);
886
887         if (obj < 0) return DIERR_OBJECTNOTFOUND;
888
889         pr->lMin = This->props[obj].wantmin;
890         pr->lMax = This->props[obj].wantmax;
891         TRACE("range(%d, %d) obj=%d\n", pr->lMin, pr->lMax, obj);
892         break;
893     }
894     case (DWORD) DIPROP_DEADZONE:
895     {
896         LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
897         int obj = find_property(&This->base.data_format, pdiph);
898
899         if (obj < 0) return DIERR_OBJECTNOTFOUND;
900
901         pd->dwData = This->props[obj].deadzone;
902         TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj);
903         break;
904     }
905
906     default:
907         return IDirectInputDevice2AImpl_GetProperty(iface, rguid, pdiph);
908     }
909
910     return DI_OK;
911 }
912
913 /******************************************************************************
914   *     GetObjectInfo : get information about a device object such as a button
915   *                     or axis
916   */
917 static HRESULT WINAPI JoystickWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface,
918         LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow)
919 {
920     static const WCHAR axisW[] = {'A','x','i','s',' ','%','d',0};
921     static const WCHAR povW[] = {'P','O','V',' ','%','d',0};
922     static const WCHAR buttonW[] = {'B','u','t','t','o','n',' ','%','d',0};
923     HRESULT res;
924
925     res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow);
926     if (res != DI_OK) return res;
927
928     if      (pdidoi->dwType & DIDFT_AXIS)
929         sprintfW(pdidoi->tszName, axisW, DIDFT_GETINSTANCE(pdidoi->dwType));
930     else if (pdidoi->dwType & DIDFT_POV)
931         sprintfW(pdidoi->tszName, povW, DIDFT_GETINSTANCE(pdidoi->dwType));
932     else if (pdidoi->dwType & DIDFT_BUTTON)
933         sprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType));
934
935     _dump_OBJECTINSTANCEW(pdidoi);
936     return res;
937 }
938
939 static HRESULT WINAPI JoystickAImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8A iface,
940         LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow)
941 {
942     HRESULT res;
943     DIDEVICEOBJECTINSTANCEW didoiW;
944     DWORD dwSize = pdidoi->dwSize;
945
946     didoiW.dwSize = sizeof(didoiW);
947     res = JoystickWImpl_GetObjectInfo((LPDIRECTINPUTDEVICE8W)iface, &didoiW, dwObj, dwHow);
948     if (res != DI_OK) return res;
949
950     memset(pdidoi, 0, pdidoi->dwSize);
951     memcpy(pdidoi, &didoiW, FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, tszName));
952     pdidoi->dwSize = dwSize;
953     WideCharToMultiByte(CP_ACP, 0, didoiW.tszName, -1, pdidoi->tszName,
954                         sizeof(pdidoi->tszName), NULL, NULL);
955
956     return res;
957 }
958
959 /****************************************************************************** 
960   *     CreateEffect - Create a new FF effect with the specified params
961   */
962 static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface,
963                                                  REFGUID rguid,
964                                                  LPCDIEFFECT lpeff,
965                                                  LPDIRECTINPUTEFFECT *ppdef,
966                                                  LPUNKNOWN pUnkOuter)
967 {
968 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
969     EffectListItem* new = NULL;
970     HRESULT retval = DI_OK;
971 #endif
972
973     JoystickImpl* This = (JoystickImpl*)iface;
974     TRACE("(this=%p,%p,%p,%p,%p)\n", This, rguid, lpeff, ppdef, pUnkOuter);
975
976 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
977     TRACE("not available (compiled w/o ff support)\n");
978     *ppdef = NULL;
979     return DI_OK;
980 #else
981
982     new = HeapAlloc(GetProcessHeap(), 0, sizeof(EffectListItem));
983     new->next = This->top_effect;
984     This->top_effect = new;
985
986     retval = linuxinput_create_effect(&(This->joyfd), rguid, &(new->ref));
987     if (retval != DI_OK)
988         return retval;
989
990     if (lpeff != NULL)
991         retval = IDirectInputEffect_SetParameters(new->ref, lpeff, 0);
992     if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED)
993         return retval;
994
995     *ppdef = new->ref;
996
997     if (pUnkOuter != NULL)
998         FIXME("Interface aggregation not implemented.\n");
999
1000     return DI_OK;
1001
1002 #endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */
1003
1004
1005 /*******************************************************************************
1006  *      EnumEffects - Enumerate available FF effects
1007  */
1008 static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface,
1009                                                 LPDIENUMEFFECTSCALLBACKA lpCallback,
1010                                                 LPVOID pvRef,
1011                                                 DWORD dwEffType)
1012 {
1013 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1014     DIEFFECTINFOA dei; /* feif */
1015     DWORD type = DIEFT_GETTYPE(dwEffType);
1016     JoystickImpl* This = (JoystickImpl*)iface;
1017
1018     TRACE("(this=%p,%p,%d) type=%d\n", This, pvRef, dwEffType, type);
1019
1020     dei.dwSize = sizeof(DIEFFECTINFOA);          
1021
1022     if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1023         && test_bit(This->joydev->ffbits, FF_CONSTANT)) {
1024         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1025         (*lpCallback)(&dei, pvRef);
1026     }
1027
1028     if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1029         && test_bit(This->joydev->ffbits, FF_PERIODIC)) {
1030         if (test_bit(This->joydev->ffbits, FF_SQUARE)) {
1031             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1032             (*lpCallback)(&dei, pvRef);
1033         }
1034         if (test_bit(This->joydev->ffbits, FF_SINE)) {
1035             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1036             (*lpCallback)(&dei, pvRef);
1037         }
1038         if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) {
1039             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1040             (*lpCallback)(&dei, pvRef);
1041         }
1042         if (test_bit(This->joydev->ffbits, FF_SAW_UP)) {
1043             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1044             (*lpCallback)(&dei, pvRef);
1045         }
1046         if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) {
1047             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1048             (*lpCallback)(&dei, pvRef);
1049         }
1050     } 
1051
1052     if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1053         && test_bit(This->joydev->ffbits, FF_RAMP)) {
1054         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1055         (*lpCallback)(&dei, pvRef);
1056     }
1057
1058     if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1059         if (test_bit(This->joydev->ffbits, FF_SPRING)) {
1060             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1061             (*lpCallback)(&dei, pvRef);
1062         }
1063         if (test_bit(This->joydev->ffbits, FF_DAMPER)) {
1064             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1065             (*lpCallback)(&dei, pvRef);
1066         }
1067         if (test_bit(This->joydev->ffbits, FF_INERTIA)) {
1068             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1069             (*lpCallback)(&dei, pvRef);
1070         }
1071         if (test_bit(This->joydev->ffbits, FF_FRICTION)) {
1072             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1073             (*lpCallback)(&dei, pvRef);
1074         }
1075     }
1076
1077 #endif
1078
1079     return DI_OK;
1080 }
1081
1082 static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface,
1083                                                 LPDIENUMEFFECTSCALLBACKW lpCallback,
1084                                                 LPVOID pvRef,
1085                                                 DWORD dwEffType)
1086 {
1087 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1088     /* seems silly to duplicate all this code but all the structures and functions
1089      * are actually different (A/W) */
1090     DIEFFECTINFOW dei; /* feif */
1091     DWORD type = DIEFT_GETTYPE(dwEffType);
1092     JoystickImpl* This = (JoystickImpl*)iface;
1093     int xfd = This->joyfd;
1094
1095     TRACE("(this=%p,%p,%d) type=%d fd=%d\n", This, pvRef, dwEffType, type, xfd);
1096
1097     dei.dwSize = sizeof(DIEFFECTINFOW);          
1098
1099     if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1100         && test_bit(This->joydev->ffbits, FF_CONSTANT)) {
1101         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1102         (*lpCallback)(&dei, pvRef);
1103     }
1104
1105     if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1106         && test_bit(This->joydev->ffbits, FF_PERIODIC)) {
1107         if (test_bit(This->joydev->ffbits, FF_SQUARE)) {
1108             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1109             (*lpCallback)(&dei, pvRef);
1110         }
1111         if (test_bit(This->joydev->ffbits, FF_SINE)) {
1112             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1113             (*lpCallback)(&dei, pvRef);
1114         }
1115         if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) {
1116             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1117             (*lpCallback)(&dei, pvRef);
1118         }
1119         if (test_bit(This->joydev->ffbits, FF_SAW_UP)) {
1120             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1121             (*lpCallback)(&dei, pvRef);
1122         }
1123         if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) {
1124             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1125             (*lpCallback)(&dei, pvRef);
1126         }
1127     } 
1128
1129     if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1130         && test_bit(This->joydev->ffbits, FF_RAMP)) {
1131         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1132         (*lpCallback)(&dei, pvRef);
1133     }
1134
1135     if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1136         if (test_bit(This->joydev->ffbits, FF_SPRING)) {
1137             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1138             (*lpCallback)(&dei, pvRef);
1139         }
1140         if (test_bit(This->joydev->ffbits, FF_DAMPER)) {
1141             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1142             (*lpCallback)(&dei, pvRef);
1143         }
1144         if (test_bit(This->joydev->ffbits, FF_INERTIA)) {
1145             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1146             (*lpCallback)(&dei, pvRef);
1147         }
1148         if (test_bit(This->joydev->ffbits, FF_FRICTION)) {
1149             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1150             (*lpCallback)(&dei, pvRef);
1151         }
1152     }
1153
1154     /* return to unacquired state if that's where it was */
1155     if (xfd == -1)
1156         IDirectInputDevice8_Unacquire(iface);
1157 #endif
1158
1159     return DI_OK;
1160 }
1161
1162 /*******************************************************************************
1163  *      GetEffectInfo - Get information about a particular effect 
1164  */
1165 static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface,
1166                                                   LPDIEFFECTINFOA pdei,
1167                                                   REFGUID guid)
1168 {
1169     JoystickImpl* This = (JoystickImpl*)iface;
1170
1171     TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1172
1173 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1174     return linuxinput_get_info_A(This->joyfd, guid, pdei); 
1175 #else
1176     return DI_OK;
1177 #endif
1178 }
1179
1180 static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface,
1181                                                   LPDIEFFECTINFOW pdei,
1182                                                   REFGUID guid)
1183 {
1184     JoystickImpl* This = (JoystickImpl*)iface;
1185             
1186     TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1187         
1188 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1189     return linuxinput_get_info_W(This->joyfd, guid, pdei);
1190 #else
1191     return DI_OK;
1192 #endif
1193 }
1194
1195 /*******************************************************************************
1196  *      GetForceFeedbackState - Get information about the device's FF state 
1197  */
1198 static HRESULT WINAPI JoystickAImpl_GetForceFeedbackState(
1199         LPDIRECTINPUTDEVICE8A iface,
1200         LPDWORD pdwOut)
1201 {
1202     JoystickImpl* This = (JoystickImpl*)iface;
1203
1204     TRACE("(this=%p,%p)\n", This, pdwOut);
1205
1206     (*pdwOut) = 0;
1207
1208 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1209     /* DIGFFS_STOPPED is the only mandatory flag to report */
1210     if (This->ff_state == FF_STATUS_STOPPED)
1211         (*pdwOut) |= DIGFFS_STOPPED;
1212 #endif
1213
1214     return DI_OK;
1215 }
1216
1217 /*******************************************************************************
1218  *      SendForceFeedbackCommand - Send a command to the device's FF system
1219  */
1220 static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(
1221         LPDIRECTINPUTDEVICE8A iface,
1222         DWORD dwFlags)
1223 {
1224     JoystickImpl* This = (JoystickImpl*)iface;
1225     TRACE("(this=%p,%d)\n", This, dwFlags);
1226
1227 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1228     if (dwFlags == DISFFC_STOPALL) {
1229         /* Stop all effects */
1230         EffectListItem* itr = This->top_effect;
1231         while (itr) {
1232             IDirectInputEffect_Stop(itr->ref);
1233             itr = itr->next;
1234         }
1235     } else if (dwFlags == DISFFC_RESET) {
1236         /* Stop, unload, release and free all effects */
1237         /* This returns the device to its "bare" state */
1238         while (This->top_effect) {
1239             EffectListItem* temp = This->top_effect;
1240             IDirectInputEffect_Stop(temp->ref);
1241             IDirectInputEffect_Unload(temp->ref);
1242             IDirectInputEffect_Release(temp->ref);
1243             This->top_effect = temp->next;
1244             HeapFree(GetProcessHeap(), 0, temp);
1245         }
1246     } else if (dwFlags == DISFFC_PAUSE || dwFlags == DISFFC_CONTINUE) {
1247         FIXME("No support for Pause or Continue in linux\n");
1248     } else if (dwFlags == DISFFC_SETACTUATORSOFF 
1249                 || dwFlags == DISFFC_SETACTUATORSON) {
1250         FIXME("No direct actuator control in linux\n");
1251     } else {
1252         FIXME("Unknown Force Feedback Command!\n");
1253         return DIERR_INVALIDPARAM;
1254     }
1255     return DI_OK;
1256 #else
1257     return DIERR_UNSUPPORTED;
1258 #endif
1259 }
1260
1261 /*******************************************************************************
1262  *      EnumCreatedEffectObjects - Enumerate all the effects that have been
1263  *              created for this device.
1264  */
1265 static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects(
1266         LPDIRECTINPUTDEVICE8A iface,
1267         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
1268         LPVOID pvRef,
1269         DWORD dwFlags)
1270 {
1271     /* this function is safe to call on non-ff-enabled builds */
1272
1273     JoystickImpl* This = (JoystickImpl*)iface;
1274     EffectListItem* itr = This->top_effect;
1275     TRACE("(this=%p,%p,%p,%d)\n", This, lpCallback, pvRef, dwFlags);
1276
1277     if (!lpCallback)
1278         return DIERR_INVALIDPARAM;
1279
1280     if (dwFlags != 0)
1281         FIXME("Flags specified, but no flags exist yet (DX9)!\n");
1282
1283     while (itr) {
1284         (*lpCallback)(itr->ref, pvRef);
1285         itr = itr->next;
1286     }
1287
1288     return DI_OK;
1289 }
1290
1291 static const IDirectInputDevice8AVtbl JoystickAvt =
1292 {
1293         IDirectInputDevice2AImpl_QueryInterface,
1294         IDirectInputDevice2AImpl_AddRef,
1295         IDirectInputDevice2AImpl_Release,
1296         JoystickAImpl_GetCapabilities,
1297         IDirectInputDevice2AImpl_EnumObjects,
1298         JoystickAImpl_GetProperty,
1299         JoystickAImpl_SetProperty,
1300         JoystickAImpl_Acquire,
1301         JoystickAImpl_Unacquire,
1302         JoystickAImpl_GetDeviceState,
1303         IDirectInputDevice2AImpl_GetDeviceData,
1304         IDirectInputDevice2AImpl_SetDataFormat,
1305         IDirectInputDevice2AImpl_SetEventNotification,
1306         IDirectInputDevice2AImpl_SetCooperativeLevel,
1307         JoystickAImpl_GetObjectInfo,
1308         IDirectInputDevice2AImpl_GetDeviceInfo,
1309         IDirectInputDevice2AImpl_RunControlPanel,
1310         IDirectInputDevice2AImpl_Initialize,
1311         JoystickAImpl_CreateEffect,
1312         JoystickAImpl_EnumEffects,
1313         JoystickAImpl_GetEffectInfo,
1314         JoystickAImpl_GetForceFeedbackState,
1315         JoystickAImpl_SendForceFeedbackCommand,
1316         JoystickAImpl_EnumCreatedEffectObjects,
1317         IDirectInputDevice2AImpl_Escape,
1318         JoystickAImpl_Poll,
1319         IDirectInputDevice2AImpl_SendDeviceData,
1320         IDirectInputDevice7AImpl_EnumEffectsInFile,
1321         IDirectInputDevice7AImpl_WriteEffectToFile,
1322         IDirectInputDevice8AImpl_BuildActionMap,
1323         IDirectInputDevice8AImpl_SetActionMap,
1324         IDirectInputDevice8AImpl_GetImageInfo
1325 };
1326
1327 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
1328 # define XCAST(fun)     (typeof(JoystickWvt.fun))
1329 #else
1330 # define XCAST(fun)     (void*)
1331 #endif
1332
1333 static const IDirectInputDevice8WVtbl JoystickWvt =
1334 {
1335         IDirectInputDevice2WImpl_QueryInterface,
1336         XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
1337         XCAST(Release)IDirectInputDevice2AImpl_Release,
1338         XCAST(GetCapabilities)JoystickAImpl_GetCapabilities,
1339         IDirectInputDevice2WImpl_EnumObjects,
1340         XCAST(GetProperty)JoystickAImpl_GetProperty,
1341         XCAST(SetProperty)JoystickAImpl_SetProperty,
1342         XCAST(Acquire)JoystickAImpl_Acquire,
1343         XCAST(Unacquire)JoystickAImpl_Unacquire,
1344         XCAST(GetDeviceState)JoystickAImpl_GetDeviceState,
1345         XCAST(GetDeviceData)IDirectInputDevice2AImpl_GetDeviceData,
1346         XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat,
1347         XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification,
1348         XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
1349         JoystickWImpl_GetObjectInfo,
1350         IDirectInputDevice2WImpl_GetDeviceInfo,
1351         XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
1352         XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
1353         XCAST(CreateEffect)JoystickAImpl_CreateEffect,
1354         JoystickWImpl_EnumEffects,
1355         JoystickWImpl_GetEffectInfo,
1356         XCAST(GetForceFeedbackState)JoystickAImpl_GetForceFeedbackState,
1357         XCAST(SendForceFeedbackCommand)JoystickAImpl_SendForceFeedbackCommand,
1358         XCAST(EnumCreatedEffectObjects)JoystickAImpl_EnumCreatedEffectObjects,
1359         XCAST(Escape)IDirectInputDevice2AImpl_Escape,
1360         XCAST(Poll)JoystickAImpl_Poll,
1361         XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
1362         IDirectInputDevice7WImpl_EnumEffectsInFile,
1363         IDirectInputDevice7WImpl_WriteEffectToFile,
1364         IDirectInputDevice8WImpl_BuildActionMap,
1365         IDirectInputDevice8WImpl_SetActionMap,
1366         IDirectInputDevice8WImpl_GetImageInfo
1367 };
1368 #undef XCAST
1369
1370 #else  /* HAVE_CORRECT_LINUXINPUT_H */
1371
1372 const struct dinput_device joystick_linuxinput_device = {
1373   "Wine Linux-input joystick driver",
1374   NULL,
1375   NULL,
1376   NULL,
1377   NULL
1378 };
1379
1380 #endif  /* HAVE_CORRECT_LINUXINPUT_H */