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