reg/tests: Add more tests for 'reg import'.
[wine.git] / dlls / dinput / joystick_linuxinput.c
blob911700b40bce54943ad27a180c7a87c9198f4ad3
1 /* DirectInput Joystick device
3 * Copyright 1998,2000 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2005 Daniel Remenak
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.
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.
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
23 #include "config.h"
24 #include "wine/port.h"
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <time.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #ifdef HAVE_SYS_TIME_H
35 # include <sys/time.h>
36 #endif
37 #include <fcntl.h>
38 #ifdef HAVE_SYS_IOCTL_H
39 # include <sys/ioctl.h>
40 #endif
41 #include <errno.h>
42 #ifdef HAVE_LINUX_INPUT_H
43 # include <linux/input.h>
44 # undef SW_MAX
45 # if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE)
46 # define HAS_PROPER_HEADER
47 # endif
48 #endif
49 #ifdef HAVE_SYS_POLL_H
50 # include <sys/poll.h>
51 #endif
53 #include "wine/debug.h"
54 #include "wine/unicode.h"
55 #include "wine/list.h"
56 #include "windef.h"
57 #include "winbase.h"
58 #include "winerror.h"
59 #include "winreg.h"
60 #include "dinput.h"
62 #include "dinput_private.h"
63 #include "device_private.h"
64 #include "joystick_private.h"
66 #ifdef HAS_PROPER_HEADER
68 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
70 #define EVDEVPREFIX "/dev/input/event"
71 #define EVDEVDRIVER " (event)"
73 /* Wine joystick driver object instances */
74 #define WINE_JOYSTICK_MAX_AXES 8
75 #define WINE_JOYSTICK_MAX_POVS 4
76 #define WINE_JOYSTICK_MAX_BUTTONS 128
78 struct wine_input_absinfo {
79 LONG value;
80 LONG minimum;
81 LONG maximum;
82 LONG fuzz;
83 LONG flat;
86 /* implemented in effect_linuxinput.c */
87 HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, struct list *parent_list_entry, LPDIRECTINPUTEFFECT* peff);
88 HRESULT linuxinput_get_info_A(int fd, REFGUID rguid, LPDIEFFECTINFOA info);
89 HRESULT linuxinput_get_info_W(int fd, REFGUID rguid, LPDIEFFECTINFOW info);
91 typedef struct JoystickImpl JoystickImpl;
92 static const IDirectInputDevice8AVtbl JoystickAvt;
93 static const IDirectInputDevice8WVtbl JoystickWvt;
95 struct JoyDev {
96 char *device;
97 char *name;
98 GUID guid;
99 GUID guid_product;
101 BOOL has_ff;
102 int num_effects;
104 /* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */
105 BYTE evbits[(EV_MAX+7)/8];
106 BYTE absbits[(ABS_MAX+7)/8];
107 BYTE keybits[(KEY_MAX+7)/8];
108 BYTE ffbits[(FF_MAX+7)/8];
110 /* data returned by the EVIOCGABS() ioctl */
111 struct wine_input_absinfo axes[ABS_MAX];
113 WORD vendor_id, product_id, bus_type;
116 struct JoystickImpl
118 struct JoystickGenericImpl generic;
119 struct JoyDev *joydev;
121 /* joystick private */
122 int joyfd;
124 int dev_axes_to_di[ABS_MAX];
125 POINTL povs[4];
127 /* LUT for KEY_ to offset in rgbButtons */
128 BYTE buttons[KEY_MAX];
130 /* Force feedback variables */
131 struct list ff_effects;
132 int ff_state;
133 int ff_autocenter;
134 int ff_gain;
137 static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
139 return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface),
140 JoystickGenericImpl, base), JoystickImpl, generic);
142 static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
144 return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface),
145 JoystickGenericImpl, base), JoystickImpl, generic);
148 static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl *This)
150 return &This->generic.base.IDirectInputDevice8W_iface;
153 static void fake_current_js_state(JoystickImpl *ji);
154 static void find_joydevs(void);
155 static void joy_polldev(LPDIRECTINPUTDEVICE8A iface);
157 /* This GUID is slightly different from the linux joystick one. Take note. */
158 static const GUID DInput_Wine_Joystick_Base_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */
159 0x9e573eda,
160 0x7734,
161 0x11d2,
162 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
166 * Construct the GUID in the same way of Windows doing this.
167 * Data1 is concatenation of productid and vendorid.
168 * Data2 and Data3 are NULL.
169 * Data4 seems to be a constant.
171 static const GUID DInput_Wine_Joystick_Constant_Part_GUID = {
172 0x000000000,
173 0x0000,
174 0x0000,
175 {0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44}
178 #define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7)))
180 #define MAX_JOYDEV 64
182 static int have_joydevs = -1;
183 static struct JoyDev *joydevs = NULL;
185 static void find_joydevs(void)
187 int i;
189 if (InterlockedCompareExchange(&have_joydevs, 0, -1) != -1)
190 /* Someone beat us to it */
191 return;
193 for (i = 0; i < MAX_JOYDEV; i++)
195 char buf[MAX_PATH];
196 struct JoyDev joydev = {0};
197 int fd;
198 BOOL no_ff_check = FALSE;
199 int j;
200 struct JoyDev *new_joydevs;
201 struct input_id device_id = {0};
203 snprintf(buf, sizeof(buf), EVDEVPREFIX"%d", i);
205 if ((fd = open(buf, O_RDWR)) == -1)
207 fd = open(buf, O_RDONLY);
208 no_ff_check = TRUE;
211 if (fd == -1)
213 WARN("Failed to open \"%s\": %d %s\n", buf, errno, strerror(errno));
214 continue;
217 if (ioctl(fd, EVIOCGBIT(0, sizeof(joydev.evbits)), joydev.evbits) == -1)
219 WARN("ioctl(EVIOCGBIT, 0) failed: %d %s\n", errno, strerror(errno));
220 close(fd);
221 continue;
223 if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(joydev.absbits)), joydev.absbits) == -1)
225 WARN("ioctl(EVIOCGBIT, EV_ABS) failed: %d %s\n", errno, strerror(errno));
226 close(fd);
227 continue;
229 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(joydev.keybits)), joydev.keybits) == -1)
231 WARN("ioctl(EVIOCGBIT, EV_KEY) failed: %d %s\n", errno, strerror(errno));
232 close(fd);
233 continue;
236 /* A true joystick has at least axis X and Y, and at least 1
237 * button. copied from linux/drivers/input/joydev.c */
238 if (!test_bit(joydev.absbits, ABS_X) || !test_bit(joydev.absbits, ABS_Y) ||
239 !(test_bit(joydev.keybits, BTN_TRIGGER) ||
240 test_bit(joydev.keybits, BTN_A) ||
241 test_bit(joydev.keybits, BTN_1)))
243 close(fd);
244 continue;
247 if (!(joydev.device = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1)))
249 close(fd);
250 continue;
252 strcpy(joydev.device, buf);
254 buf[MAX_PATH - 1] = 0;
255 if (ioctl(fd, EVIOCGNAME(MAX_PATH - 1), buf) != -1 &&
256 (joydev.name = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + strlen(EVDEVDRIVER) + 1)))
258 strcpy(joydev.name, buf);
259 /* Append driver name */
260 strcat(joydev.name, EVDEVDRIVER);
262 else
263 joydev.name = joydev.device;
265 if (device_disabled_registry(joydev.name)) {
266 close(fd);
267 HeapFree(GetProcessHeap(), 0, joydev.name);
268 if (joydev.name != joydev.device)
269 HeapFree(GetProcessHeap(), 0, joydev.device);
270 continue;
273 joydev.guid = DInput_Wine_Joystick_Base_GUID;
274 joydev.guid.Data3 += have_joydevs;
276 TRACE("Found a joystick on %s: %s (%s)\n",
277 joydev.device, joydev.name,
278 debugstr_guid(&joydev.guid)
281 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
282 if (!no_ff_check &&
283 test_bit(joydev.evbits, EV_FF) &&
284 ioctl(fd, EVIOCGBIT(EV_FF, sizeof(joydev.ffbits)), joydev.ffbits) != -1 &&
285 ioctl(fd, EVIOCGEFFECTS, &joydev.num_effects) != -1 &&
286 joydev.num_effects > 0)
288 TRACE(" ... with force feedback\n");
289 joydev.has_ff = TRUE;
291 #endif
293 for (j = 0; j < ABS_MAX;j ++)
295 if (!test_bit(joydev.absbits, j)) continue;
296 if (ioctl(fd, EVIOCGABS(j), &(joydev.axes[j])) != -1)
298 TRACE(" ... with axis %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n",
300 joydev.axes[j].value,
301 joydev.axes[j].minimum,
302 joydev.axes[j].maximum,
303 joydev.axes[j].fuzz,
304 joydev.axes[j].flat
309 if (ioctl(fd, EVIOCGID, &device_id) == -1)
311 WARN("ioctl(EVIOCGID) failed: %d %s\n", errno, strerror(errno));
312 joydev.guid_product = DInput_Wine_Joystick_Base_GUID;
314 else
316 joydev.vendor_id = device_id.vendor;
317 joydev.product_id = device_id.product;
318 joydev.bus_type = device_id.bustype;
320 /* Concatenate product_id with vendor_id to mimic Windows behaviour */
321 joydev.guid_product = DInput_Wine_Joystick_Constant_Part_GUID;
322 joydev.guid_product.Data1 = MAKELONG(joydev.vendor_id, joydev.product_id);
325 if (!have_joydevs)
326 new_joydevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct JoyDev));
327 else
328 new_joydevs = HeapReAlloc(GetProcessHeap(), 0, joydevs, (1 + have_joydevs) * sizeof(struct JoyDev));
330 if (!new_joydevs)
332 close(fd);
333 continue;
335 joydevs = new_joydevs;
336 joydevs[have_joydevs] = joydev;
337 have_joydevs++;
339 close(fd);
343 static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
345 DWORD dwSize = lpddi->dwSize;
347 TRACE("%d %p\n", dwSize, lpddi);
348 memset(lpddi, 0, dwSize);
350 lpddi->dwSize = dwSize;
351 lpddi->guidInstance = joydevs[id].guid;
352 lpddi->guidProduct = joydevs[id].guid_product;
353 lpddi->guidFFDriver = GUID_NULL;
355 if (version >= 0x0800)
356 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
357 else
358 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
360 /* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */
361 if (joydevs[id].bus_type == BUS_USB &&
362 joydevs[id].vendor_id && joydevs[id].product_id)
364 lpddi->dwDevType |= DIDEVTYPE_HID;
365 lpddi->wUsagePage = 0x01; /* Desktop */
366 if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType == DIDEVTYPE_JOYSTICK)
367 lpddi->wUsage = 0x04; /* Joystick */
368 else
369 lpddi->wUsage = 0x05; /* Game Pad */
372 MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
373 MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszProductName, MAX_PATH);
376 static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
378 DIDEVICEINSTANCEW lpddiW;
379 DWORD dwSize = lpddi->dwSize;
381 lpddiW.dwSize = sizeof(lpddiW);
382 fill_joystick_dideviceinstanceW(&lpddiW, version, id);
384 TRACE("%d %p\n", dwSize, lpddi);
385 memset(lpddi, 0, dwSize);
387 /* Convert W->A */
388 lpddi->dwSize = dwSize;
389 lpddi->guidInstance = lpddiW.guidInstance;
390 lpddi->guidProduct = lpddiW.guidProduct;
391 lpddi->dwDevType = lpddiW.dwDevType;
392 strcpy(lpddi->tszInstanceName, joydevs[id].name);
393 strcpy(lpddi->tszProductName, joydevs[id].name);
394 lpddi->guidFFDriver = lpddiW.guidFFDriver;
395 lpddi->wUsagePage = lpddiW.wUsagePage;
396 lpddi->wUsage = lpddiW.wUsage;
399 static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
401 find_joydevs();
403 if (id >= have_joydevs) {
404 return E_FAIL;
407 if (!((dwDevType == 0) ||
408 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
409 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
410 return S_FALSE;
412 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
413 if (dwFlags & DIEDFL_FORCEFEEDBACK)
414 return S_FALSE;
415 #endif
417 if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) {
418 fill_joystick_dideviceinstanceA(lpddi, version, id);
419 return S_OK;
421 return S_FALSE;
424 static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
426 find_joydevs();
428 if (id >= have_joydevs) {
429 return E_FAIL;
432 if (!((dwDevType == 0) ||
433 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
434 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
435 return S_FALSE;
437 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
438 if (dwFlags & DIEDFL_FORCEFEEDBACK)
439 return S_FALSE;
440 #endif
442 if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) {
443 fill_joystick_dideviceinstanceW(lpddi, version, id);
444 return S_OK;
446 return S_FALSE;
449 static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsigned short index)
451 JoystickImpl* newDevice;
452 LPDIDATAFORMAT df = NULL;
453 int i, idx = 0;
454 int default_axis_map[WINE_JOYSTICK_MAX_AXES + WINE_JOYSTICK_MAX_POVS*2];
455 DIDEVICEINSTANCEW ddi;
457 newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl));
458 if (!newDevice) return NULL;
460 newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt;
461 newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt;
462 newDevice->generic.base.ref = 1;
463 newDevice->generic.base.guid = *rguid;
464 newDevice->generic.base.dinput = dinput;
465 newDevice->generic.joy_polldev = joy_polldev;
466 newDevice->joyfd = -1;
467 newDevice->joydev = &joydevs[index];
468 newDevice->generic.name = newDevice->joydev->name;
469 list_init(&newDevice->ff_effects);
470 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
471 newDevice->ff_state = FF_STATUS_STOPPED;
472 #endif
473 /* There is no way in linux to query force feedback autocenter status.
474 Instead, track it with ff_autocenter, and assume it's initially
475 enabled. */
476 newDevice->ff_autocenter = 1;
477 newDevice->ff_gain = 0xFFFF;
478 InitializeCriticalSection(&newDevice->generic.base.crit);
479 newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit");
481 /* Count number of available axes - supported Axis & POVs */
482 for (i = 0; i < ABS_MAX; i++)
484 if (i < WINE_JOYSTICK_MAX_AXES &&
485 test_bit(newDevice->joydev->absbits, i))
487 newDevice->generic.device_axis_count++;
488 newDevice->dev_axes_to_di[i] = idx;
489 newDevice->generic.props[idx].lDevMin = newDevice->joydev->axes[i].minimum;
490 newDevice->generic.props[idx].lDevMax = newDevice->joydev->axes[i].maximum;
491 default_axis_map[idx] = i;
492 idx++;
494 else
495 newDevice->dev_axes_to_di[i] = -1;
498 for (i = 0; i < WINE_JOYSTICK_MAX_POVS; i++)
500 if (test_bit(newDevice->joydev->absbits, ABS_HAT0X + i * 2) &&
501 test_bit(newDevice->joydev->absbits, ABS_HAT0Y + i * 2))
503 newDevice->generic.device_axis_count += 2;
504 newDevice->generic.props[idx ].lDevMin = newDevice->joydev->axes[ABS_HAT0X + i * 2].minimum;
505 newDevice->generic.props[idx ].lDevMax = newDevice->joydev->axes[ABS_HAT0X + i * 2].maximum;
506 newDevice->dev_axes_to_di[ABS_HAT0X + i * 2] = idx;
507 newDevice->generic.props[idx+1].lDevMin = newDevice->joydev->axes[ABS_HAT0Y + i * 2].minimum;
508 newDevice->generic.props[idx+1].lDevMax = newDevice->joydev->axes[ABS_HAT0Y + i * 2].maximum;
509 newDevice->dev_axes_to_di[ABS_HAT0Y + i * 2] = idx + 1;
511 default_axis_map[idx] = default_axis_map[idx + 1] = WINE_JOYSTICK_MAX_AXES + i;
512 idx += 2;
514 else
515 newDevice->dev_axes_to_di[ABS_HAT0X + i * 2] = newDevice->dev_axes_to_di[ABS_HAT0Y + i * 2] = -1;
518 /* do any user specified configuration */
519 if (setup_dinput_options(&newDevice->generic, default_axis_map) != DI_OK) goto failed;
521 /* Create copy of default data format */
522 if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto failed;
523 memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
524 if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed;
527 /* Construct internal data format */
529 /* Supported Axis & POVs */
530 for (i = 0, idx = 0; i < newDevice->generic.device_axis_count; i++)
532 int wine_obj = newDevice->generic.axis_map[i];
534 if (wine_obj < 0) continue;
536 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
537 if (wine_obj < 8)
538 df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
539 else
541 df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(wine_obj - 8) | DIDFT_POV;
542 i++; /* POV takes 2 axes */
545 newDevice->generic.props[idx].lMin = 0;
546 newDevice->generic.props[idx].lMax = 0xffff;
547 newDevice->generic.props[idx].lSaturation = 0;
548 newDevice->generic.props[idx].lDeadZone = newDevice->generic.deadzone;
550 /* Linux supports force-feedback on X & Y axes only */
551 if (newDevice->joydev->has_ff && (i == 0 || i == 1))
552 df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR;
554 idx++;
557 /* Buttons can be anywhere, so check all */
558 for (i = 0; i < KEY_MAX && newDevice->generic.devcaps.dwButtons < WINE_JOYSTICK_MAX_BUTTONS; i++)
560 if (!test_bit(newDevice->joydev->keybits, i)) continue;
562 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[newDevice->generic.devcaps.dwButtons + 12], df->dwObjSize);
563 newDevice->buttons[i] = 0x80 | newDevice->generic.devcaps.dwButtons;
564 df->rgodf[idx ].pguid = &GUID_Button;
565 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(newDevice->generic.devcaps.dwButtons++) | DIDFT_PSHBUTTON;
567 df->dwNumObjs = idx;
568 newDevice->generic.base.data_format.wine_df = df;
570 fake_current_js_state(newDevice);
572 /* Fill the caps */
573 newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
574 newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
576 ddi.dwSize = sizeof(ddi);
577 fill_joystick_dideviceinstanceW(&ddi, newDevice->generic.base.dinput->dwVersion, index);
578 newDevice->generic.devcaps.dwDevType = ddi.dwDevType;
580 if (newDevice->joydev->has_ff)
581 newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK;
583 IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface);
585 EnterCriticalSection(&dinput->crit);
586 list_add_tail(&dinput->devices_list, &newDevice->generic.base.entry);
587 LeaveCriticalSection(&dinput->crit);
589 return newDevice;
591 failed:
592 if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
593 HeapFree(GetProcessHeap(), 0, df);
594 HeapFree(GetProcessHeap(), 0, newDevice->generic.axis_map);
595 HeapFree(GetProcessHeap(), 0, newDevice);
596 return NULL;
599 /******************************************************************************
600 * get_joystick_index : Get the joystick index from a given GUID
602 static unsigned short get_joystick_index(REFGUID guid)
604 GUID wine_joystick = DInput_Wine_Joystick_Base_GUID;
605 GUID dev_guid = *guid;
607 wine_joystick.Data3 = 0;
608 dev_guid.Data3 = 0;
610 /* for the standard joystick GUID use index 0 */
611 if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
613 /* for the wine joystick GUIDs use the index stored in Data3 */
614 if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3 - DInput_Wine_Joystick_Base_GUID.Data3;
616 return MAX_JOYDEV;
619 static HRESULT joydev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode)
621 unsigned short index;
623 TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode);
624 find_joydevs();
625 *pdev = NULL;
627 if ((index = get_joystick_index(rguid)) < MAX_JOYDEV &&
628 have_joydevs && index < have_joydevs)
630 JoystickImpl *This;
632 if (riid == NULL)
633 ;/* nothing */
634 else if (IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
635 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
636 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
637 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
639 unicode = 0;
641 else if (IsEqualGUID(&IID_IDirectInputDeviceW, riid) ||
642 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
643 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
644 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
646 unicode = 1;
648 else
650 WARN("no interface\n");
651 return DIERR_NOINTERFACE;
654 This = alloc_device(rguid, dinput, index);
655 TRACE("Created a Joystick device (%p)\n", This);
657 if (!This) return DIERR_OUTOFMEMORY;
659 if (unicode)
660 *pdev = &This->generic.base.IDirectInputDevice8W_iface;
661 else
662 *pdev = &This->generic.base.IDirectInputDevice8A_iface;
664 return DI_OK;
667 return DIERR_DEVICENOTREG;
671 const struct dinput_device joystick_linuxinput_device = {
672 "Wine Linux-input joystick driver",
673 joydev_enum_deviceA,
674 joydev_enum_deviceW,
675 joydev_create_device
678 /******************************************************************************
679 * Acquire : gets exclusive control of the joystick
681 static HRESULT WINAPI JoystickWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
683 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
684 HRESULT res;
686 TRACE("(this=%p)\n",This);
688 if ((res = IDirectInputDevice2WImpl_Acquire(iface)) != DI_OK)
690 WARN("Failed to acquire: %x\n", res);
691 return res;
694 if ((This->joyfd = open(This->joydev->device, O_RDWR)) == -1)
696 if ((This->joyfd = open(This->joydev->device, O_RDONLY)) == -1)
698 /* Couldn't open the device at all */
699 ERR("Failed to open device %s: %d %s\n", This->joydev->device, errno, strerror(errno));
700 IDirectInputDevice2WImpl_Unacquire(iface);
701 return DIERR_NOTFOUND;
703 else
705 /* Couldn't open in r/w but opened in read-only. */
706 WARN("Could not open %s in read-write mode. Force feedback will be disabled.\n", This->joydev->device);
709 else
711 struct input_event event;
713 event.type = EV_FF;
714 event.code = FF_GAIN;
715 event.value = This->ff_gain;
716 if (write(This->joyfd, &event, sizeof(event)) == -1)
717 ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno, strerror(errno));
718 if (!This->ff_autocenter)
720 /* Disable autocenter. */
721 event.code = FF_AUTOCENTER;
722 event.value = 0;
723 if (write(This->joyfd, &event, sizeof(event)) == -1)
724 ERR("Failed disabling autocenter: %d %s\n", errno, strerror(errno));
728 return DI_OK;
731 static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
733 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
734 return JoystickWImpl_Acquire(IDirectInputDevice8W_from_impl(This));
737 /******************************************************************************
738 * Unacquire : frees the joystick
740 static HRESULT WINAPI JoystickWImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface)
742 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
743 HRESULT res;
745 TRACE("(this=%p)\n",This);
746 res = IDirectInputDevice2WImpl_Unacquire(iface);
747 if (res==DI_OK && This->joyfd!=-1) {
748 effect_list_item *itr;
749 struct input_event event;
751 /* For each known effect:
752 * - stop it
753 * - unload it
754 * But, unlike DISFFC_RESET, do not release the effect.
756 LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry) {
757 IDirectInputEffect_Stop(itr->ref);
758 IDirectInputEffect_Unload(itr->ref);
761 /* Enable autocenter. */
762 event.type = EV_FF;
763 event.code = FF_AUTOCENTER;
764 /* TODO: Read autocenter strength before disabling it, and use it here
765 * instead of 0xFFFF (maximum strength).
767 event.value = 0xFFFF;
768 if (write(This->joyfd, &event, sizeof(event)) == -1)
769 ERR("Failed to set autocenter to %04x: %d %s\n", event.value, errno, strerror(errno));
771 close(This->joyfd);
772 This->joyfd = -1;
774 return res;
777 static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
779 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
780 return JoystickWImpl_Unacquire(IDirectInputDevice8W_from_impl(This));
784 * set the current state of the js device as it would be with the middle
785 * values on the axes
787 #define CENTER_AXIS(a) \
788 (ji->dev_axes_to_di[a] == -1 ? 0 : joystick_map_axis( &ji->generic.props[ji->dev_axes_to_di[a]], \
789 ji->joydev->axes[a].value ))
790 static void fake_current_js_state(JoystickImpl *ji)
792 int i;
794 /* center the axes */
795 ji->generic.js.lX = CENTER_AXIS(ABS_X);
796 ji->generic.js.lY = CENTER_AXIS(ABS_Y);
797 ji->generic.js.lZ = CENTER_AXIS(ABS_Z);
798 ji->generic.js.lRx = CENTER_AXIS(ABS_RX);
799 ji->generic.js.lRy = CENTER_AXIS(ABS_RY);
800 ji->generic.js.lRz = CENTER_AXIS(ABS_RZ);
801 ji->generic.js.rglSlider[0] = CENTER_AXIS(ABS_THROTTLE);
802 ji->generic.js.rglSlider[1] = CENTER_AXIS(ABS_RUDDER);
804 /* POV center is -1 */
805 for (i = 0; i < 4; i++)
806 ji->generic.js.rgdwPOV[i] = -1;
808 #undef CENTER_AXIS
810 /* convert wine format offset to user format object index */
811 static void joy_polldev(LPDIRECTINPUTDEVICE8A iface)
813 struct pollfd plfd;
814 struct input_event ie;
815 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
817 if (This->joyfd==-1)
818 return;
820 while (1)
822 LONG value = 0;
823 int inst_id = -1;
825 plfd.fd = This->joyfd;
826 plfd.events = POLLIN;
828 if (poll(&plfd,1,0) != 1)
829 return;
831 /* we have one event, so we can read */
832 if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie)))
833 return;
835 TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value);
836 switch (ie.type) {
837 case EV_KEY: /* button */
839 int btn = This->buttons[ie.code];
841 TRACE("(%p) %d -> %d\n", This, ie.code, btn);
842 if (btn & 0x80)
844 btn &= 0x7F;
845 inst_id = DIDFT_MAKEINSTANCE(btn) | DIDFT_PSHBUTTON;
846 This->generic.js.rgbButtons[btn] = value = ie.value ? 0x80 : 0x00;
848 break;
850 case EV_ABS:
852 int axis = This->dev_axes_to_di[ie.code];
854 /* User axis remapping */
855 if (axis < 0) break;
856 axis = This->generic.axis_map[axis];
857 if (axis < 0) break;
859 inst_id = axis < 8 ? DIDFT_MAKEINSTANCE(axis) | DIDFT_ABSAXIS :
860 DIDFT_MAKEINSTANCE(axis - 8) | DIDFT_POV;
861 value = joystick_map_axis(&This->generic.props[id_to_object(This->generic.base.data_format.wine_df, inst_id)], ie.value);
863 switch (axis) {
864 case 0: This->generic.js.lX = value; break;
865 case 1: This->generic.js.lY = value; break;
866 case 2: This->generic.js.lZ = value; break;
867 case 3: This->generic.js.lRx = value; break;
868 case 4: This->generic.js.lRy = value; break;
869 case 5: This->generic.js.lRz = value; break;
870 case 6: This->generic.js.rglSlider[0] = value; break;
871 case 7: This->generic.js.rglSlider[1] = value; break;
872 case 8: case 9: case 10: case 11:
874 int idx = axis - 8;
876 if (ie.code % 2)
877 This->povs[idx].y = ie.value;
878 else
879 This->povs[idx].x = ie.value;
881 This->generic.js.rgdwPOV[idx] = value = joystick_map_pov(&This->povs[idx]);
882 break;
884 default:
885 FIXME("unhandled joystick axis event (code %d, value %d)\n",ie.code,ie.value);
887 break;
889 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
890 case EV_FF_STATUS:
891 This->ff_state = ie.value;
892 break;
893 #endif
894 #ifdef EV_SYN
895 case EV_SYN:
896 /* there is nothing to do */
897 break;
898 #endif
899 #ifdef EV_MSC
900 case EV_MSC:
901 /* Ignore */
902 break;
903 #endif
904 default:
905 FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code);
906 break;
908 if (inst_id >= 0)
909 queue_event(iface, inst_id,
910 value, GetCurrentTime(), This->generic.base.dinput->evsequence++);
914 /******************************************************************************
915 * SetProperty : change input device properties
917 static HRESULT WINAPI JoystickWImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPCDIPROPHEADER ph)
919 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
921 if (!ph) {
922 WARN("invalid argument\n");
923 return DIERR_INVALIDPARAM;
926 TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
927 TRACE("ph.dwSize = %d, ph.dwHeaderSize =%d, ph.dwObj = %d, ph.dwHow= %d\n",
928 ph->dwSize, ph->dwHeaderSize, ph->dwObj, ph->dwHow);
930 if (IS_DIPROP(rguid)) {
931 switch (LOWORD(rguid)) {
932 case (DWORD_PTR)DIPROP_CALIBRATIONMODE: {
933 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
934 FIXME("DIPROP_CALIBRATIONMODE(%d)\n", pd->dwData);
935 break;
937 case (DWORD_PTR)DIPROP_AUTOCENTER: {
938 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
940 TRACE("autocenter(%d)\n", pd->dwData);
941 This->ff_autocenter = pd->dwData == DIPROPAUTOCENTER_ON;
943 break;
945 case (DWORD_PTR)DIPROP_FFGAIN: {
946 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
948 TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData);
949 This->ff_gain = MulDiv(pd->dwData, 0xFFFF, 10000);
950 if (This->generic.base.acquired) {
951 /* Update immediately. */
952 struct input_event event;
954 event.type = EV_FF;
955 event.code = FF_GAIN;
956 event.value = This->ff_gain;
957 if (write(This->joyfd, &event, sizeof(event)) == -1)
958 ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno, strerror(errno));
960 break;
962 default:
963 return JoystickWGenericImpl_SetProperty(iface, rguid, ph);
966 return DI_OK;
969 static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIPROPHEADER ph)
971 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
972 return JoystickWImpl_SetProperty(IDirectInputDevice8W_from_impl(This), rguid, ph);
975 /******************************************************************************
976 * GetProperty : get input device properties
978 static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph)
980 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
982 TRACE("(this=%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph);
983 _dump_DIPROPHEADER(pdiph);
985 if (!IS_DIPROP(rguid)) return DI_OK;
987 switch (LOWORD(rguid)) {
988 case (DWORD_PTR) DIPROP_AUTOCENTER:
990 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
992 pd->dwData = This->ff_autocenter ? DIPROPAUTOCENTER_ON : DIPROPAUTOCENTER_OFF;
993 TRACE("autocenter(%d)\n", pd->dwData);
994 break;
996 case (DWORD_PTR) DIPROP_FFGAIN:
998 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
1000 pd->dwData = MulDiv(This->ff_gain, 10000, 0xFFFF);
1001 TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData);
1002 break;
1005 case (DWORD_PTR) DIPROP_VIDPID:
1007 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
1009 if (!This->joydev->product_id || !This->joydev->vendor_id)
1010 return DIERR_UNSUPPORTED;
1011 pd->dwData = MAKELONG(This->joydev->vendor_id, This->joydev->product_id);
1012 TRACE("DIPROP_VIDPID(%08x)\n", pd->dwData);
1013 break;
1016 case (DWORD_PTR) DIPROP_JOYSTICKID:
1018 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
1020 pd->dwData = get_joystick_index(&This->generic.base.guid);
1021 TRACE("DIPROP_JOYSTICKID(%d)\n", pd->dwData);
1022 break;
1025 default:
1026 return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph);
1029 return DI_OK;
1032 static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph)
1034 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1035 return JoystickWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
1038 /******************************************************************************
1039 * CreateEffect - Create a new FF effect with the specified params
1041 static HRESULT WINAPI JoystickWImpl_CreateEffect(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid,
1042 LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdef,
1043 LPUNKNOWN pUnkOuter)
1045 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1046 effect_list_item* new_effect = NULL;
1047 HRESULT retval = DI_OK;
1048 #endif
1050 JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1051 TRACE("(this=%p,%p,%p,%p,%p)\n", This, rguid, lpeff, ppdef, pUnkOuter);
1053 *ppdef = NULL;
1054 if (!This->joydev->has_ff)
1056 TRACE("No force feedback support\n");
1057 return DIERR_UNSUPPORTED;
1060 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
1061 TRACE("not available (compiled w/o force feedback support)\n");
1062 return DIERR_UNSUPPORTED;
1063 #else
1065 if (!(new_effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_effect))))
1066 return DIERR_OUTOFMEMORY;
1068 retval = linuxinput_create_effect(&This->joyfd, rguid, &new_effect->entry, &new_effect->ref);
1069 if (retval != DI_OK)
1071 HeapFree(GetProcessHeap(), 0, new_effect);
1072 return retval;
1075 if (lpeff != NULL)
1077 retval = IDirectInputEffect_SetParameters(new_effect->ref, lpeff, 0);
1079 if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED)
1081 HeapFree(GetProcessHeap(), 0, new_effect);
1082 return retval;
1086 list_add_tail(&This->ff_effects, &new_effect->entry);
1087 *ppdef = new_effect->ref;
1089 if (pUnkOuter != NULL)
1090 FIXME("Interface aggregation not implemented.\n");
1092 return DI_OK;
1094 #endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */
1097 static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid,
1098 LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdef,
1099 LPUNKNOWN pUnkOuter)
1101 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1102 return JoystickWImpl_CreateEffect(IDirectInputDevice8W_from_impl(This), rguid, lpeff, ppdef, pUnkOuter);
1105 /*******************************************************************************
1106 * EnumEffects - Enumerate available FF effects
1108 static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface,
1109 LPDIENUMEFFECTSCALLBACKA lpCallback,
1110 LPVOID pvRef,
1111 DWORD dwEffType)
1113 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1114 DIEFFECTINFOA dei; /* feif */
1115 DWORD type = DIEFT_GETTYPE(dwEffType);
1116 JoystickImpl* This = impl_from_IDirectInputDevice8A(iface);
1118 TRACE("(this=%p,%p,%d) type=%d\n", This, pvRef, dwEffType, type);
1120 dei.dwSize = sizeof(DIEFFECTINFOA);
1122 if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1123 && test_bit(This->joydev->ffbits, FF_CONSTANT)) {
1124 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1125 (*lpCallback)(&dei, pvRef);
1128 if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1129 && test_bit(This->joydev->ffbits, FF_PERIODIC)) {
1130 if (test_bit(This->joydev->ffbits, FF_SQUARE)) {
1131 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1132 (*lpCallback)(&dei, pvRef);
1134 if (test_bit(This->joydev->ffbits, FF_SINE)) {
1135 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1136 (*lpCallback)(&dei, pvRef);
1138 if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) {
1139 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1140 (*lpCallback)(&dei, pvRef);
1142 if (test_bit(This->joydev->ffbits, FF_SAW_UP)) {
1143 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1144 (*lpCallback)(&dei, pvRef);
1146 if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) {
1147 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1148 (*lpCallback)(&dei, pvRef);
1152 if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1153 && test_bit(This->joydev->ffbits, FF_RAMP)) {
1154 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1155 (*lpCallback)(&dei, pvRef);
1158 if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1159 if (test_bit(This->joydev->ffbits, FF_SPRING)) {
1160 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1161 (*lpCallback)(&dei, pvRef);
1163 if (test_bit(This->joydev->ffbits, FF_DAMPER)) {
1164 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1165 (*lpCallback)(&dei, pvRef);
1167 if (test_bit(This->joydev->ffbits, FF_INERTIA)) {
1168 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1169 (*lpCallback)(&dei, pvRef);
1171 if (test_bit(This->joydev->ffbits, FF_FRICTION)) {
1172 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1173 (*lpCallback)(&dei, pvRef);
1177 #endif
1179 return DI_OK;
1182 static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface,
1183 LPDIENUMEFFECTSCALLBACKW lpCallback,
1184 LPVOID pvRef,
1185 DWORD dwEffType)
1187 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1188 /* seems silly to duplicate all this code but all the structures and functions
1189 * are actually different (A/W) */
1190 DIEFFECTINFOW dei; /* feif */
1191 DWORD type = DIEFT_GETTYPE(dwEffType);
1192 JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1193 int xfd = This->joyfd;
1195 TRACE("(this=%p,%p,%d) type=%d fd=%d\n", This, pvRef, dwEffType, type, xfd);
1197 dei.dwSize = sizeof(DIEFFECTINFOW);
1199 if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1200 && test_bit(This->joydev->ffbits, FF_CONSTANT)) {
1201 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1202 (*lpCallback)(&dei, pvRef);
1205 if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1206 && test_bit(This->joydev->ffbits, FF_PERIODIC)) {
1207 if (test_bit(This->joydev->ffbits, FF_SQUARE)) {
1208 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1209 (*lpCallback)(&dei, pvRef);
1211 if (test_bit(This->joydev->ffbits, FF_SINE)) {
1212 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1213 (*lpCallback)(&dei, pvRef);
1215 if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) {
1216 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1217 (*lpCallback)(&dei, pvRef);
1219 if (test_bit(This->joydev->ffbits, FF_SAW_UP)) {
1220 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1221 (*lpCallback)(&dei, pvRef);
1223 if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) {
1224 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1225 (*lpCallback)(&dei, pvRef);
1229 if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1230 && test_bit(This->joydev->ffbits, FF_RAMP)) {
1231 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1232 (*lpCallback)(&dei, pvRef);
1235 if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1236 if (test_bit(This->joydev->ffbits, FF_SPRING)) {
1237 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1238 (*lpCallback)(&dei, pvRef);
1240 if (test_bit(This->joydev->ffbits, FF_DAMPER)) {
1241 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1242 (*lpCallback)(&dei, pvRef);
1244 if (test_bit(This->joydev->ffbits, FF_INERTIA)) {
1245 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1246 (*lpCallback)(&dei, pvRef);
1248 if (test_bit(This->joydev->ffbits, FF_FRICTION)) {
1249 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1250 (*lpCallback)(&dei, pvRef);
1254 /* return to unacquired state if that's where it was */
1255 if (xfd == -1)
1256 IDirectInputDevice8_Unacquire(iface);
1257 #endif
1259 return DI_OK;
1262 /*******************************************************************************
1263 * GetEffectInfo - Get information about a particular effect
1265 static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface,
1266 LPDIEFFECTINFOA pdei,
1267 REFGUID guid)
1269 JoystickImpl* This = impl_from_IDirectInputDevice8A(iface);
1271 TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1273 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1274 return linuxinput_get_info_A(This->joyfd, guid, pdei);
1275 #else
1276 return DI_OK;
1277 #endif
1280 static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface,
1281 LPDIEFFECTINFOW pdei,
1282 REFGUID guid)
1284 JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1286 TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1288 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1289 return linuxinput_get_info_W(This->joyfd, guid, pdei);
1290 #else
1291 return DI_OK;
1292 #endif
1295 /*******************************************************************************
1296 * GetForceFeedbackState - Get information about the device's FF state
1298 static HRESULT WINAPI JoystickWImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8W iface, LPDWORD pdwOut)
1300 JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1302 TRACE("(this=%p,%p)\n", This, pdwOut);
1304 (*pdwOut) = 0;
1306 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1307 /* DIGFFS_STOPPED is the only mandatory flag to report */
1308 if (This->ff_state == FF_STATUS_STOPPED)
1309 (*pdwOut) |= DIGFFS_STOPPED;
1310 #endif
1312 return DI_OK;
1315 static HRESULT WINAPI JoystickAImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8A iface, LPDWORD pdwOut)
1317 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1318 return JoystickWImpl_GetForceFeedbackState(IDirectInputDevice8W_from_impl(This), pdwOut);
1321 /*******************************************************************************
1322 * SendForceFeedbackCommand - Send a command to the device's FF system
1324 static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W iface, DWORD dwFlags)
1326 JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1327 TRACE("(this=%p,%d)\n", This, dwFlags);
1329 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1330 switch (dwFlags)
1332 case DISFFC_STOPALL:
1334 /* Stop all effects */
1335 effect_list_item *itr;
1337 LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry)
1338 IDirectInputEffect_Stop(itr->ref);
1339 break;
1342 case DISFFC_RESET:
1344 effect_list_item *itr, *ptr;
1346 /* Stop, unload, release and free all effects */
1347 /* This returns the device to its "bare" state */
1348 LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->ff_effects, effect_list_item, entry)
1349 IDirectInputEffect_Release(itr->ref);
1350 break;
1352 case DISFFC_PAUSE:
1353 case DISFFC_CONTINUE:
1354 FIXME("No support for Pause or Continue in linux\n");
1355 break;
1357 case DISFFC_SETACTUATORSOFF:
1358 case DISFFC_SETACTUATORSON:
1359 FIXME("No direct actuator control in linux\n");
1360 break;
1362 default:
1363 FIXME("Unknown Force Feedback Command!\n");
1364 return DIERR_INVALIDPARAM;
1366 return DI_OK;
1367 #else
1368 return DIERR_UNSUPPORTED;
1369 #endif
1372 static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8A iface, DWORD dwFlags)
1374 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1375 return JoystickWImpl_SendForceFeedbackCommand(IDirectInputDevice8W_from_impl(This), dwFlags);
1378 /*******************************************************************************
1379 * EnumCreatedEffectObjects - Enumerate all the effects that have been
1380 * created for this device.
1382 static HRESULT WINAPI JoystickWImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8W iface,
1383 LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
1384 LPVOID pvRef, DWORD dwFlags)
1386 /* this function is safe to call on non-ff-enabled builds */
1387 JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1388 effect_list_item *itr, *ptr;
1390 TRACE("(this=%p,%p,%p,%d)\n", This, lpCallback, pvRef, dwFlags);
1392 if (!lpCallback)
1393 return DIERR_INVALIDPARAM;
1395 if (dwFlags != 0)
1396 FIXME("Flags specified, but no flags exist yet (DX9)!\n");
1398 LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->ff_effects, effect_list_item, entry)
1399 (*lpCallback)(itr->ref, pvRef);
1401 return DI_OK;
1404 static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8A iface,
1405 LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
1406 LPVOID pvRef, DWORD dwFlags)
1408 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1409 return JoystickWImpl_EnumCreatedEffectObjects(IDirectInputDevice8W_from_impl(This), lpCallback, pvRef, dwFlags);
1412 /******************************************************************************
1413 * GetDeviceInfo : get information about a device's identity
1415 static HRESULT WINAPI JoystickAImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8A iface,
1416 LPDIDEVICEINSTANCEA pdidi)
1418 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1420 TRACE("(%p) %p\n", This, pdidi);
1422 if (pdidi == NULL) return E_POINTER;
1423 if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) &&
1424 (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)))
1425 return DIERR_INVALIDPARAM;
1427 fill_joystick_dideviceinstanceA(pdidi, This->generic.base.dinput->dwVersion,
1428 get_joystick_index(&This->generic.base.guid));
1429 return DI_OK;
1432 static HRESULT WINAPI JoystickWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface,
1433 LPDIDEVICEINSTANCEW pdidi)
1435 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
1437 TRACE("(%p) %p\n", This, pdidi);
1439 if (pdidi == NULL) return E_POINTER;
1440 if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) &&
1441 (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)))
1442 return DIERR_INVALIDPARAM;
1444 fill_joystick_dideviceinstanceW(pdidi, This->generic.base.dinput->dwVersion,
1445 get_joystick_index(&This->generic.base.guid));
1446 return DI_OK;
1449 static const IDirectInputDevice8AVtbl JoystickAvt =
1451 IDirectInputDevice2AImpl_QueryInterface,
1452 IDirectInputDevice2AImpl_AddRef,
1453 IDirectInputDevice2AImpl_Release,
1454 JoystickAGenericImpl_GetCapabilities,
1455 IDirectInputDevice2AImpl_EnumObjects,
1456 JoystickAImpl_GetProperty,
1457 JoystickAImpl_SetProperty,
1458 JoystickAImpl_Acquire,
1459 JoystickAImpl_Unacquire,
1460 JoystickAGenericImpl_GetDeviceState,
1461 IDirectInputDevice2AImpl_GetDeviceData,
1462 IDirectInputDevice2AImpl_SetDataFormat,
1463 IDirectInputDevice2AImpl_SetEventNotification,
1464 IDirectInputDevice2AImpl_SetCooperativeLevel,
1465 JoystickAGenericImpl_GetObjectInfo,
1466 JoystickAImpl_GetDeviceInfo,
1467 IDirectInputDevice2AImpl_RunControlPanel,
1468 IDirectInputDevice2AImpl_Initialize,
1469 JoystickAImpl_CreateEffect,
1470 JoystickAImpl_EnumEffects,
1471 JoystickAImpl_GetEffectInfo,
1472 JoystickAImpl_GetForceFeedbackState,
1473 JoystickAImpl_SendForceFeedbackCommand,
1474 JoystickAImpl_EnumCreatedEffectObjects,
1475 IDirectInputDevice2AImpl_Escape,
1476 JoystickAGenericImpl_Poll,
1477 IDirectInputDevice2AImpl_SendDeviceData,
1478 IDirectInputDevice7AImpl_EnumEffectsInFile,
1479 IDirectInputDevice7AImpl_WriteEffectToFile,
1480 JoystickAGenericImpl_BuildActionMap,
1481 JoystickAGenericImpl_SetActionMap,
1482 IDirectInputDevice8AImpl_GetImageInfo
1485 static const IDirectInputDevice8WVtbl JoystickWvt =
1487 IDirectInputDevice2WImpl_QueryInterface,
1488 IDirectInputDevice2WImpl_AddRef,
1489 IDirectInputDevice2WImpl_Release,
1490 JoystickWGenericImpl_GetCapabilities,
1491 IDirectInputDevice2WImpl_EnumObjects,
1492 JoystickWImpl_GetProperty,
1493 JoystickWImpl_SetProperty,
1494 JoystickWImpl_Acquire,
1495 JoystickWImpl_Unacquire,
1496 JoystickWGenericImpl_GetDeviceState,
1497 IDirectInputDevice2WImpl_GetDeviceData,
1498 IDirectInputDevice2WImpl_SetDataFormat,
1499 IDirectInputDevice2WImpl_SetEventNotification,
1500 IDirectInputDevice2WImpl_SetCooperativeLevel,
1501 JoystickWGenericImpl_GetObjectInfo,
1502 JoystickWImpl_GetDeviceInfo,
1503 IDirectInputDevice2WImpl_RunControlPanel,
1504 IDirectInputDevice2WImpl_Initialize,
1505 JoystickWImpl_CreateEffect,
1506 JoystickWImpl_EnumEffects,
1507 JoystickWImpl_GetEffectInfo,
1508 JoystickWImpl_GetForceFeedbackState,
1509 JoystickWImpl_SendForceFeedbackCommand,
1510 JoystickWImpl_EnumCreatedEffectObjects,
1511 IDirectInputDevice2WImpl_Escape,
1512 JoystickWGenericImpl_Poll,
1513 IDirectInputDevice2WImpl_SendDeviceData,
1514 IDirectInputDevice7WImpl_EnumEffectsInFile,
1515 IDirectInputDevice7WImpl_WriteEffectToFile,
1516 JoystickWGenericImpl_BuildActionMap,
1517 JoystickWGenericImpl_SetActionMap,
1518 IDirectInputDevice8WImpl_GetImageInfo
1521 #else /* HAS_PROPER_HEADER */
1523 const struct dinput_device joystick_linuxinput_device = {
1524 "Wine Linux-input joystick driver",
1525 NULL,
1526 NULL,
1527 NULL
1530 #endif /* HAS_PROPER_HEADER */