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