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