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