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