Sync with trunk.
[reactos.git] / dll / directx / wine / dinput / joystick_linux.c
1 /* DirectInput Joystick device
2 *
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 /*
23 * To Do:
24 * dead zone
25 * force feedback
26 */
27
28 #include "dinput_private.h"
29
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33 #ifdef HAVE_SYS_TIME_H
34 # include <sys/time.h>
35 #endif
36 #ifdef HAVE_SYS_IOCTL_H
37 # include <sys/ioctl.h>
38 #endif
39 #ifdef HAVE_LINUX_IOCTL_H
40 # include <linux/ioctl.h>
41 #endif
42 #ifdef HAVE_LINUX_JOYSTICK_H
43 # include <linux/joystick.h>
44 # undef SW_MAX
45 #endif
46 #ifdef HAVE_SYS_POLL_H
47 # include <sys/poll.h>
48 #endif
49
50 #ifdef HAVE_LINUX_22_JOYSTICK_API
51
52 #define JOYDEV_NEW "/dev/input/js"
53 #define JOYDEV_OLD "/dev/js"
54 #define JOYDEVDRIVER " (js)"
55
56 struct JoyDev
57 {
58 char device[MAX_PATH];
59 char name[MAX_PATH];
60
61 BYTE axis_count;
62 BYTE button_count;
63 int *dev_axes_map;
64 };
65
66 typedef struct JoystickImpl JoystickImpl;
67 static const IDirectInputDevice8AVtbl JoystickAvt;
68 static const IDirectInputDevice8WVtbl JoystickWvt;
69 struct JoystickImpl
70 {
71 struct JoystickGenericImpl generic;
72
73 struct JoyDev *joydev;
74
75 /* joystick private */
76 int joyfd;
77 POINTL povs[4];
78 };
79
80 static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
81 {
82 return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface),
83 JoystickGenericImpl, base), JoystickImpl, generic);
84 }
85 static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
86 {
87 return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface),
88 JoystickGenericImpl, base), JoystickImpl, generic);
89 }
90 static inline IDirectInputDevice8A *IDirectInputDevice8A_from_impl(JoystickImpl *This)
91 {
92 return &This->generic.base.IDirectInputDevice8A_iface;
93 }
94 static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl *This)
95 {
96 return &This->generic.base.IDirectInputDevice8W_iface;
97 }
98
99 static const GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */
100 0x9e573ed9,
101 0x7734,
102 0x11d2,
103 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
104 };
105
106 #define MAX_JOYSTICKS 64
107 static INT joystick_devices_count = -1;
108 static struct JoyDev *joystick_devices;
109
110 static void joy_polldev(LPDIRECTINPUTDEVICE8A iface);
111
112 static INT find_joystick_devices(void)
113 {
114 INT i;
115
116 if (joystick_devices_count != -1) return joystick_devices_count;
117
118 joystick_devices_count = 0;
119 for (i = 0; i < MAX_JOYSTICKS; i++)
120 {
121 int fd;
122 struct JoyDev joydev, *new_joydevs;
123 BYTE axes_map[ABS_MAX + 1];
124
125 snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_NEW, i);
126 if ((fd = open(joydev.device, O_RDONLY)) < 0)
127 {
128 snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_OLD, i);
129 if ((fd = open(joydev.device, O_RDONLY)) < 0) continue;
130 }
131
132 strcpy(joydev.name, "Wine Joystick");
133 #if defined(JSIOCGNAME)
134 if (ioctl(fd, JSIOCGNAME(sizeof(joydev.name) - sizeof(JOYDEVDRIVER)), joydev.name) < 0)
135 WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", joydev.device, strerror(errno));
136 #endif
137
138 /* Append driver name */
139 strcat(joydev.name, JOYDEVDRIVER);
140
141 if (device_disabled_registry(joydev.name)) {
142 close(fd);
143 continue;
144 }
145
146 #ifdef JSIOCGAXES
147 if (ioctl(fd, JSIOCGAXES, &joydev.axis_count) < 0)
148 {
149 WARN("ioctl(%s,JSIOCGAXES) failed: %s, defauting to 2\n", joydev.device, strerror(errno));
150 joydev.axis_count = 2;
151 }
152 #endif
153 #ifdef JSIOCGBUTTONS
154 if (ioctl(fd, JSIOCGBUTTONS, &joydev.button_count) < 0)
155 {
156 WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defauting to 2\n", joydev.device, strerror(errno));
157 joydev.button_count = 2;
158 }
159 #endif
160
161 if (ioctl(fd, JSIOCGAXMAP, axes_map) < 0)
162 {
163 WARN("ioctl(%s,JSIOCGAXMAP) failed: %s\n", joydev.device, strerror(errno));
164 joydev.dev_axes_map = NULL;
165 }
166 else
167 if ((joydev.dev_axes_map = HeapAlloc(GetProcessHeap(), 0, joydev.axis_count * sizeof(int))))
168 {
169 INT j;
170
171 /* Remap to DI numbers */
172 for (j = 0; j < joydev.axis_count; j++)
173 if (axes_map[j] < 8)
174 /* Axis match 1-to-1 */
175 joydev.dev_axes_map[j] = j;
176 else if (axes_map[j] == 16 ||
177 axes_map[j] == 17)
178 /* POV axis */
179 joydev.dev_axes_map[j] = 8;
180 else
181 joydev.dev_axes_map[j] = -1;
182 }
183
184 close(fd);
185
186 if (!joystick_devices_count)
187 new_joydevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct JoyDev));
188 else
189 new_joydevs = HeapReAlloc(GetProcessHeap(), 0, joystick_devices,
190 (joystick_devices_count + 1) * sizeof(struct JoyDev));
191 if (!new_joydevs) continue;
192
193 TRACE("Found a joystick on %s: %s\n with %d axes and %d buttons\n", joydev.device,
194 joydev.name, joydev.axis_count, joydev.button_count);
195
196 joystick_devices = new_joydevs;
197 joystick_devices[joystick_devices_count++] = joydev;
198 }
199
200 return joystick_devices_count;
201 }
202
203 static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
204 {
205 int fd = -1;
206
207 if (id >= find_joystick_devices()) return E_FAIL;
208
209 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
210 WARN("force feedback not supported\n");
211 return S_FALSE;
212 }
213
214 if ((dwDevType == 0) ||
215 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
216 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
217 /* check whether we have a joystick */
218 if ((fd = open(joystick_devices[id].device, O_RDONLY)) < 0)
219 {
220 WARN("open(%s, O_RDONLY) failed: %s\n", joystick_devices[id].name, strerror(errno));
221 return S_FALSE;
222 }
223
224 /* Return joystick */
225 lpddi->guidInstance = DInput_Wine_Joystick_GUID;
226 lpddi->guidInstance.Data3 = id;
227 lpddi->guidProduct = DInput_Wine_Joystick_GUID;
228 /* we only support traditional joysticks for now */
229 if (version >= 0x0800)
230 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
231 else
232 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
233
234 strcpy(lpddi->tszInstanceName, joystick_devices[id].name);
235 strcpy(lpddi->tszProductName, joystick_devices[id].name);
236
237 lpddi->guidFFDriver = GUID_NULL;
238 close(fd);
239 TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id].device, lpddi->tszProductName);
240 return S_OK;
241 }
242
243 return S_FALSE;
244 }
245
246 static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
247 {
248 int fd = -1;
249
250 if (id >= find_joystick_devices()) return E_FAIL;
251
252 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
253 WARN("force feedback not supported\n");
254 return S_FALSE;
255 }
256
257 if ((dwDevType == 0) ||
258 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
259 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
260 /* check whether we have a joystick */
261 if ((fd = open(joystick_devices[id].device, O_RDONLY)) < 0)
262 {
263 WARN("open(%s,O_RDONLY) failed: %s\n", joystick_devices[id].device, strerror(errno));
264 return S_FALSE;
265 }
266
267 /* Return joystick */
268 lpddi->guidInstance = DInput_Wine_Joystick_GUID;
269 lpddi->guidInstance.Data3 = id;
270 lpddi->guidProduct = DInput_Wine_Joystick_GUID;
271 /* we only support traditional joysticks for now */
272 if (version >= 0x0800)
273 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
274 else
275 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
276
277 MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
278 MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszProductName, MAX_PATH);
279 lpddi->guidFFDriver = GUID_NULL;
280 close(fd);
281 TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id].device, joystick_devices[id].name);
282 return S_OK;
283 }
284
285 return S_FALSE;
286 }
287
288 static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
289 JoystickImpl **pdev, unsigned short index)
290 {
291 DWORD i;
292 JoystickImpl* newDevice;
293 HRESULT hr;
294 LPDIDATAFORMAT df = NULL;
295 int idx = 0;
296
297 TRACE("%s %p %p %hu\n", debugstr_guid(rguid), dinput, pdev, index);
298
299 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
300 if (newDevice == 0) {
301 WARN("out of memory\n");
302 *pdev = 0;
303 return DIERR_OUTOFMEMORY;
304 }
305
306 newDevice->joydev = &joystick_devices[index];
307 newDevice->joyfd = -1;
308 newDevice->generic.guidInstance = DInput_Wine_Joystick_GUID;
309 newDevice->generic.guidInstance.Data3 = index;
310 newDevice->generic.guidProduct = DInput_Wine_Joystick_GUID;
311 newDevice->generic.joy_polldev = joy_polldev;
312 newDevice->generic.name = newDevice->joydev->name;
313 newDevice->generic.device_axis_count = newDevice->joydev->axis_count;
314 newDevice->generic.devcaps.dwButtons = newDevice->joydev->button_count;
315
316 if (newDevice->generic.devcaps.dwButtons > 128)
317 {
318 WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
319 newDevice->generic.devcaps.dwButtons = 128;
320 }
321
322 newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt;
323 newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt;
324 newDevice->generic.base.ref = 1;
325 newDevice->generic.base.dinput = dinput;
326 newDevice->generic.base.guid = *rguid;
327 InitializeCriticalSection(&newDevice->generic.base.crit);
328 newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
329
330 /* setup_dinput_options may change these */
331 newDevice->generic.deadzone = 0;
332
333 /* do any user specified configuration */
334 hr = setup_dinput_options(&newDevice->generic, newDevice->joydev->dev_axes_map);
335 if (hr != DI_OK)
336 goto FAILED1;
337
338 /* Create copy of default data format */
339 if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
340 memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
341
342 df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
343 if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
344
345 for (i = 0; i < newDevice->generic.device_axis_count; i++)
346 {
347 int wine_obj = newDevice->generic.axis_map[i];
348
349 if (wine_obj < 0) continue;
350
351 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
352 if (wine_obj < 8)
353 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
354 else
355 {
356 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj - 8) | DIDFT_POV;
357 i++; /* POV takes 2 axes */
358 }
359 }
360 for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
361 {
362 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
363 df->rgodf[idx ].pguid = &GUID_Button;
364 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
365 }
366 newDevice->generic.base.data_format.wine_df = df;
367
368 /* initialize default properties */
369 for (i = 0; i < c_dfDIJoystick2.dwNumObjs; i++) {
370 newDevice->generic.props[i].lDevMin = -32767;
371 newDevice->generic.props[i].lDevMax = +32767;
372 newDevice->generic.props[i].lMin = 0;
373 newDevice->generic.props[i].lMax = 0xffff;
374 newDevice->generic.props[i].lDeadZone = newDevice->generic.deadzone; /* % * 1000 */
375 newDevice->generic.props[i].lSaturation = 0;
376 }
377
378 IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface);
379
380 EnterCriticalSection(&dinput->crit);
381 list_add_tail(&dinput->devices_list, &newDevice->generic.base.entry);
382 LeaveCriticalSection(&dinput->crit);
383
384 newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
385 newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
386 if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
387 newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
388 else
389 newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
390 newDevice->generic.devcaps.dwFFSamplePeriod = 0;
391 newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
392 newDevice->generic.devcaps.dwFirmwareRevision = 0;
393 newDevice->generic.devcaps.dwHardwareRevision = 0;
394 newDevice->generic.devcaps.dwFFDriverVersion = 0;
395
396 if (TRACE_ON(dinput)) {
397 _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
398 for (i = 0; i < (newDevice->generic.device_axis_count); i++)
399 TRACE("axis_map[%d] = %d\n", i, newDevice->generic.axis_map[i]);
400 _dump_DIDEVCAPS(&newDevice->generic.devcaps);
401 }
402
403 *pdev = newDevice;
404
405 return DI_OK;
406
407 FAILED:
408 hr = DIERR_OUTOFMEMORY;
409 FAILED1:
410 if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
411 HeapFree(GetProcessHeap(), 0, df);
412 release_DataFormat(&newDevice->generic.base.data_format);
413 HeapFree(GetProcessHeap(),0,newDevice->generic.axis_map);
414 HeapFree(GetProcessHeap(),0,newDevice);
415 *pdev = 0;
416
417 return hr;
418 }
419
420 /******************************************************************************
421 * get_joystick_index : Get the joystick index from a given GUID
422 */
423 static unsigned short get_joystick_index(REFGUID guid)
424 {
425 GUID wine_joystick = DInput_Wine_Joystick_GUID;
426 GUID dev_guid = *guid;
427
428 wine_joystick.Data3 = 0;
429 dev_guid.Data3 = 0;
430
431 /* for the standard joystick GUID use index 0 */
432 if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
433
434 /* for the wine joystick GUIDs use the index stored in Data3 */
435 if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
436
437 return MAX_JOYSTICKS;
438 }
439
440 static HRESULT joydev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode)
441 {
442 unsigned short index;
443
444 TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode);
445 find_joystick_devices();
446 *pdev = NULL;
447
448 if ((index = get_joystick_index(rguid)) < MAX_JOYSTICKS &&
449 joystick_devices_count && index < joystick_devices_count)
450 {
451 JoystickImpl *This;
452 HRESULT hr;
453
454 if (riid == NULL)
455 ;/* nothing */
456 else if (IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
457 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
458 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
459 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
460 {
461 unicode = 0;
462 }
463 else if (IsEqualGUID(&IID_IDirectInputDeviceW, riid) ||
464 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
465 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
466 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
467 {
468 unicode = 1;
469 }
470 else
471 {
472 WARN("no interface\n");
473 return DIERR_NOINTERFACE;
474 }
475
476 hr = alloc_device(rguid, dinput, &This, index);
477 if (!This) return hr;
478
479 if (unicode)
480 *pdev = &This->generic.base.IDirectInputDevice8W_iface;
481 else
482 *pdev = &This->generic.base.IDirectInputDevice8A_iface;
483
484 return hr;
485 }
486
487 return DIERR_DEVICENOTREG;
488 }
489
490 #undef MAX_JOYSTICKS
491
492 const struct dinput_device joystick_linux_device = {
493 "Wine Linux joystick driver",
494 joydev_enum_deviceA,
495 joydev_enum_deviceW,
496 joydev_create_device
497 };
498
499 /******************************************************************************
500 * Acquire : gets exclusive control of the joystick
501 */
502 static HRESULT WINAPI JoystickLinuxWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
503 {
504 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
505 HRESULT res;
506
507 TRACE("(%p)\n",This);
508
509 res = IDirectInputDevice2WImpl_Acquire(iface);
510 if (res != DI_OK)
511 return res;
512
513 /* open the joystick device */
514 if (This->joyfd==-1) {
515 TRACE("opening joystick device %s\n", This->joydev->device);
516
517 This->joyfd = open(This->joydev->device, O_RDONLY);
518 if (This->joyfd==-1) {
519 ERR("open(%s) failed: %s\n", This->joydev->device, strerror(errno));
520 IDirectInputDevice2WImpl_Unacquire(iface);
521 return DIERR_NOTFOUND;
522 }
523 }
524
525 return DI_OK;
526 }
527
528 static HRESULT WINAPI JoystickLinuxAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
529 {
530 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
531 return JoystickLinuxWImpl_Acquire(IDirectInputDevice8W_from_impl(This));
532 }
533
534 /******************************************************************************
535 * GetProperty : get input device properties
536 */
537 static HRESULT WINAPI JoystickLinuxWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph)
538 {
539 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
540
541 TRACE("(this=%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph);
542 _dump_DIPROPHEADER(pdiph);
543
544 if (!IS_DIPROP(rguid)) return DI_OK;
545
546 switch (LOWORD(rguid)) {
547
548 case (DWORD_PTR) DIPROP_JOYSTICKID:
549 {
550 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
551
552 pd->dwData = get_joystick_index(&This->generic.base.guid);
553 TRACE("DIPROP_JOYSTICKID(%d)\n", pd->dwData);
554 break;
555 }
556
557 default:
558 return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph);
559 }
560
561 return DI_OK;
562 }
563
564 static HRESULT WINAPI JoystickLinuxAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph)
565 {
566 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
567 return JoystickLinuxWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
568 }
569
570 /******************************************************************************
571 * Unacquire : frees the joystick
572 */
573 static HRESULT WINAPI JoystickLinuxWImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface)
574 {
575 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
576 HRESULT res;
577
578 TRACE("(%p)\n",This);
579
580 res = IDirectInputDevice2WImpl_Unacquire(iface);
581
582 if (res != DI_OK)
583 return res;
584
585 if (This->joyfd!=-1) {
586 TRACE("closing joystick device\n");
587 close(This->joyfd);
588 This->joyfd = -1;
589 return DI_OK;
590 }
591
592 return DI_NOEFFECT;
593 }
594
595 static HRESULT WINAPI JoystickLinuxAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
596 {
597 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
598 return JoystickLinuxWImpl_Unacquire(IDirectInputDevice8W_from_impl(This));
599 }
600
601 static void joy_polldev(LPDIRECTINPUTDEVICE8A iface)
602 {
603 struct pollfd plfd;
604 struct js_event jse;
605 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
606
607 TRACE("(%p)\n", This);
608
609 if (This->joyfd==-1) {
610 WARN("no device\n");
611 return;
612 }
613 while (1)
614 {
615 LONG value;
616 int inst_id = -1;
617
618 plfd.fd = This->joyfd;
619 plfd.events = POLLIN;
620 if (poll(&plfd,1,0) != 1)
621 return;
622 /* we have one event, so we can read */
623 if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) {
624 return;
625 }
626 TRACE("js_event: type 0x%x, number %d, value %d\n",
627 jse.type,jse.number,jse.value);
628 if (jse.type & JS_EVENT_BUTTON)
629 {
630 if (jse.number >= This->generic.devcaps.dwButtons) return;
631
632 inst_id = DIDFT_MAKEINSTANCE(jse.number) | DIDFT_PSHBUTTON;
633 This->generic.js.rgbButtons[jse.number] = value = jse.value ? 0x80 : 0x00;
634 }
635 else if (jse.type & JS_EVENT_AXIS)
636 {
637 int number = This->generic.axis_map[jse.number]; /* wine format object index */
638
639 if (number < 0) return;
640 inst_id = number < 8 ? DIDFT_MAKEINSTANCE(number) | DIDFT_ABSAXIS :
641 DIDFT_MAKEINSTANCE(number - 8) | DIDFT_POV;
642 value = joystick_map_axis(&This->generic.props[id_to_object(This->generic.base.data_format.wine_df, inst_id)], jse.value);
643
644 TRACE("changing axis %d => %d\n", jse.number, number);
645 switch (number)
646 {
647 case 0: This->generic.js.lX = value; break;
648 case 1: This->generic.js.lY = value; break;
649 case 2: This->generic.js.lZ = value; break;
650 case 3: This->generic.js.lRx = value; break;
651 case 4: This->generic.js.lRy = value; break;
652 case 5: This->generic.js.lRz = value; break;
653 case 6: This->generic.js.rglSlider[0] = value; break;
654 case 7: This->generic.js.rglSlider[1] = value; break;
655 case 8: case 9: case 10: case 11:
656 {
657 int idx = number - 8;
658
659 if (jse.number % 2)
660 This->povs[idx].y = jse.value;
661 else
662 This->povs[idx].x = jse.value;
663
664 This->generic.js.rgdwPOV[idx] = value = joystick_map_pov(&This->povs[idx]);
665 break;
666 }
667 default:
668 WARN("axis %d not supported\n", number);
669 }
670 }
671 if (inst_id >= 0)
672 queue_event(iface, inst_id, value, GetCurrentTime(), This->generic.base.dinput->evsequence++);
673 }
674 }
675
676 static const IDirectInputDevice8AVtbl JoystickAvt =
677 {
678 IDirectInputDevice2AImpl_QueryInterface,
679 IDirectInputDevice2AImpl_AddRef,
680 IDirectInputDevice2AImpl_Release,
681 JoystickAGenericImpl_GetCapabilities,
682 IDirectInputDevice2AImpl_EnumObjects,
683 JoystickLinuxAImpl_GetProperty,
684 JoystickAGenericImpl_SetProperty,
685 JoystickLinuxAImpl_Acquire,
686 JoystickLinuxAImpl_Unacquire,
687 JoystickAGenericImpl_GetDeviceState,
688 IDirectInputDevice2AImpl_GetDeviceData,
689 IDirectInputDevice2AImpl_SetDataFormat,
690 IDirectInputDevice2AImpl_SetEventNotification,
691 IDirectInputDevice2AImpl_SetCooperativeLevel,
692 JoystickAGenericImpl_GetObjectInfo,
693 JoystickAGenericImpl_GetDeviceInfo,
694 IDirectInputDevice2AImpl_RunControlPanel,
695 IDirectInputDevice2AImpl_Initialize,
696 IDirectInputDevice2AImpl_CreateEffect,
697 IDirectInputDevice2AImpl_EnumEffects,
698 IDirectInputDevice2AImpl_GetEffectInfo,
699 IDirectInputDevice2AImpl_GetForceFeedbackState,
700 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
701 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
702 IDirectInputDevice2AImpl_Escape,
703 JoystickAGenericImpl_Poll,
704 IDirectInputDevice2AImpl_SendDeviceData,
705 IDirectInputDevice7AImpl_EnumEffectsInFile,
706 IDirectInputDevice7AImpl_WriteEffectToFile,
707 JoystickAGenericImpl_BuildActionMap,
708 JoystickAGenericImpl_SetActionMap,
709 IDirectInputDevice8AImpl_GetImageInfo
710 };
711
712 static const IDirectInputDevice8WVtbl JoystickWvt =
713 {
714 IDirectInputDevice2WImpl_QueryInterface,
715 IDirectInputDevice2WImpl_AddRef,
716 IDirectInputDevice2WImpl_Release,
717 JoystickWGenericImpl_GetCapabilities,
718 IDirectInputDevice2WImpl_EnumObjects,
719 JoystickLinuxWImpl_GetProperty,
720 JoystickWGenericImpl_SetProperty,
721 JoystickLinuxWImpl_Acquire,
722 JoystickLinuxWImpl_Unacquire,
723 JoystickWGenericImpl_GetDeviceState,
724 IDirectInputDevice2WImpl_GetDeviceData,
725 IDirectInputDevice2WImpl_SetDataFormat,
726 IDirectInputDevice2WImpl_SetEventNotification,
727 IDirectInputDevice2WImpl_SetCooperativeLevel,
728 JoystickWGenericImpl_GetObjectInfo,
729 JoystickWGenericImpl_GetDeviceInfo,
730 IDirectInputDevice2WImpl_RunControlPanel,
731 IDirectInputDevice2WImpl_Initialize,
732 IDirectInputDevice2WImpl_CreateEffect,
733 IDirectInputDevice2WImpl_EnumEffects,
734 IDirectInputDevice2WImpl_GetEffectInfo,
735 IDirectInputDevice2WImpl_GetForceFeedbackState,
736 IDirectInputDevice2WImpl_SendForceFeedbackCommand,
737 IDirectInputDevice2WImpl_EnumCreatedEffectObjects,
738 IDirectInputDevice2WImpl_Escape,
739 JoystickWGenericImpl_Poll,
740 IDirectInputDevice2WImpl_SendDeviceData,
741 IDirectInputDevice7WImpl_EnumEffectsInFile,
742 IDirectInputDevice7WImpl_WriteEffectToFile,
743 JoystickWGenericImpl_BuildActionMap,
744 JoystickWGenericImpl_SetActionMap,
745 IDirectInputDevice8WImpl_GetImageInfo
746 };
747
748 #else /* HAVE_LINUX_22_JOYSTICK_API */
749
750 const struct dinput_device joystick_linux_device = {
751 "Wine Linux joystick driver",
752 NULL,
753 NULL,
754 NULL
755 };
756
757 #endif /* HAVE_LINUX_22_JOYSTICK_API */