1 /* DirectInput Joystick device
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
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.
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.
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
29 #include "wine/port.h"
39 #ifdef HAVE_SYS_TIME_H
40 # include <sys/time.h>
42 #include <sys/fcntl.h>
43 #ifdef HAVE_SYS_IOCTL_H
44 # include <sys/ioctl.h>
47 #ifdef HAVE_SYS_ERRNO_H
48 # include <sys/errno.h>
50 #ifdef HAVE_LINUX_IOCTL_H
51 # include <linux/ioctl.h>
53 #ifdef HAVE_LINUX_JOYSTICK_H
54 # include <linux/joystick.h>
56 #ifdef HAVE_SYS_POLL_H
57 # include <sys/poll.h>
60 #include "wine/debug.h"
61 #include "wine/unicode.h"
68 #include "dinput_private.h"
69 #include "device_private.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
73 #ifdef HAVE_LINUX_22_JOYSTICK_API
75 #define JOYDEV_NEW "/dev/input/js"
76 #define JOYDEV_OLD "/dev/js"
90 typedef struct JoystickImpl JoystickImpl;
91 static const IDirectInputDevice8AVtbl JoystickAvt;
92 static const IDirectInputDevice8WVtbl JoystickWvt;
95 struct IDirectInputDevice2AImpl base;
99 /* The 'parent' DInput */
100 IDirectInputImpl *dinput;
102 /* joystick private */
104 DIJOYSTATE2 js; /* wine data */
115 static GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */
119 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
122 static void _dump_DIDEVCAPS(LPDIDEVCAPS lpDIDevCaps)
124 TRACE("dwSize: %d\n", lpDIDevCaps->dwSize);
125 TRACE("dwFlags: %08x\n", lpDIDevCaps->dwFlags);
126 TRACE("dwDevType: %08x %s\n", lpDIDevCaps->dwDevType,
127 lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" :
128 lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" :
129 lpDIDevCaps->dwDevType == DIDEVTYPE_MOUSE ? "DIDEVTYPE_MOUSE" :
130 lpDIDevCaps->dwDevType == DIDEVTYPE_KEYBOARD ? "DIDEVTYPE_KEYBOARD" :
131 lpDIDevCaps->dwDevType == DIDEVTYPE_JOYSTICK ? "DIDEVTYPE_JOYSTICK" :
132 lpDIDevCaps->dwDevType == DIDEVTYPE_HID ? "DIDEVTYPE_HID" : "UNKNOWN");
133 TRACE("dwAxes: %d\n", lpDIDevCaps->dwAxes);
134 TRACE("dwButtons: %d\n", lpDIDevCaps->dwButtons);
135 TRACE("dwPOVs: %d\n", lpDIDevCaps->dwPOVs);
136 if (lpDIDevCaps->dwSize > sizeof(DIDEVCAPS_DX3)) {
137 TRACE("dwFFSamplePeriod: %d\n", lpDIDevCaps->dwFFSamplePeriod);
138 TRACE("dwFFMinTimeResolution: %d\n", lpDIDevCaps->dwFFMinTimeResolution);
139 TRACE("dwFirmwareRevision: %d\n", lpDIDevCaps->dwFirmwareRevision);
140 TRACE("dwHardwareRevision: %d\n", lpDIDevCaps->dwHardwareRevision);
141 TRACE("dwFFDriverVersion: %d\n", lpDIDevCaps->dwFFDriverVersion);
145 static int joydev_get_device(char *dev, int id)
148 sprintf(dev, "%s%d", JOYDEV_NEW, id);
149 if ((ret = open(dev, O_RDONLY)) < 0) {
150 sprintf(dev, "%s%d", JOYDEV_OLD, id);
151 if ((ret = open(dev, O_RDONLY)) < 0) {
158 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
163 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
164 WARN("force feedback not supported\n");
168 if ((dwDevType == 0) ||
169 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
170 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
171 /* check whether we have a joystick */
172 if ((fd = joydev_get_device(dev, id)) < 0) {
173 WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno));
177 /* Return joystick */
178 lpddi->guidInstance = DInput_Wine_Joystick_GUID;
179 lpddi->guidInstance.Data3 = id;
180 lpddi->guidProduct = DInput_Wine_Joystick_GUID;
181 /* we only support traditional joysticks for now */
182 if (version >= 0x0800)
183 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
185 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
186 sprintf(lpddi->tszInstanceName, "Joystick %d", id);
187 #if defined(JSIOCGNAME)
188 if (ioctl(fd,JSIOCGNAME(sizeof(lpddi->tszProductName)),lpddi->tszProductName) < 0) {
189 WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno));
190 strcpy(lpddi->tszProductName, "Wine Joystick");
193 strcpy(lpddi->tszProductName, "Wine Joystick");
196 lpddi->guidFFDriver = GUID_NULL;
198 TRACE("Enumerating the linux Joystick device: %s (%s)\n", dev, lpddi->tszProductName);
205 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
212 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
213 WARN("force feedback not supported\n");
217 if ((dwDevType == 0) ||
218 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
219 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
220 /* check whether we have a joystick */
221 if ((fd = joydev_get_device(dev, id)) < 0) {
222 WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno));
226 /* Return joystick */
227 lpddi->guidInstance = DInput_Wine_Joystick_GUID;
228 lpddi->guidInstance.Data3 = id;
229 lpddi->guidProduct = DInput_Wine_Joystick_GUID;
230 /* we only support traditional joysticks for now */
231 if (version >= 0x0800)
232 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
234 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
235 sprintf(friendly, "Joystick %d", id);
236 MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
237 #if defined(JSIOCGNAME)
238 if (ioctl(fd,JSIOCGNAME(sizeof(name)),name) < 0) {
239 WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno));
240 strcpy(name, "Wine Joystick");
243 strcpy(name, "Wine Joystick");
245 MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
246 lpddi->guidFFDriver = GUID_NULL;
248 TRACE("Enumerating the linux Joystick device: %s (%s)\n",dev,name);
256 * Get a config key from either the app-specific or the default config
259 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
260 char *buffer, DWORD size )
262 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size ))
265 if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size ))
268 return ERROR_FILE_NOT_FOUND;
272 * Setup the dinput options.
275 static HRESULT setup_dinput_options(JoystickImpl * device)
277 char buffer[MAX_PATH+16];
278 HKEY hkey, appkey = 0;
281 buffer[MAX_PATH]='\0';
283 /* @@ Wine registry key: HKCU\Software\Wine\DirectInput */
284 if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\DirectInput", &hkey)) hkey = 0;
286 len = GetModuleFileNameA( 0, buffer, MAX_PATH );
287 if (len && len < MAX_PATH) {
289 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectInput */
290 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
292 char *p, *appname = buffer;
293 if ((p = strrchr( appname, '/' ))) appname = p + 1;
294 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
295 strcat( appname, "\\DirectInput" );
296 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
297 RegCloseKey( tmpkey );
303 if (!get_config_key( hkey, appkey, "DefaultDeadZone", buffer, MAX_PATH )) {
304 device->deadzone = atoi(buffer);
305 TRACE("setting default deadzone to: \"%s\" %d\n", buffer, device->deadzone);
308 if (!get_config_key( hkey, appkey, device->name, buffer, MAX_PATH )) {
312 const char *delim = ",";
314 TRACE("\"%s\" = \"%s\"\n", device->name, buffer);
316 device->axis_map = HeapAlloc(GetProcessHeap(), 0, device->axes * sizeof(int));
317 if (device->axis_map == 0)
318 return DIERR_OUTOFMEMORY;
320 if ((ptr = strtok(buffer, delim)) != NULL) {
322 if (strcmp(ptr, "X") == 0) {
323 device->axis_map[tokens] = 0;
325 } else if (strcmp(ptr, "Y") == 0) {
326 device->axis_map[tokens] = 1;
328 } else if (strcmp(ptr, "Z") == 0) {
329 device->axis_map[tokens] = 2;
331 } else if (strcmp(ptr, "Rx") == 0) {
332 device->axis_map[tokens] = 3;
334 } else if (strcmp(ptr, "Ry") == 0) {
335 device->axis_map[tokens] = 4;
337 } else if (strcmp(ptr, "Rz") == 0) {
338 device->axis_map[tokens] = 5;
340 } else if (strcmp(ptr, "Slider1") == 0) {
341 device->axis_map[tokens] = 6;
343 } else if (strcmp(ptr, "Slider2") == 0) {
344 device->axis_map[tokens] = 7;
346 } else if (strcmp(ptr, "POV1") == 0) {
347 device->axis_map[tokens++] = 8;
348 device->axis_map[tokens] = 8;
350 } else if (strcmp(ptr, "POV2") == 0) {
351 device->axis_map[tokens++] = 9;
352 device->axis_map[tokens] = 9;
354 } else if (strcmp(ptr, "POV3") == 0) {
355 device->axis_map[tokens++] = 10;
356 device->axis_map[tokens] = 10;
358 } else if (strcmp(ptr, "POV4") == 0) {
359 device->axis_map[tokens++] = 11;
360 device->axis_map[tokens] = 11;
363 ERR("invalid joystick axis type: %s\n", ptr);
364 device->axis_map[tokens] = tokens;
369 } while ((ptr = strtok(NULL, delim)) != NULL);
371 if (tokens != device->devcaps.dwAxes) {
372 ERR("not all joystick axes mapped: %d axes(%d,%d), %d arguments\n", device->axes, axis, pov,tokens);
373 while (tokens < device->axes) {
374 device->axis_map[tokens] = tokens;
380 device->devcaps.dwAxes = axis;
381 device->devcaps.dwPOVs = pov;
385 RegCloseKey( appkey );
393 static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput, LPDIRECTINPUTDEVICEA* pdev)
396 JoystickImpl* newDevice;
400 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
401 if (newDevice == 0) {
402 WARN("out of memory\n");
404 return DIERR_OUTOFMEMORY;
407 if ((newDevice->joyfd = joydev_get_device(newDevice->dev, rguid->Data3)) < 0) {
408 WARN("open(%s,O_RDONLY) failed: %s\n", newDevice->dev, strerror(errno));
409 HeapFree(GetProcessHeap(), 0, newDevice);
410 return DIERR_DEVICENOTREG;
413 /* get the device name */
414 #if defined(JSIOCGNAME)
415 if (ioctl(newDevice->joyfd,JSIOCGNAME(MAX_PATH),name) < 0) {
416 WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", newDevice->dev, strerror(errno));
417 strcpy(name, "Wine Joystick");
420 strcpy(name, "Wine Joystick");
423 /* copy the device name */
424 newDevice->name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
425 strcpy(newDevice->name, name);
428 if (ioctl(newDevice->joyfd,JSIOCGAXES,&newDevice->axes) < 0) {
429 WARN("ioctl(%s,JSIOCGAXES) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno));
434 if (ioctl(newDevice->joyfd,JSIOCGBUTTONS,&newDevice->buttons) < 0) {
435 WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno));
436 newDevice->buttons = 2;
440 newDevice->base.lpVtbl = jvt;
441 newDevice->base.ref = 1;
442 newDevice->dinput = dinput;
443 CopyMemory(&newDevice->base.guid, rguid, sizeof(*rguid));
444 InitializeCriticalSection(&newDevice->base.crit);
445 newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)"DINPUT_joystick";
447 /* setup_dinput_options may change these */
448 newDevice->deadzone = 5000;
449 newDevice->devcaps.dwButtons = newDevice->buttons;
450 newDevice->devcaps.dwAxes = newDevice->axes;
451 newDevice->devcaps.dwPOVs = 0;
453 /* do any user specified configuration */
454 hr = setup_dinput_options(newDevice);
458 if (newDevice->axis_map == 0) {
459 newDevice->axis_map = HeapAlloc(GetProcessHeap(), 0, newDevice->axes * sizeof(int));
460 if (newDevice->axis_map == 0)
463 for (i = 0; i < newDevice->axes; i++)
464 newDevice->axis_map[i] = i;
467 /* create default properties */
468 newDevice->props = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*sizeof(ObjProps));
469 if (newDevice->props == 0)
472 /* initialize default properties */
473 for (i = 0; i < c_dfDIJoystick2.dwNumObjs; i++) {
474 newDevice->props[i].lMin = 0;
475 newDevice->props[i].lMax = 0xffff;
476 newDevice->props[i].lDeadZone = newDevice->deadzone; /* % * 1000 */
477 newDevice->props[i].lSaturation = 0;
480 /* wine uses DIJOYSTATE2 as it's internal format */
481 newDevice->base.data_format.wine_df = &c_dfDIJoystick2;
483 /* create the default transform filter */
484 hr = create_DataFormat(&c_dfDIJoystick2, &newDevice->base.data_format);
485 if (hr != DI_OK) goto FAILED;
487 IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->dinput);
489 newDevice->devcaps.dwSize = sizeof(newDevice->devcaps);
490 newDevice->devcaps.dwFlags = DIDC_ATTACHED;
491 if (newDevice->dinput->dwVersion >= 0x0800)
492 newDevice->devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
494 newDevice->devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
495 newDevice->devcaps.dwFFSamplePeriod = 0;
496 newDevice->devcaps.dwFFMinTimeResolution = 0;
497 newDevice->devcaps.dwFirmwareRevision = 0;
498 newDevice->devcaps.dwHardwareRevision = 0;
499 newDevice->devcaps.dwFFDriverVersion = 0;
501 if (TRACE_ON(dinput)) {
502 _dump_DIDATAFORMAT(newDevice->base.data_format.user_df);
503 for (i = 0; i < (newDevice->axes); i++)
504 TRACE("axis_map[%d] = %d\n", i, newDevice->axis_map[i]);
505 _dump_DIDEVCAPS(&newDevice->devcaps);
508 *pdev = (LPDIRECTINPUTDEVICEA)newDevice;
513 hr = DIERR_OUTOFMEMORY;
515 release_DataFormat(&newDevice->base.data_format);
516 HeapFree(GetProcessHeap(),0,newDevice->axis_map);
517 HeapFree(GetProcessHeap(),0,newDevice->name);
518 HeapFree(GetProcessHeap(),0,newDevice->props);
519 HeapFree(GetProcessHeap(),0,newDevice);
525 static BOOL IsJoystickGUID(REFGUID guid)
527 GUID wine_joystick = DInput_Wine_Joystick_GUID;
528 GUID dev_guid = *guid;
530 wine_joystick.Data3 = 0;
533 return IsEqualGUID(&wine_joystick, &dev_guid);
536 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
538 if ((IsEqualGUID(&GUID_Joystick,rguid)) ||
539 (IsJoystickGUID(rguid))) {
540 if ((riid == NULL) ||
541 IsEqualGUID(&IID_IDirectInputDeviceA,riid) ||
542 IsEqualGUID(&IID_IDirectInputDevice2A,riid) ||
543 IsEqualGUID(&IID_IDirectInputDevice7A,riid) ||
544 IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
545 return alloc_device(rguid, &JoystickAvt, dinput, pdev);
547 WARN("no interface\n");
549 return DIERR_NOINTERFACE;
553 WARN("invalid device GUID\n");
555 return DIERR_DEVICENOTREG;
558 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
560 if ((IsEqualGUID(&GUID_Joystick,rguid)) ||
561 (IsJoystickGUID(rguid))) {
562 if ((riid == NULL) ||
563 IsEqualGUID(&IID_IDirectInputDeviceW,riid) ||
564 IsEqualGUID(&IID_IDirectInputDevice2W,riid) ||
565 IsEqualGUID(&IID_IDirectInputDevice7W,riid) ||
566 IsEqualGUID(&IID_IDirectInputDevice8W,riid)) {
567 return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev);
569 WARN("no interface\n");
571 return DIERR_NOINTERFACE;
575 WARN("invalid device GUID\n");
577 return DIERR_DEVICENOTREG;
580 const struct dinput_device joystick_linux_device = {
581 "Wine Linux joystick driver",
584 joydev_create_deviceA,
585 joydev_create_deviceW
588 /******************************************************************************
591 static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface)
593 JoystickImpl *This = (JoystickImpl *)iface;
596 ref = InterlockedDecrement(&This->base.ref);
600 /* Free the device name */
601 HeapFree(GetProcessHeap(),0,This->name);
603 /* Free the axis map */
604 HeapFree(GetProcessHeap(),0,This->axis_map);
606 /* Free the data queue */
607 HeapFree(GetProcessHeap(), 0, This->base.data_queue);
609 /* Free the properties */
610 HeapFree(GetProcessHeap(), 0, This->props);
612 /* release the data transform filter */
613 release_DataFormat(&This->base.data_format);
615 This->base.crit.DebugInfo->Spare[0] = 0;
616 IDirectInput_Release((LPDIRECTINPUTDEVICE8A)This->dinput);
617 DeleteCriticalSection(&This->base.crit);
619 HeapFree(GetProcessHeap(),0,This);
623 /******************************************************************************
624 * SetDataFormat : the application can choose the format of the data
625 * the device driver sends back with GetDeviceState.
627 static HRESULT WINAPI JoystickAImpl_SetDataFormat(
628 LPDIRECTINPUTDEVICE8A iface,
631 JoystickImpl *This = (JoystickImpl *)iface;
633 ObjProps * new_props = 0;
636 TRACE("(%p,%p)\n",This,df);
638 hr = IDirectInputDevice2AImpl_SetDataFormat(iface, df);
639 if (FAILED(hr)) return hr;
641 new_props = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*sizeof(ObjProps));
642 if (!new_props) return DIERR_OUTOFMEMORY;
644 HeapFree(GetProcessHeap(),0,This->props);
646 This->props = new_props;
647 for (i = 0; i < df->dwNumObjs; i++) {
648 This->props[i].lMin = 0;
649 This->props[i].lMax = 0xffff;
650 This->props[i].lDeadZone = 1000;
651 This->props[i].lSaturation = 0;
657 /******************************************************************************
658 * Acquire : gets exclusive control of the joystick
660 static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
662 JoystickImpl *This = (JoystickImpl *)iface;
664 TRACE("(%p)\n",This);
666 if (This->base.acquired) {
667 WARN("already acquired\n");
671 /* open the joystick device */
672 if (This->joyfd==-1) {
673 TRACE("opening joystick device %s\n", This->dev);
675 This->joyfd=open(This->dev,O_RDONLY);
676 if (This->joyfd==-1) {
677 ERR("open(%s) failed: %s\n", This->dev, strerror(errno));
678 return DIERR_NOTFOUND;
682 This->base.acquired = 1;
687 /******************************************************************************
688 * Unacquire : frees the joystick
690 static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
692 JoystickImpl *This = (JoystickImpl *)iface;
695 TRACE("(%p)\n",This);
697 if ((res = IDirectInputDevice2AImpl_Unacquire(iface)) != DI_OK) return res;
699 if (This->joyfd!=-1) {
700 TRACE("closing joystick device\n");
709 static LONG map_axis(JoystickImpl * This, short val, short index)
712 double fmin = This->props[index].lMin;
713 double fmax = This->props[index].lMax;
716 fret = (((fval + 32767.0) * (fmax - fmin)) / (32767.0*2.0)) + fmin;
726 static LONG calculate_pov(JoystickImpl *This, int index)
728 if (This->povs[index].lX < -16384) {
729 if (This->povs[index].lY < -16384)
730 This->js.rgdwPOV[index] = 31500;
731 else if (This->povs[index].lY > 16384)
732 This->js.rgdwPOV[index] = 22500;
734 This->js.rgdwPOV[index] = 27000;
735 } else if (This->povs[index].lX > 16384) {
736 if (This->povs[index].lY < -16384)
737 This->js.rgdwPOV[index] = 4500;
738 else if (This->povs[index].lY > 16384)
739 This->js.rgdwPOV[index] = 13500;
741 This->js.rgdwPOV[index] = 9000;
743 if (This->povs[index].lY < -16384)
744 This->js.rgdwPOV[index] = 0;
745 else if (This->povs[index].lY > 16384)
746 This->js.rgdwPOV[index] = 18000;
748 This->js.rgdwPOV[index] = -1;
751 return This->js.rgdwPOV[index];
754 static void joy_polldev(JoystickImpl *This) {
757 TRACE("(%p)\n", This);
759 if (This->joyfd==-1) {
764 plfd.fd = This->joyfd;
765 plfd.events = POLLIN;
766 if (poll(&plfd,1,0) != 1)
768 /* we have one event, so we can read */
769 if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) {
772 TRACE("js_event: type 0x%x, number %d, value %d\n",
773 jse.type,jse.number,jse.value);
774 if (jse.type & JS_EVENT_BUTTON) {
775 int offset = This->base.data_format.offsets[jse.number + 12];
776 int value = jse.value?0x80:0x00;
778 This->js.rgbButtons[jse.number] = value;
779 queue_event((LPDIRECTINPUTDEVICE8A)This, offset, value, jse.time, This->dinput->evsequence++);
780 } else if (jse.type & JS_EVENT_AXIS) {
781 int number = This->axis_map[jse.number]; /* wine format object index */
783 int offset = This->base.data_format.offsets[number];
784 int index = offset_to_object(This->base.data_format.user_df, offset);
785 LONG value = map_axis(This, jse.value, index);
787 /* FIXME do deadzone and saturation here */
789 TRACE("changing axis %d => %d\n", jse.number, number);
801 This->js.lRx = value;
804 This->js.lRy = value;
807 This->js.lRz = value;
810 This->js.rglSlider[0] = value;
813 This->js.rglSlider[1] = value;
816 /* FIXME don't go off array */
817 if (This->axis_map[jse.number + 1] == number)
818 This->povs[0].lX = jse.value;
819 else if (This->axis_map[jse.number - 1] == number)
820 This->povs[0].lY = jse.value;
821 value = calculate_pov(This, 0);
824 if (This->axis_map[jse.number + 1] == number)
825 This->povs[1].lX = jse.value;
826 else if (This->axis_map[jse.number - 1] == number)
827 This->povs[1].lY = jse.value;
828 value = calculate_pov(This, 1);
831 if (This->axis_map[jse.number + 1] == number)
832 This->povs[2].lX = jse.value;
833 else if (This->axis_map[jse.number - 1] == number)
834 This->povs[2].lY = jse.value;
835 value = calculate_pov(This, 2);
838 if (This->axis_map[jse.number + 1] == number)
839 This->povs[3].lX = jse.value;
840 else if (This->axis_map[jse.number - 1] == number)
841 This->povs[3].lY = jse.value;
842 value = calculate_pov(This, 3);
846 queue_event((LPDIRECTINPUTDEVICE8A)This, offset, value, jse.time, This->dinput->evsequence++);
848 WARN("axis %d not supported\n", number);
853 /******************************************************************************
854 * GetDeviceState : returns the "state" of the joystick.
857 static HRESULT WINAPI JoystickAImpl_GetDeviceState(
858 LPDIRECTINPUTDEVICE8A iface,
862 JoystickImpl *This = (JoystickImpl *)iface;
864 TRACE("(%p,0x%08x,%p)\n", This, len, ptr);
866 if (!This->base.acquired) {
867 WARN("not acquired\n");
868 return DIERR_NOTACQUIRED;
871 /* update joystick state */
874 /* convert and copy data to user supplied buffer */
875 fill_DataFormat(ptr, &This->js, &This->base.data_format);
880 /******************************************************************************
881 * SetProperty : change input device properties
883 static HRESULT WINAPI JoystickAImpl_SetProperty(
884 LPDIRECTINPUTDEVICE8A iface,
888 JoystickImpl *This = (JoystickImpl *)iface;
891 TRACE("(%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
894 WARN("invalid parameter: ph == NULL\n");
895 return DIERR_INVALIDPARAM;
898 if (TRACE_ON(dinput))
899 _dump_DIPROPHEADER(ph);
901 if (!HIWORD(rguid)) {
902 switch (LOWORD(rguid)) {
903 case (DWORD)DIPROP_RANGE: {
904 LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph;
905 if (ph->dwHow == DIPH_DEVICE) {
906 TRACE("proprange(%d,%d) all\n", pr->lMin, pr->lMax);
907 for (i = 0; i < This->base.data_format.user_df->dwNumObjs; i++) {
908 This->props[i].lMin = pr->lMin;
909 This->props[i].lMax = pr->lMax;
912 int obj = find_property(This->base.data_format.user_df, ph);
913 TRACE("proprange(%d,%d) obj=%d\n", pr->lMin, pr->lMax, obj);
915 This->props[obj].lMin = pr->lMin;
916 This->props[obj].lMax = pr->lMax;
922 case (DWORD)DIPROP_DEADZONE: {
923 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
924 if (ph->dwHow == DIPH_DEVICE) {
925 TRACE("deadzone(%d) all\n", pd->dwData);
926 for (i = 0; i < This->base.data_format.user_df->dwNumObjs; i++)
927 This->props[i].lDeadZone = pd->dwData;
929 int obj = find_property(This->base.data_format.user_df, ph);
930 TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj);
932 This->props[obj].lDeadZone = pd->dwData;
938 case (DWORD)DIPROP_SATURATION: {
939 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
940 if (ph->dwHow == DIPH_DEVICE) {
941 TRACE("saturation(%d) all\n", pd->dwData);
942 for (i = 0; i < This->base.data_format.user_df->dwNumObjs; i++)
943 This->props[i].lSaturation = pd->dwData;
945 int obj = find_property(This->base.data_format.user_df, ph);
946 TRACE("saturation(%d) obj=%d\n", pd->dwData, obj);
948 This->props[obj].lSaturation = pd->dwData;
955 return IDirectInputDevice2AImpl_SetProperty(iface, rguid, ph);
962 static HRESULT WINAPI JoystickAImpl_GetCapabilities(
963 LPDIRECTINPUTDEVICE8A iface,
964 LPDIDEVCAPS lpDIDevCaps)
966 JoystickImpl *This = (JoystickImpl *)iface;
969 TRACE("%p->(%p)\n",iface,lpDIDevCaps);
971 if (lpDIDevCaps == NULL) {
972 WARN("invalid pointer\n");
976 size = lpDIDevCaps->dwSize;
978 if (!(size == sizeof(DIDEVCAPS) || size == sizeof(DIDEVCAPS_DX3))) {
979 WARN("invalid parameter\n");
980 return DIERR_INVALIDPARAM;
983 CopyMemory(lpDIDevCaps, &This->devcaps, size);
984 lpDIDevCaps->dwSize = size;
986 if (TRACE_ON(dinput))
987 _dump_DIDEVCAPS(lpDIDevCaps);
992 static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface)
994 JoystickImpl *This = (JoystickImpl *)iface;
996 TRACE("(%p)\n",This);
998 if (!This->base.acquired) {
999 WARN("not acquired\n");
1000 return DIERR_NOTACQUIRED;
1007 /******************************************************************************
1008 * EnumObjects : enumerate the different buttons and axis...
1010 static HRESULT WINAPI JoystickAImpl_EnumObjects(
1011 LPDIRECTINPUTDEVICE8A iface,
1012 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
1016 JoystickImpl *This = (JoystickImpl *)iface;
1017 DIDEVICEOBJECTINSTANCEA ddoi;
1022 TRACE("(this=%p,%p,%p,%08x)\n", This, lpCallback, lpvRef, dwFlags);
1023 if (TRACE_ON(dinput)) {
1024 TRACE(" - flags = ");
1025 _dump_EnumObjects_flags(dwFlags);
1029 /* Only the fields till dwFFMaxForce are relevant */
1030 ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
1032 /* For the joystick, do as is done in the GetCapabilities function */
1033 if ((dwFlags == DIDFT_ALL) ||
1034 (dwFlags & DIDFT_AXIS) ||
1035 (dwFlags & DIDFT_POV)) {
1036 int pov[4] = { 0, 0, 0, 0 };
1040 for (i = 0; i < This->axes; i++) {
1041 int wine_obj = This->axis_map[i];
1046 ddoi.guidType = GUID_XAxis;
1049 ddoi.guidType = GUID_YAxis;
1052 ddoi.guidType = GUID_ZAxis;
1055 ddoi.guidType = GUID_RxAxis;
1058 ddoi.guidType = GUID_RyAxis;
1061 ddoi.guidType = GUID_RzAxis;
1064 ddoi.guidType = GUID_Slider;
1067 ddoi.guidType = GUID_Slider;
1071 ddoi.guidType = GUID_POV;
1075 ddoi.guidType = GUID_POV;
1079 ddoi.guidType = GUID_POV;
1083 ddoi.guidType = GUID_POV;
1086 ddoi.guidType = GUID_Unknown;
1089 user_offset = This->base.data_format.offsets[wine_obj]; /* get user offset from wine index */
1090 user_object = offset_to_object(This->base.data_format.user_df, user_offset);
1092 ddoi.dwType = This->base.data_format.user_df->rgodf[user_object].dwType & 0x00ffffff;
1093 ddoi.dwOfs = This->base.data_format.user_df->rgodf[user_object].dwOfs;
1094 sprintf(ddoi.tszName, "Axis %d", axes);
1097 if (pov[wine_obj - 8] < 2) {
1098 user_offset = This->base.data_format.offsets[wine_obj]; /* get user offset from wine index */
1099 user_object = offset_to_object(This->base.data_format.user_df, user_offset);
1101 ddoi.dwType = This->base.data_format.user_df->rgodf[user_object].dwType & 0x00ffffff;
1102 ddoi.dwOfs = This->base.data_format.user_df->rgodf[user_object].dwOfs;
1103 sprintf(ddoi.tszName, "POV %d", povs);
1109 _dump_OBJECTINSTANCEA(&ddoi);
1110 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE)
1116 if ((dwFlags == DIDFT_ALL) ||
1117 (dwFlags & DIDFT_BUTTON)) {
1119 /* The DInput SDK says that GUID_Button is only for mouse buttons but well... */
1120 ddoi.guidType = GUID_Button;
1122 for (i = 0; i < This->buttons; i++) {
1123 user_offset = This->base.data_format.offsets[i + 12]; /* get user offset from wine index */
1124 user_object = offset_to_object(This->base.data_format.user_df, user_offset);
1125 ddoi.guidType = GUID_Button;
1126 ddoi.dwType = This->base.data_format.user_df->rgodf[user_object].dwType & 0x00ffffff;
1127 ddoi.dwOfs = This->base.data_format.user_df->rgodf[user_object].dwOfs;
1128 sprintf(ddoi.tszName, "Button %d", i);
1129 _dump_OBJECTINSTANCEA(&ddoi);
1130 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1137 /******************************************************************************
1138 * EnumObjects : enumerate the different buttons and axis...
1140 static HRESULT WINAPI JoystickWImpl_EnumObjects(
1141 LPDIRECTINPUTDEVICE8W iface,
1142 LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback,
1146 JoystickImpl *This = (JoystickImpl *)iface;
1148 device_enumobjects_AtoWcb_data data;
1150 data.lpCallBack = lpCallback;
1151 data.lpvRef = lpvRef;
1153 return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags);
1156 /******************************************************************************
1157 * GetProperty : get input device properties
1159 static HRESULT WINAPI JoystickAImpl_GetProperty(
1160 LPDIRECTINPUTDEVICE8A iface,
1162 LPDIPROPHEADER pdiph)
1164 JoystickImpl *This = (JoystickImpl *)iface;
1166 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph);
1168 if (TRACE_ON(dinput))
1169 _dump_DIPROPHEADER(pdiph);
1171 if (!HIWORD(rguid)) {
1172 switch (LOWORD(rguid)) {
1173 case (DWORD) DIPROP_RANGE: {
1174 LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
1175 int obj = find_property(This->base.data_format.user_df, pdiph);
1176 /* The app is querying the current range of the axis
1177 * return the lMin and lMax values */
1179 pr->lMin = This->props[obj].lMin;
1180 pr->lMax = This->props[obj].lMax;
1181 TRACE("range(%d, %d) obj=%d\n", pr->lMin, pr->lMax, obj);
1186 case (DWORD) DIPROP_DEADZONE: {
1187 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
1188 int obj = find_property(This->base.data_format.user_df, pdiph);
1190 pd->dwData = This->props[obj].lDeadZone;
1191 TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj);
1196 case (DWORD) DIPROP_SATURATION: {
1197 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
1198 int obj = find_property(This->base.data_format.user_df, pdiph);
1200 pd->dwData = This->props[obj].lSaturation;
1201 TRACE("saturation(%d) obj=%d\n", pd->dwData, obj);
1207 return IDirectInputDevice2AImpl_GetProperty(iface, rguid, pdiph);
1214 /******************************************************************************
1215 * GetObjectInfo : get object info
1217 static HRESULT WINAPI JoystickAImpl_GetObjectInfo(
1218 LPDIRECTINPUTDEVICE8A iface,
1219 LPDIDEVICEOBJECTINSTANCEA pdidoi,
1223 JoystickImpl *This = (JoystickImpl *)iface;
1224 DIDEVICEOBJECTINSTANCEA didoiA;
1227 TRACE("(%p,%p,%d,0x%08x(%s))\n",
1228 iface, pdidoi, dwObj, dwHow,
1229 dwHow == DIPH_BYOFFSET ? "DIPH_BYOFFSET" :
1230 dwHow == DIPH_BYID ? "DIPH_BYID" :
1231 dwHow == DIPH_BYUSAGE ? "DIPH_BYUSAGE" :
1234 if (pdidoi == NULL) {
1235 WARN("invalid parameter: pdidoi = NULL\n");
1236 return DIERR_INVALIDPARAM;
1239 if ((pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEA)) &&
1240 (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3A))) {
1241 WARN("invalid parameter: pdidoi->dwSize = %d != %d or %d\n",
1242 pdidoi->dwSize, sizeof(DIDEVICEOBJECTINSTANCEA),
1243 sizeof(DIDEVICEOBJECTINSTANCE_DX3A));
1244 return DIERR_INVALIDPARAM;
1247 ZeroMemory(&didoiA, sizeof(didoiA));
1248 didoiA.dwSize = pdidoi->dwSize;
1251 case DIPH_BYOFFSET: {
1255 for (i = 0; i < This->base.data_format.user_df->dwNumObjs; i++) {
1256 if (This->base.data_format.user_df->rgodf[i].dwOfs == dwObj) {
1257 if (This->base.data_format.user_df->rgodf[i].pguid)
1258 didoiA.guidType = *This->base.data_format.user_df->rgodf[i].pguid;
1260 didoiA.guidType = GUID_NULL;
1262 didoiA.dwOfs = dwObj;
1263 didoiA.dwType = This->base.data_format.user_df->rgodf[i].dwType;
1264 didoiA.dwFlags = This->base.data_format.user_df->rgodf[i].dwFlags;
1266 if (DIDFT_GETTYPE(This->base.data_format.user_df->rgodf[i].dwType) & DIDFT_AXIS)
1267 sprintf(didoiA.tszName, "Axis %d", axis);
1268 else if (DIDFT_GETTYPE(This->base.data_format.user_df->rgodf[i].dwType) & DIDFT_POV)
1269 sprintf(didoiA.tszName, "POV %d", pov);
1270 else if (DIDFT_GETTYPE(This->base.data_format.user_df->rgodf[i].dwType) & DIDFT_BUTTON)
1271 sprintf(didoiA.tszName, "Button %d", button);
1273 CopyMemory(pdidoi, &didoiA, pdidoi->dwSize);
1277 if (DIDFT_GETTYPE(This->base.data_format.user_df->rgodf[i].dwType) & DIDFT_AXIS)
1279 else if (DIDFT_GETTYPE(This->base.data_format.user_df->rgodf[i].dwType) & DIDFT_POV)
1281 else if (DIDFT_GETTYPE(This->base.data_format.user_df->rgodf[i].dwType) & DIDFT_BUTTON)
1287 FIXME("dwHow = DIPH_BYID not implemented\n");
1290 FIXME("dwHow = DIPH_BYUSAGE not implemented\n");
1293 WARN("invalid parameter: dwHow = %08x\n", dwHow);
1294 return DIERR_INVALIDPARAM;
1297 CopyMemory(pdidoi, &didoiA, pdidoi->dwSize);
1302 /******************************************************************************
1303 * GetDeviceInfo : get information about a device's identity
1305 static HRESULT WINAPI JoystickAImpl_GetDeviceInfo(
1306 LPDIRECTINPUTDEVICE8A iface,
1307 LPDIDEVICEINSTANCEA pdidi)
1309 JoystickImpl *This = (JoystickImpl *)iface;
1311 TRACE("(%p,%p)\n", iface, pdidi);
1313 if (pdidi == NULL) {
1314 WARN("invalid pointer\n");
1318 if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) &&
1319 (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA))) {
1320 WARN("invalid parameter: pdidi->dwSize = %d != %d or %d\n",
1321 pdidi->dwSize, sizeof(DIDEVICEINSTANCE_DX3A),
1322 sizeof(DIDEVICEINSTANCEA));
1323 return DIERR_INVALIDPARAM;
1326 /* Return joystick */
1327 pdidi->guidInstance = GUID_Joystick;
1328 pdidi->guidProduct = DInput_Wine_Joystick_GUID;
1329 /* we only support traditional joysticks for now */
1330 pdidi->dwDevType = This->devcaps.dwDevType;
1331 strcpy(pdidi->tszInstanceName, "Joystick");
1332 strcpy(pdidi->tszProductName, This->name);
1333 if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3A)) {
1334 pdidi->guidFFDriver = GUID_NULL;
1335 pdidi->wUsagePage = 0;
1342 /******************************************************************************
1343 * GetDeviceInfo : get information about a device's identity
1345 static HRESULT WINAPI JoystickWImpl_GetDeviceInfo(
1346 LPDIRECTINPUTDEVICE8W iface,
1347 LPDIDEVICEINSTANCEW pdidi)
1349 JoystickImpl *This = (JoystickImpl *)iface;
1351 TRACE("(%p,%p)\n", iface, pdidi);
1353 if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) &&
1354 (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW))) {
1355 WARN("invalid parameter: pdidi->dwSize = %d != %d or %d\n",
1356 pdidi->dwSize, sizeof(DIDEVICEINSTANCE_DX3W),
1357 sizeof(DIDEVICEINSTANCEW));
1358 return DIERR_INVALIDPARAM;
1361 /* Return joystick */
1362 pdidi->guidInstance = GUID_Joystick;
1363 pdidi->guidProduct = DInput_Wine_Joystick_GUID;
1364 /* we only support traditional joysticks for now */
1365 pdidi->dwDevType = This->devcaps.dwDevType;
1366 MultiByteToWideChar(CP_ACP, 0, "Joystick", -1, pdidi->tszInstanceName, MAX_PATH);
1367 MultiByteToWideChar(CP_ACP, 0, This->name, -1, pdidi->tszProductName, MAX_PATH);
1368 if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3W)) {
1369 pdidi->guidFFDriver = GUID_NULL;
1370 pdidi->wUsagePage = 0;
1377 static const IDirectInputDevice8AVtbl JoystickAvt =
1379 IDirectInputDevice2AImpl_QueryInterface,
1380 IDirectInputDevice2AImpl_AddRef,
1381 JoystickAImpl_Release,
1382 JoystickAImpl_GetCapabilities,
1383 JoystickAImpl_EnumObjects,
1384 JoystickAImpl_GetProperty,
1385 JoystickAImpl_SetProperty,
1386 JoystickAImpl_Acquire,
1387 JoystickAImpl_Unacquire,
1388 JoystickAImpl_GetDeviceState,
1389 IDirectInputDevice2AImpl_GetDeviceData,
1390 JoystickAImpl_SetDataFormat,
1391 IDirectInputDevice2AImpl_SetEventNotification,
1392 IDirectInputDevice2AImpl_SetCooperativeLevel,
1393 JoystickAImpl_GetObjectInfo,
1394 JoystickAImpl_GetDeviceInfo,
1395 IDirectInputDevice2AImpl_RunControlPanel,
1396 IDirectInputDevice2AImpl_Initialize,
1397 IDirectInputDevice2AImpl_CreateEffect,
1398 IDirectInputDevice2AImpl_EnumEffects,
1399 IDirectInputDevice2AImpl_GetEffectInfo,
1400 IDirectInputDevice2AImpl_GetForceFeedbackState,
1401 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1402 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1403 IDirectInputDevice2AImpl_Escape,
1405 IDirectInputDevice2AImpl_SendDeviceData,
1406 IDirectInputDevice7AImpl_EnumEffectsInFile,
1407 IDirectInputDevice7AImpl_WriteEffectToFile,
1408 IDirectInputDevice8AImpl_BuildActionMap,
1409 IDirectInputDevice8AImpl_SetActionMap,
1410 IDirectInputDevice8AImpl_GetImageInfo
1413 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
1414 # define XCAST(fun) (typeof(SysJoystickWvt.fun))
1416 # define XCAST(fun) (void*)
1419 static const IDirectInputDevice8WVtbl SysJoystickWvt =
1421 IDirectInputDevice2WImpl_QueryInterface,
1422 XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
1423 XCAST(Release)JoystickAImpl_Release,
1424 XCAST(GetCapabilities)JoystickAImpl_GetCapabilities,
1425 JoystickWImpl_EnumObjects,
1426 XCAST(GetProperty)JoystickAImpl_GetProperty,
1427 XCAST(SetProperty)JoystickAImpl_SetProperty,
1428 XCAST(Acquire)JoystickAImpl_Acquire,
1429 XCAST(Unacquire)JoystickAImpl_Unacquire,
1430 XCAST(GetDeviceState)JoystickAImpl_GetDeviceState,
1431 XCAST(GetDeviceData)IDirectInputDevice2AImpl_GetDeviceData,
1432 XCAST(SetDataFormat)JoystickAImpl_SetDataFormat,
1433 XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification,
1434 XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
1435 IDirectInputDevice2WImpl_GetObjectInfo,
1436 JoystickWImpl_GetDeviceInfo,
1437 XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
1438 XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
1439 XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
1440 IDirectInputDevice2WImpl_EnumEffects,
1441 IDirectInputDevice2WImpl_GetEffectInfo,
1442 XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
1443 XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1444 XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1445 XCAST(Escape)IDirectInputDevice2AImpl_Escape,
1446 XCAST(Poll)JoystickAImpl_Poll,
1447 XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
1448 IDirectInputDevice7WImpl_EnumEffectsInFile,
1449 IDirectInputDevice7WImpl_WriteEffectToFile,
1450 IDirectInputDevice8WImpl_BuildActionMap,
1451 IDirectInputDevice8WImpl_SetActionMap,
1452 IDirectInputDevice8WImpl_GetImageInfo
1456 #else /* HAVE_LINUX_22_JOYSTICK_API */
1458 const struct dinput_device joystick_linux_device = {
1459 "Wine Linux joystick driver",
1466 #endif /* HAVE_LINUX_22_JOYSTICK_API */