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