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>
57 #include "wine/debug.h"
58 #include "wine/unicode.h"
65 #include "dinput_private.h"
66 #include "device_private.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(dinput
);
70 #ifdef HAVE_LINUX_22_JOYSTICK_API
72 #define JOYDEV_NEW "/dev/input/js"
73 #define JOYDEV_OLD "/dev/js"
87 typedef struct JoystickImpl JoystickImpl
;
88 static const IDirectInputDevice8AVtbl JoystickAvt
;
89 static const IDirectInputDevice8WVtbl JoystickWvt
;
97 /* The 'parent' DInput */
98 IDirectInputImpl
*dinput
;
100 /* joystick private */
102 DIJOYSTATE2 js
; /* wine data */
103 LPDIDATAFORMAT user_df
; /* user defined format */
104 DataFormat
*transform
; /* wine to user format converter */
105 int *offsets
; /* object offsets */
108 LPDIDEVICEOBJECTDATA data_queue
;
109 int queue_head
, queue_tail
, queue_len
;
118 CRITICAL_SECTION crit
;
122 static GUID DInput_Wine_Joystick_GUID
= { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */
126 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
129 static void _dump_DIDEVCAPS(LPDIDEVCAPS lpDIDevCaps
)
131 TRACE("dwSize: %ld\n", lpDIDevCaps
->dwSize
);
132 TRACE("dwFlags: %08lx\n",lpDIDevCaps
->dwFlags
);
133 TRACE("dwDevType: %08lx %s\n", lpDIDevCaps
->dwDevType
,
134 lpDIDevCaps
->dwDevType
== DIDEVTYPE_DEVICE
? "DIDEVTYPE_DEVICE" :
135 lpDIDevCaps
->dwDevType
== DIDEVTYPE_DEVICE
? "DIDEVTYPE_DEVICE" :
136 lpDIDevCaps
->dwDevType
== DIDEVTYPE_MOUSE
? "DIDEVTYPE_MOUSE" :
137 lpDIDevCaps
->dwDevType
== DIDEVTYPE_KEYBOARD
? "DIDEVTYPE_KEYBOARD" :
138 lpDIDevCaps
->dwDevType
== DIDEVTYPE_JOYSTICK
? "DIDEVTYPE_JOYSTICK" :
139 lpDIDevCaps
->dwDevType
== DIDEVTYPE_HID
? "DIDEVTYPE_HID" : "UNKNOWN");
140 TRACE("dwAxes: %ld\n",lpDIDevCaps
->dwAxes
);
141 TRACE("dwButtons: %ld\n",lpDIDevCaps
->dwButtons
);
142 TRACE("dwPOVs: %ld\n",lpDIDevCaps
->dwPOVs
);
143 if (lpDIDevCaps
->dwSize
> sizeof(DIDEVCAPS_DX3
)) {
144 TRACE("dwFFSamplePeriod: %ld\n",lpDIDevCaps
->dwFFSamplePeriod
);
145 TRACE("dwFFMinTimeResolution: %ld\n",lpDIDevCaps
->dwFFMinTimeResolution
);
146 TRACE("dwFirmwareRevision: %ld\n",lpDIDevCaps
->dwFirmwareRevision
);
147 TRACE("dwHardwareRevision: %ld\n",lpDIDevCaps
->dwHardwareRevision
);
148 TRACE("dwFFDriverVersion: %ld\n",lpDIDevCaps
->dwFFDriverVersion
);
152 static int joydev_get_device(char *dev
, int id
)
155 sprintf(dev
, "%s%d", JOYDEV_NEW
, id
);
156 if ((ret
= open(dev
, O_RDONLY
)) < 0) {
157 sprintf(dev
, "%s%d", JOYDEV_OLD
, id
);
158 if ((ret
= open(dev
, O_RDONLY
)) < 0) {
165 static BOOL
joydev_enum_deviceA(DWORD dwDevType
, DWORD dwFlags
, LPDIDEVICEINSTANCEA lpddi
, DWORD version
, int id
)
170 if (dwFlags
& DIEDFL_FORCEFEEDBACK
) {
171 WARN("force feedback not supported\n");
175 if ((dwDevType
== 0) ||
176 ((dwDevType
== DIDEVTYPE_JOYSTICK
) && (version
> 0x0300 && version
< 0x0800)) ||
177 (((dwDevType
== DI8DEVCLASS_GAMECTRL
) || (dwDevType
== DI8DEVTYPE_JOYSTICK
)) && (version
>= 0x0800))) {
178 /* check whether we have a joystick */
179 if ((fd
= joydev_get_device(dev
, id
)) < 0) {
180 WARN("open(%s,O_RDONLY) failed: %s\n", dev
, strerror(errno
));
184 /* Return joystick */
185 lpddi
->guidInstance
= DInput_Wine_Joystick_GUID
;
186 lpddi
->guidInstance
.Data3
= id
;
187 lpddi
->guidProduct
= DInput_Wine_Joystick_GUID
;
188 /* we only support traditional joysticks for now */
189 if (version
>= 0x0800)
190 lpddi
->dwDevType
= DI8DEVTYPE_JOYSTICK
| (DI8DEVTYPEJOYSTICK_STANDARD
<< 8);
192 lpddi
->dwDevType
= DIDEVTYPE_JOYSTICK
| (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
193 sprintf(lpddi
->tszInstanceName
, "Joystick %d", id
);
194 #if defined(JSIOCGNAME)
195 if (ioctl(fd
,JSIOCGNAME(sizeof(lpddi
->tszProductName
)),lpddi
->tszProductName
) < 0) {
196 WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev
, strerror(errno
));
197 strcpy(lpddi
->tszProductName
, "Wine Joystick");
200 strcpy(lpddi
->tszProductName
, "Wine Joystick");
203 lpddi
->guidFFDriver
= GUID_NULL
;
205 TRACE("Enumerating the linux Joystick device: %s (%s)\n", dev
, lpddi
->tszProductName
);
212 static BOOL
joydev_enum_deviceW(DWORD dwDevType
, DWORD dwFlags
, LPDIDEVICEINSTANCEW lpddi
, DWORD version
, int id
)
219 if (dwFlags
& DIEDFL_FORCEFEEDBACK
) {
220 WARN("force feedback not supported\n");
224 if ((dwDevType
== 0) ||
225 ((dwDevType
== DIDEVTYPE_JOYSTICK
) && (version
> 0x0300 && version
< 0x0800)) ||
226 (((dwDevType
== DI8DEVCLASS_GAMECTRL
) || (dwDevType
== DI8DEVTYPE_JOYSTICK
)) && (version
>= 0x0800))) {
227 /* check whether we have a joystick */
228 if ((fd
= joydev_get_device(dev
, id
)) < 0) {
229 WARN("open(%s,O_RDONLY) failed: %s\n", dev
, strerror(errno
));
233 /* Return joystick */
234 lpddi
->guidInstance
= DInput_Wine_Joystick_GUID
;
235 lpddi
->guidInstance
.Data3
= id
;
236 lpddi
->guidProduct
= DInput_Wine_Joystick_GUID
;
237 /* we only support traditional joysticks for now */
238 if (version
>= 0x0800)
239 lpddi
->dwDevType
= DI8DEVTYPE_JOYSTICK
| (DI8DEVTYPEJOYSTICK_STANDARD
<< 8);
241 lpddi
->dwDevType
= DIDEVTYPE_JOYSTICK
| (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
242 sprintf(friendly
, "Joystick %d", id
);
243 MultiByteToWideChar(CP_ACP
, 0, friendly
, -1, lpddi
->tszInstanceName
, MAX_PATH
);
244 #if defined(JSIOCGNAME)
245 if (ioctl(fd
,JSIOCGNAME(sizeof(name
)),name
) < 0) {
246 WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev
, strerror(errno
));
247 strcpy(name
, "Wine Joystick");
250 strcpy(name
, "Wine Joystick");
252 MultiByteToWideChar(CP_ACP
, 0, name
, -1, lpddi
->tszProductName
, MAX_PATH
);
253 lpddi
->guidFFDriver
= GUID_NULL
;
255 TRACE("Enumerating the linux Joystick device: %s (%s)\n",dev
,name
);
263 * Get a config key from either the app-specific or the default config
266 inline static DWORD
get_config_key( HKEY defkey
, HKEY appkey
, const char *name
,
267 char *buffer
, DWORD size
)
269 if (appkey
&& !RegQueryValueExA( appkey
, name
, 0, NULL
, (LPBYTE
)buffer
, &size
))
272 if (defkey
&& !RegQueryValueExA( defkey
, name
, 0, NULL
, (LPBYTE
)buffer
, &size
))
275 return ERROR_FILE_NOT_FOUND
;
279 * Setup the dinput options.
282 static HRESULT
setup_dinput_options(JoystickImpl
* device
)
284 char buffer
[MAX_PATH
+16];
285 HKEY hkey
, appkey
= 0;
288 buffer
[MAX_PATH
]='\0';
290 /* @@ Wine registry key: HKCU\Software\Wine\DirectInput */
291 if (RegOpenKeyA( HKEY_CURRENT_USER
, "Software\\Wine\\DirectInput", &hkey
)) hkey
= 0;
293 len
= GetModuleFileNameA( 0, buffer
, MAX_PATH
);
294 if (len
&& len
< MAX_PATH
) {
296 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectInput */
297 if (!RegOpenKeyA( HKEY_CURRENT_USER
, "Software\\Wine\\AppDefaults", &tmpkey
))
299 char *p
, *appname
= buffer
;
300 if ((p
= strrchr( appname
, '/' ))) appname
= p
+ 1;
301 if ((p
= strrchr( appname
, '\\' ))) appname
= p
+ 1;
302 strcat( appname
, "\\DirectInput" );
303 if (RegOpenKeyA( tmpkey
, appname
, &appkey
)) appkey
= 0;
304 RegCloseKey( tmpkey
);
310 if (!get_config_key( hkey
, appkey
, "DefaultDeadZone", buffer
, MAX_PATH
)) {
311 device
->deadzone
= atoi(buffer
);
312 TRACE("setting default deadzone to: \"%s\" %ld\n", buffer
, device
->deadzone
);
315 if (!get_config_key( hkey
, appkey
, device
->name
, buffer
, MAX_PATH
)) {
319 const char *delim
= ",";
321 TRACE("\"%s\" = \"%s\"\n", device
->name
, buffer
);
323 device
->axis_map
= HeapAlloc(GetProcessHeap(), 0, device
->axes
* sizeof(int));
324 if (device
->axis_map
== 0)
325 return DIERR_OUTOFMEMORY
;
327 if ((ptr
= strtok(buffer
, delim
)) != NULL
) {
329 if (strcmp(ptr
, "X") == 0) {
330 device
->axis_map
[tokens
] = 0;
332 } else if (strcmp(ptr
, "Y") == 0) {
333 device
->axis_map
[tokens
] = 1;
335 } else if (strcmp(ptr
, "Z") == 0) {
336 device
->axis_map
[tokens
] = 2;
338 } else if (strcmp(ptr
, "Rx") == 0) {
339 device
->axis_map
[tokens
] = 3;
341 } else if (strcmp(ptr
, "Ry") == 0) {
342 device
->axis_map
[tokens
] = 4;
344 } else if (strcmp(ptr
, "Rz") == 0) {
345 device
->axis_map
[tokens
] = 5;
347 } else if (strcmp(ptr
, "Slider1") == 0) {
348 device
->axis_map
[tokens
] = 6;
350 } else if (strcmp(ptr
, "Slider2") == 0) {
351 device
->axis_map
[tokens
] = 7;
353 } else if (strcmp(ptr
, "POV1") == 0) {
354 device
->axis_map
[tokens
++] = 8;
355 device
->axis_map
[tokens
] = 8;
357 } else if (strcmp(ptr
, "POV2") == 0) {
358 device
->axis_map
[tokens
++] = 9;
359 device
->axis_map
[tokens
] = 9;
361 } else if (strcmp(ptr
, "POV3") == 0) {
362 device
->axis_map
[tokens
++] = 10;
363 device
->axis_map
[tokens
] = 10;
365 } else if (strcmp(ptr
, "POV4") == 0) {
366 device
->axis_map
[tokens
++] = 11;
367 device
->axis_map
[tokens
] = 11;
370 ERR("invalid joystick axis type: %s\n", ptr
);
371 device
->axis_map
[tokens
] = tokens
;
376 } while ((ptr
= strtok(NULL
, delim
)) != NULL
);
378 if (tokens
!= device
->devcaps
.dwAxes
) {
379 ERR("not all joystick axes mapped: %d axes(%d,%d), %d arguments\n", device
->axes
, axis
, pov
,tokens
);
380 while (tokens
< device
->axes
) {
381 device
->axis_map
[tokens
] = tokens
;
387 device
->devcaps
.dwAxes
= axis
;
388 device
->devcaps
.dwPOVs
= pov
;
392 RegCloseKey( appkey
);
400 static void calculate_ids(JoystickImpl
* device
)
410 /* Make two passes over the format. The first counts the number
411 * for each type and the second sets the id */
412 for (i
= 0; i
< device
->user_df
->dwNumObjs
; i
++) {
413 if (DIDFT_GETTYPE(device
->user_df
->rgodf
[i
].dwType
) & DIDFT_AXIS
)
415 else if (DIDFT_GETTYPE(device
->user_df
->rgodf
[i
].dwType
) & DIDFT_POV
)
417 else if (DIDFT_GETTYPE(device
->user_df
->rgodf
[i
].dwType
) & DIDFT_BUTTON
)
423 button_base
= axis
+ pov
;
429 for (i
= 0; i
< device
->user_df
->dwNumObjs
; i
++) {
431 if (DIDFT_GETTYPE(device
->user_df
->rgodf
[i
].dwType
) & DIDFT_AXIS
) {
433 type
= DIDFT_GETTYPE(device
->user_df
->rgodf
[i
].dwType
) |
434 DIDFT_MAKEINSTANCE(axis
+ axis_base
);
435 TRACE("axis type = 0x%08lx\n", type
);
436 } else if (DIDFT_GETTYPE(device
->user_df
->rgodf
[i
].dwType
) & DIDFT_POV
) {
438 type
= DIDFT_GETTYPE(device
->user_df
->rgodf
[i
].dwType
) |
439 DIDFT_MAKEINSTANCE(pov
+ pov_base
);
440 TRACE("POV type = 0x%08lx\n", type
);
441 } else if (DIDFT_GETTYPE(device
->user_df
->rgodf
[i
].dwType
) & DIDFT_BUTTON
) {
443 type
= DIDFT_GETTYPE(device
->user_df
->rgodf
[i
].dwType
) |
444 DIDFT_MAKEINSTANCE(button
+ button_base
);
445 TRACE("button type = 0x%08lx\n", type
);
447 device
->user_df
->rgodf
[i
].dwType
= type
;
451 static HRESULT
alloc_device(REFGUID rguid
, const void *jvt
, IDirectInputImpl
*dinput
, LPDIRECTINPUTDEVICEA
* pdev
)
454 JoystickImpl
* newDevice
;
458 newDevice
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(JoystickImpl
));
459 if (newDevice
== 0) {
460 WARN("out of memory\n");
462 return DIERR_OUTOFMEMORY
;
465 if ((newDevice
->joyfd
= joydev_get_device(newDevice
->dev
, rguid
->Data3
)) < 0) {
466 WARN("open(%s,O_RDONLY) failed: %s\n", newDevice
->dev
, strerror(errno
));
467 HeapFree(GetProcessHeap(), 0, newDevice
);
468 return DIERR_DEVICENOTREG
;
471 /* get the device name */
472 #if defined(JSIOCGNAME)
473 if (ioctl(newDevice
->joyfd
,JSIOCGNAME(MAX_PATH
),name
) < 0) {
474 WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", newDevice
->dev
, strerror(errno
));
475 strcpy(name
, "Wine Joystick");
478 strcpy(name
, "Wine Joystick");
481 /* copy the device name */
482 newDevice
->name
= HeapAlloc(GetProcessHeap(),0,strlen(name
) + 1);
483 strcpy(newDevice
->name
, name
);
486 if (ioctl(newDevice
->joyfd
,JSIOCGAXES
,&newDevice
->axes
) < 0) {
487 WARN("ioctl(%s,JSIOCGAXES) failed: %s, defauting to 2\n", newDevice
->dev
, strerror(errno
));
492 if (ioctl(newDevice
->joyfd
,JSIOCGBUTTONS
,&newDevice
->buttons
) < 0) {
493 WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defauting to 2\n", newDevice
->dev
, strerror(errno
));
494 newDevice
->buttons
= 2;
498 newDevice
->lpVtbl
= jvt
;
500 newDevice
->dinput
= dinput
;
501 newDevice
->acquired
= FALSE
;
502 newDevice
->overflow
= FALSE
;
503 CopyMemory(&(newDevice
->guid
),rguid
,sizeof(*rguid
));
505 /* setup_dinput_options may change these */
506 newDevice
->deadzone
= 5000;
507 newDevice
->devcaps
.dwButtons
= newDevice
->buttons
;
508 newDevice
->devcaps
.dwAxes
= newDevice
->axes
;
509 newDevice
->devcaps
.dwPOVs
= 0;
511 /* do any user specified configuration */
512 hr
= setup_dinput_options(newDevice
);
516 if (newDevice
->axis_map
== 0) {
517 newDevice
->axis_map
= HeapAlloc(GetProcessHeap(), 0, newDevice
->axes
* sizeof(int));
518 if (newDevice
->axis_map
== 0)
521 for (i
= 0; i
< newDevice
->axes
; i
++)
522 newDevice
->axis_map
[i
] = i
;
525 /* wine uses DIJOYSTATE2 as it's internal format so copy
526 * the already defined format c_dfDIJoystick2 */
527 newDevice
->user_df
= HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2
.dwSize
);
528 if (newDevice
->user_df
== 0)
531 CopyMemory(newDevice
->user_df
, &c_dfDIJoystick2
, c_dfDIJoystick2
.dwSize
);
533 /* copy default objects */
534 newDevice
->user_df
->rgodf
= HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2
.dwNumObjs
*c_dfDIJoystick2
.dwObjSize
);
535 if (newDevice
->user_df
->rgodf
== 0)
538 CopyMemory(newDevice
->user_df
->rgodf
,c_dfDIJoystick2
.rgodf
,c_dfDIJoystick2
.dwNumObjs
*c_dfDIJoystick2
.dwObjSize
);
540 /* create default properties */
541 newDevice
->props
= HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2
.dwNumObjs
*sizeof(ObjProps
));
542 if (newDevice
->props
== 0)
545 /* initialize default properties */
546 for (i
= 0; i
< c_dfDIJoystick2
.dwNumObjs
; i
++) {
547 newDevice
->props
[i
].lMin
= 0;
548 newDevice
->props
[i
].lMax
= 0xffff;
549 newDevice
->props
[i
].lDeadZone
= newDevice
->deadzone
; /* % * 1000 */
550 newDevice
->props
[i
].lSaturation
= 0;
553 /* create an offsets array */
554 newDevice
->offsets
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,c_dfDIJoystick2
.dwNumObjs
*sizeof(int));
555 if (newDevice
->offsets
== 0)
558 /* create the default transform filter */
559 newDevice
->transform
= create_DataFormat(&c_dfDIJoystick2
, newDevice
->user_df
, newDevice
->offsets
);
561 calculate_ids(newDevice
);
563 IDirectInputDevice_AddRef((LPDIRECTINPUTDEVICE8A
)newDevice
->dinput
);
564 InitializeCriticalSection(&(newDevice
->crit
));
565 newDevice
->crit
.DebugInfo
->Spare
[0] = (DWORD_PTR
)"DINPUT_Mouse";
567 newDevice
->devcaps
.dwSize
= sizeof(newDevice
->devcaps
);
568 newDevice
->devcaps
.dwFlags
= DIDC_ATTACHED
;
569 if (newDevice
->dinput
->dwVersion
>= 0x0800)
570 newDevice
->devcaps
.dwDevType
= DI8DEVTYPE_JOYSTICK
| (DI8DEVTYPEJOYSTICK_STANDARD
<< 8);
572 newDevice
->devcaps
.dwDevType
= DIDEVTYPE_JOYSTICK
| (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
573 newDevice
->devcaps
.dwFFSamplePeriod
= 0;
574 newDevice
->devcaps
.dwFFMinTimeResolution
= 0;
575 newDevice
->devcaps
.dwFirmwareRevision
= 0;
576 newDevice
->devcaps
.dwHardwareRevision
= 0;
577 newDevice
->devcaps
.dwFFDriverVersion
= 0;
579 if (TRACE_ON(dinput
)) {
580 _dump_DIDATAFORMAT(newDevice
->user_df
);
581 for (i
= 0; i
< (newDevice
->axes
); i
++)
582 TRACE("axis_map[%ld] = %d\n", i
, newDevice
->axis_map
[i
]);
583 _dump_DIDEVCAPS(&newDevice
->devcaps
);
586 *pdev
= (LPDIRECTINPUTDEVICEA
)newDevice
;
591 hr
= DIERR_OUTOFMEMORY
;
593 HeapFree(GetProcessHeap(),0,newDevice
->axis_map
);
594 HeapFree(GetProcessHeap(),0,newDevice
->name
);
595 HeapFree(GetProcessHeap(),0,newDevice
->props
);
596 HeapFree(GetProcessHeap(),0,newDevice
->user_df
->rgodf
);
597 HeapFree(GetProcessHeap(),0,newDevice
->user_df
);
598 HeapFree(GetProcessHeap(),0,newDevice
);
604 static BOOL
IsJoystickGUID(REFGUID guid
)
606 GUID wine_joystick
= DInput_Wine_Joystick_GUID
;
607 GUID dev_guid
= *guid
;
609 wine_joystick
.Data3
= 0;
612 return IsEqualGUID(&wine_joystick
, &dev_guid
);
615 static HRESULT
joydev_create_deviceA(IDirectInputImpl
*dinput
, REFGUID rguid
, REFIID riid
, LPDIRECTINPUTDEVICEA
* pdev
)
617 if ((IsEqualGUID(&GUID_Joystick
,rguid
)) ||
618 (IsJoystickGUID(rguid
))) {
619 if ((riid
== NULL
) ||
620 IsEqualGUID(&IID_IDirectInputDeviceA
,riid
) ||
621 IsEqualGUID(&IID_IDirectInputDevice2A
,riid
) ||
622 IsEqualGUID(&IID_IDirectInputDevice7A
,riid
) ||
623 IsEqualGUID(&IID_IDirectInputDevice8A
,riid
)) {
624 return alloc_device(rguid
, &JoystickAvt
, dinput
, pdev
);
626 WARN("no interface\n");
628 return DIERR_NOINTERFACE
;
632 WARN("invalid device GUID\n");
634 return DIERR_DEVICENOTREG
;
637 static HRESULT
joydev_create_deviceW(IDirectInputImpl
*dinput
, REFGUID rguid
, REFIID riid
, LPDIRECTINPUTDEVICEW
* pdev
)
639 if ((IsEqualGUID(&GUID_Joystick
,rguid
)) ||
640 (IsJoystickGUID(rguid
))) {
641 if ((riid
== NULL
) ||
642 IsEqualGUID(&IID_IDirectInputDeviceW
,riid
) ||
643 IsEqualGUID(&IID_IDirectInputDevice2W
,riid
) ||
644 IsEqualGUID(&IID_IDirectInputDevice7W
,riid
) ||
645 IsEqualGUID(&IID_IDirectInputDevice8W
,riid
)) {
646 return alloc_device(rguid
, &JoystickWvt
, dinput
, (LPDIRECTINPUTDEVICEA
*)pdev
);
648 WARN("no interface\n");
650 return DIERR_NOINTERFACE
;
654 WARN("invalid device GUID\n");
656 return DIERR_DEVICENOTREG
;
659 const struct dinput_device joystick_linux_device
= {
660 "Wine Linux joystick driver",
663 joydev_create_deviceA
,
664 joydev_create_deviceW
667 /******************************************************************************
670 static ULONG WINAPI
JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface
)
672 JoystickImpl
*This
= (JoystickImpl
*)iface
;
675 ref
= InterlockedDecrement((&This
->ref
));
679 /* Free the device name */
680 HeapFree(GetProcessHeap(),0,This
->name
);
682 /* Free the axis map */
683 HeapFree(GetProcessHeap(),0,This
->axis_map
);
685 /* Free the data queue */
686 HeapFree(GetProcessHeap(),0,This
->data_queue
);
688 /* Free the DataFormat */
689 HeapFree(GetProcessHeap(), 0, This
->user_df
->rgodf
);
690 HeapFree(GetProcessHeap(), 0, This
->user_df
);
692 /* Free the properties */
693 HeapFree(GetProcessHeap(), 0, This
->props
);
695 /* Free the offsets array */
696 HeapFree(GetProcessHeap(),0,This
->offsets
);
698 /* release the data transform filter */
699 release_DataFormat(This
->transform
);
701 This
->crit
.DebugInfo
->Spare
[0] = 0;
702 DeleteCriticalSection(&(This
->crit
));
703 IDirectInputDevice_Release((LPDIRECTINPUTDEVICE8A
)This
->dinput
);
705 HeapFree(GetProcessHeap(),0,This
);
709 /******************************************************************************
710 * SetDataFormat : the application can choose the format of the data
711 * the device driver sends back with GetDeviceState.
713 static HRESULT WINAPI
JoystickAImpl_SetDataFormat(
714 LPDIRECTINPUTDEVICE8A iface
,
717 JoystickImpl
*This
= (JoystickImpl
*)iface
;
719 LPDIDATAFORMAT new_df
= 0;
720 LPDIOBJECTDATAFORMAT new_rgodf
= 0;
721 ObjProps
* new_props
= 0;
723 TRACE("(%p,%p)\n",This
,df
);
726 WARN("invalid pointer\n");
730 if (df
->dwSize
!= sizeof(*df
)) {
731 WARN("invalid argument\n");
732 return DIERR_INVALIDPARAM
;
735 if (This
->acquired
) {
737 return DIERR_ACQUIRED
;
740 if (TRACE_ON(dinput
))
741 _dump_DIDATAFORMAT(df
);
743 /* Store the new data format */
744 new_df
= HeapAlloc(GetProcessHeap(),0,df
->dwSize
);
748 new_rgodf
= HeapAlloc(GetProcessHeap(),0,df
->dwNumObjs
*df
->dwObjSize
);
752 new_props
= HeapAlloc(GetProcessHeap(),0,df
->dwNumObjs
*sizeof(ObjProps
));
756 HeapFree(GetProcessHeap(),0,This
->user_df
);
757 HeapFree(GetProcessHeap(),0,This
->user_df
->rgodf
);
758 HeapFree(GetProcessHeap(),0,This
->props
);
759 release_DataFormat(This
->transform
);
761 This
->user_df
= new_df
;
762 CopyMemory(This
->user_df
, df
, df
->dwSize
);
763 This
->user_df
->rgodf
= new_rgodf
;
764 CopyMemory(This
->user_df
->rgodf
,df
->rgodf
,df
->dwNumObjs
*df
->dwObjSize
);
765 This
->props
= new_props
;
766 for (i
= 0; i
< df
->dwNumObjs
; i
++) {
767 This
->props
[i
].lMin
= 0;
768 This
->props
[i
].lMax
= 0xffff;
769 This
->props
[i
].lDeadZone
= 1000;
770 This
->props
[i
].lSaturation
= 0;
772 This
->transform
= create_DataFormat(&c_dfDIJoystick2
, This
->user_df
, This
->offsets
);
779 WARN("out of memory\n");
780 HeapFree(GetProcessHeap(),0,new_props
);
781 HeapFree(GetProcessHeap(),0,new_rgodf
);
782 HeapFree(GetProcessHeap(),0,new_df
);
783 return DIERR_OUTOFMEMORY
;
786 /******************************************************************************
787 * Acquire : gets exclusive control of the joystick
789 static HRESULT WINAPI
JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface
)
791 JoystickImpl
*This
= (JoystickImpl
*)iface
;
793 TRACE("(%p)\n",This
);
795 if (This
->acquired
) {
796 WARN("already acquired\n");
800 /* open the joystick device */
801 if (This
->joyfd
==-1) {
802 TRACE("opening joystick device %s\n", This
->dev
);
804 This
->joyfd
=open(This
->dev
,O_RDONLY
);
805 if (This
->joyfd
==-1) {
806 ERR("open(%s) failed: %s\n", This
->dev
, strerror(errno
));
807 return DIERR_NOTFOUND
;
811 This
->acquired
= TRUE
;
816 /******************************************************************************
817 * Unacquire : frees the joystick
819 static HRESULT WINAPI
JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface
)
821 JoystickImpl
*This
= (JoystickImpl
*)iface
;
823 TRACE("(%p)\n",This
);
825 if (!This
->acquired
) {
826 WARN("not acquired\n");
827 return DIERR_NOTACQUIRED
;
830 if (This
->joyfd
!=-1) {
831 TRACE("closing joystick device\n");
834 This
->acquired
= FALSE
;
838 This
->acquired
= FALSE
;
843 static LONG
map_axis(JoystickImpl
* This
, short val
, short index
)
846 double fmin
= This
->props
[index
].lMin
;
847 double fmax
= This
->props
[index
].lMax
;
850 fret
= (((fval
+ 32767.0) * (fmax
- fmin
)) / (32767.0*2.0)) + fmin
;
860 /* convert wine format offset to user format object index */
861 static int offset_to_object(JoystickImpl
*This
, int offset
)
865 for (i
= 0; i
< This
->user_df
->dwNumObjs
; i
++) {
866 if (This
->user_df
->rgodf
[i
].dwOfs
== offset
)
873 static LONG
calculate_pov(JoystickImpl
*This
, int index
)
875 if (This
->povs
[index
].lX
< -16384) {
876 if (This
->povs
[index
].lY
< -16384)
877 This
->js
.rgdwPOV
[index
] = 31500;
878 else if (This
->povs
[index
].lY
> 16384)
879 This
->js
.rgdwPOV
[index
] = 22500;
881 This
->js
.rgdwPOV
[index
] = 27000;
882 } else if (This
->povs
[index
].lX
> 16384) {
883 if (This
->povs
[index
].lY
< -16384)
884 This
->js
.rgdwPOV
[index
] = 4500;
885 else if (This
->povs
[index
].lY
> 16384)
886 This
->js
.rgdwPOV
[index
] = 13500;
888 This
->js
.rgdwPOV
[index
] = 9000;
890 if (This
->povs
[index
].lY
< -16384)
891 This
->js
.rgdwPOV
[index
] = 0;
892 else if (This
->povs
[index
].lY
> 16384)
893 This
->js
.rgdwPOV
[index
] = 18000;
895 This
->js
.rgdwPOV
[index
] = -1;
898 return This
->js
.rgdwPOV
[index
];
901 static void joy_polldev(JoystickImpl
*This
) {
905 TRACE("(%p)\n", This
);
907 if (This
->joyfd
==-1) {
912 memset(&tv
,0,sizeof(tv
));
913 FD_ZERO(&readfds
);FD_SET(This
->joyfd
,&readfds
);
914 if (1>select(This
->joyfd
+1,&readfds
,NULL
,NULL
,&tv
))
916 /* we have one event, so we can read */
917 if (sizeof(jse
)!=read(This
->joyfd
,&jse
,sizeof(jse
))) {
920 TRACE("js_event: type 0x%x, number %d, value %d\n",
921 jse
.type
,jse
.number
,jse
.value
);
922 if (jse
.type
& JS_EVENT_BUTTON
) {
923 int offset
= This
->offsets
[jse
.number
+ 12];
924 int value
= jse
.value
?0x80:0x00;
926 This
->js
.rgbButtons
[jse
.number
] = value
;
927 GEN_EVENT(offset
,value
,jse
.time
,(This
->dinput
->evsequence
)++);
928 } else if (jse
.type
& JS_EVENT_AXIS
) {
929 int number
= This
->axis_map
[jse
.number
]; /* wine format object index */
931 int offset
= This
->offsets
[number
];
932 int index
= offset_to_object(This
, offset
);
933 LONG value
= map_axis(This
, jse
.value
, index
);
935 /* FIXME do deadzone and saturation here */
937 TRACE("changing axis %d => %d\n", jse
.number
, number
);
949 This
->js
.lRx
= value
;
952 This
->js
.lRy
= value
;
955 This
->js
.lRz
= value
;
958 This
->js
.rglSlider
[0] = value
;
961 This
->js
.rglSlider
[1] = value
;
964 /* FIXME don't go off array */
965 if (This
->axis_map
[jse
.number
+ 1] == number
)
966 This
->povs
[0].lX
= jse
.value
;
967 else if (This
->axis_map
[jse
.number
- 1] == number
)
968 This
->povs
[0].lY
= jse
.value
;
969 value
= calculate_pov(This
, 0);
972 if (This
->axis_map
[jse
.number
+ 1] == number
)
973 This
->povs
[1].lX
= jse
.value
;
974 else if (This
->axis_map
[jse
.number
- 1] == number
)
975 This
->povs
[1].lY
= jse
.value
;
976 value
= calculate_pov(This
, 1);
979 if (This
->axis_map
[jse
.number
+ 1] == number
)
980 This
->povs
[2].lX
= jse
.value
;
981 else if (This
->axis_map
[jse
.number
- 1] == number
)
982 This
->povs
[2].lY
= jse
.value
;
983 value
= calculate_pov(This
, 2);
986 if (This
->axis_map
[jse
.number
+ 1] == number
)
987 This
->povs
[3].lX
= jse
.value
;
988 else if (This
->axis_map
[jse
.number
- 1] == number
)
989 This
->povs
[3].lY
= jse
.value
;
990 value
= calculate_pov(This
, 3);
994 GEN_EVENT(offset
,value
,jse
.time
,(This
->dinput
->evsequence
)++);
996 WARN("axis %d not supported\n", number
);
1001 /******************************************************************************
1002 * GetDeviceState : returns the "state" of the joystick.
1005 static HRESULT WINAPI
JoystickAImpl_GetDeviceState(
1006 LPDIRECTINPUTDEVICE8A iface
,
1010 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1012 TRACE("(%p,0x%08lx,%p)\n",This
,len
,ptr
);
1014 if (!This
->acquired
) {
1015 WARN("not acquired\n");
1016 return DIERR_NOTACQUIRED
;
1019 /* update joystick state */
1022 /* convert and copy data to user supplied buffer */
1023 fill_DataFormat(ptr
, &This
->js
, This
->transform
);
1028 /******************************************************************************
1029 * GetDeviceData : gets buffered input data.
1031 static HRESULT WINAPI
JoystickAImpl_GetDeviceData(
1032 LPDIRECTINPUTDEVICE8A iface
,
1034 LPDIDEVICEOBJECTDATA dod
,
1038 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1043 TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This
,dodsize
,*entries
,flags
);
1045 if (!This
->acquired
) {
1046 WARN("not acquired\n");
1047 return DIERR_NOTACQUIRED
;
1050 EnterCriticalSection(&(This
->crit
));
1054 len
= ((This
->queue_head
< This
->queue_tail
) ? This
->queue_len
: 0)
1055 + (This
->queue_head
- This
->queue_tail
);
1061 TRACE("Application discarding %ld event(s).\n", len
);
1064 nqtail
= This
->queue_tail
+ len
;
1065 while (nqtail
>= This
->queue_len
)
1066 nqtail
-= This
->queue_len
;
1068 if (dodsize
< sizeof(DIDEVICEOBJECTDATA_DX3
)) {
1069 ERR("Wrong structure size !\n");
1070 LeaveCriticalSection(&(This
->crit
));
1071 return DIERR_INVALIDPARAM
;
1075 TRACE("Application retrieving %ld event(s).\n", len
);
1078 nqtail
= This
->queue_tail
;
1080 /* Copy the buffered data into the application queue */
1081 memcpy((char *)dod
+ *entries
* dodsize
, This
->data_queue
+ nqtail
, dodsize
);
1082 /* Advance position */
1084 if (nqtail
>= This
->queue_len
)
1085 nqtail
-= This
->queue_len
;
1091 if (This
->overflow
) {
1092 hr
= DI_BUFFEROVERFLOW
;
1093 if (!(flags
& DIGDD_PEEK
)) {
1094 This
->overflow
= FALSE
;
1098 if (!(flags
& DIGDD_PEEK
))
1099 This
->queue_tail
= nqtail
;
1101 LeaveCriticalSection(&(This
->crit
));
1106 static int find_property(JoystickImpl
* This
, LPCDIPROPHEADER ph
)
1109 if (ph
->dwHow
== DIPH_BYOFFSET
) {
1110 return offset_to_object(This
, ph
->dwObj
);
1111 } else if (ph
->dwHow
== DIPH_BYID
) {
1112 for (i
= 0; i
< This
->user_df
->dwNumObjs
; i
++) {
1113 if ((This
->user_df
->rgodf
[i
].dwType
& 0x00ffffff) == (ph
->dwObj
& 0x00ffffff)) {
1122 /******************************************************************************
1123 * SetProperty : change input device properties
1125 static HRESULT WINAPI
JoystickAImpl_SetProperty(
1126 LPDIRECTINPUTDEVICE8A iface
,
1130 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1133 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(rguid
),ph
);
1136 WARN("invalid parameter: ph == NULL\n");
1137 return DIERR_INVALIDPARAM
;
1140 if (TRACE_ON(dinput
))
1141 _dump_DIPROPHEADER(ph
);
1143 if (!HIWORD(rguid
)) {
1144 switch (LOWORD(rguid
)) {
1145 case (DWORD
) DIPROP_BUFFERSIZE
: {
1146 LPCDIPROPDWORD pd
= (LPCDIPROPDWORD
)ph
;
1147 TRACE("buffersize = %ld\n",pd
->dwData
);
1148 if (This
->data_queue
)
1149 This
->data_queue
= HeapReAlloc(GetProcessHeap(),0, This
->data_queue
, pd
->dwData
* sizeof(DIDEVICEOBJECTDATA
));
1151 This
->data_queue
= HeapAlloc(GetProcessHeap(),0, pd
->dwData
* sizeof(DIDEVICEOBJECTDATA
));
1152 This
->queue_head
= 0;
1153 This
->queue_tail
= 0;
1154 This
->queue_len
= pd
->dwData
;
1157 case (DWORD
)DIPROP_RANGE
: {
1158 LPCDIPROPRANGE pr
= (LPCDIPROPRANGE
)ph
;
1159 if (ph
->dwHow
== DIPH_DEVICE
) {
1160 TRACE("proprange(%ld,%ld) all\n",pr
->lMin
,pr
->lMax
);
1161 for (i
= 0; i
< This
->user_df
->dwNumObjs
; i
++) {
1162 This
->props
[i
].lMin
= pr
->lMin
;
1163 This
->props
[i
].lMax
= pr
->lMax
;
1166 int obj
= find_property(This
, ph
);
1167 TRACE("proprange(%ld,%ld) obj=%d\n",pr
->lMin
,pr
->lMax
,obj
);
1169 This
->props
[obj
].lMin
= pr
->lMin
;
1170 This
->props
[obj
].lMax
= pr
->lMax
;
1176 case (DWORD
)DIPROP_DEADZONE
: {
1177 LPCDIPROPDWORD pd
= (LPCDIPROPDWORD
)ph
;
1178 if (ph
->dwHow
== DIPH_DEVICE
) {
1179 TRACE("deadzone(%ld) all\n",pd
->dwData
);
1180 for (i
= 0; i
< This
->user_df
->dwNumObjs
; i
++)
1181 This
->props
[i
].lDeadZone
= pd
->dwData
;
1183 int obj
= find_property(This
, ph
);
1184 TRACE("deadzone(%ld) obj=%d\n",pd
->dwData
,obj
);
1186 This
->props
[obj
].lDeadZone
= pd
->dwData
;
1192 case (DWORD
)DIPROP_SATURATION
: {
1193 LPCDIPROPDWORD pd
= (LPCDIPROPDWORD
)ph
;
1194 if (ph
->dwHow
== DIPH_DEVICE
) {
1195 TRACE("saturation(%ld) all\n",pd
->dwData
);
1196 for (i
= 0; i
< This
->user_df
->dwNumObjs
; i
++)
1197 This
->props
[i
].lSaturation
= pd
->dwData
;
1199 int obj
= find_property(This
, ph
);
1200 TRACE("saturation(%ld) obj=%d\n",pd
->dwData
,obj
);
1202 This
->props
[obj
].lSaturation
= pd
->dwData
;
1209 FIXME("Unknown type %p (%s)\n",rguid
,debugstr_guid(rguid
));
1217 /******************************************************************************
1218 * SetEventNotification : specifies event to be sent on state change
1220 static HRESULT WINAPI
JoystickAImpl_SetEventNotification(
1221 LPDIRECTINPUTDEVICE8A iface
, HANDLE hnd
1223 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1225 TRACE("(this=%p,%p)\n",This
,hnd
);
1230 static HRESULT WINAPI
JoystickAImpl_GetCapabilities(
1231 LPDIRECTINPUTDEVICE8A iface
,
1232 LPDIDEVCAPS lpDIDevCaps
)
1234 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1237 TRACE("%p->(%p)\n",iface
,lpDIDevCaps
);
1239 if (lpDIDevCaps
== NULL
) {
1240 WARN("invalid pointer\n");
1244 size
= lpDIDevCaps
->dwSize
;
1246 if (!(size
== sizeof(DIDEVCAPS
) || size
== sizeof(DIDEVCAPS_DX3
))) {
1247 WARN("invalid parameter\n");
1248 return DIERR_INVALIDPARAM
;
1251 CopyMemory(lpDIDevCaps
, &This
->devcaps
, size
);
1252 lpDIDevCaps
->dwSize
= size
;
1254 if (TRACE_ON(dinput
))
1255 _dump_DIDEVCAPS(lpDIDevCaps
);
1260 static HRESULT WINAPI
JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface
)
1262 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1264 TRACE("(%p)\n",This
);
1266 if (!This
->acquired
) {
1267 WARN("not acquired\n");
1268 return DIERR_NOTACQUIRED
;
1275 /******************************************************************************
1276 * EnumObjects : enumerate the different buttons and axis...
1278 static HRESULT WINAPI
JoystickAImpl_EnumObjects(
1279 LPDIRECTINPUTDEVICE8A iface
,
1280 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback
,
1284 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1285 DIDEVICEOBJECTINSTANCEA ddoi
;
1290 TRACE("(this=%p,%p,%p,%08lx)\n", This
, lpCallback
, lpvRef
, dwFlags
);
1291 if (TRACE_ON(dinput
)) {
1292 TRACE(" - flags = ");
1293 _dump_EnumObjects_flags(dwFlags
);
1297 /* Only the fields till dwFFMaxForce are relevant */
1298 ddoi
.dwSize
= FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA
, dwFFMaxForce
);
1300 /* For the joystick, do as is done in the GetCapabilities function */
1301 if ((dwFlags
== DIDFT_ALL
) ||
1302 (dwFlags
& DIDFT_AXIS
) ||
1303 (dwFlags
& DIDFT_POV
)) {
1304 int pov
[4] = { 0, 0, 0, 0 };
1308 for (i
= 0; i
< This
->axes
; i
++) {
1309 int wine_obj
= This
->axis_map
[i
];
1314 ddoi
.guidType
= GUID_XAxis
;
1317 ddoi
.guidType
= GUID_YAxis
;
1320 ddoi
.guidType
= GUID_ZAxis
;
1323 ddoi
.guidType
= GUID_RxAxis
;
1326 ddoi
.guidType
= GUID_RyAxis
;
1329 ddoi
.guidType
= GUID_RzAxis
;
1332 ddoi
.guidType
= GUID_Slider
;
1335 ddoi
.guidType
= GUID_Slider
;
1339 ddoi
.guidType
= GUID_POV
;
1343 ddoi
.guidType
= GUID_POV
;
1347 ddoi
.guidType
= GUID_POV
;
1351 ddoi
.guidType
= GUID_POV
;
1354 ddoi
.guidType
= GUID_Unknown
;
1357 user_offset
= This
->offsets
[wine_obj
]; /* get user offset from wine index */
1358 user_object
= offset_to_object(This
, user_offset
);
1360 ddoi
.dwType
= This
->user_df
->rgodf
[user_object
].dwType
& 0x00ffffff;
1361 ddoi
.dwOfs
= This
->user_df
->rgodf
[user_object
].dwOfs
;
1362 sprintf(ddoi
.tszName
, "Axis %d", axes
);
1365 if (pov
[wine_obj
- 8] < 2) {
1366 user_offset
= This
->offsets
[wine_obj
]; /* get user offset from wine index */
1367 user_object
= offset_to_object(This
, user_offset
);
1369 ddoi
.dwType
= This
->user_df
->rgodf
[user_object
].dwType
& 0x00ffffff;
1370 ddoi
.dwOfs
= This
->user_df
->rgodf
[user_object
].dwOfs
;
1371 sprintf(ddoi
.tszName
, "POV %d", povs
);
1377 _dump_OBJECTINSTANCEA(&ddoi
);
1378 if (lpCallback(&ddoi
, lpvRef
) != DIENUM_CONTINUE
)
1384 if ((dwFlags
== DIDFT_ALL
) ||
1385 (dwFlags
& DIDFT_BUTTON
)) {
1387 /* The DInput SDK says that GUID_Button is only for mouse buttons but well... */
1388 ddoi
.guidType
= GUID_Button
;
1390 for (i
= 0; i
< This
->buttons
; i
++) {
1391 user_offset
= This
->offsets
[i
+ 12]; /* get user offset from wine index */
1392 user_object
= offset_to_object(This
, user_offset
);
1393 ddoi
.guidType
= GUID_Button
;
1394 ddoi
.dwType
= This
->user_df
->rgodf
[user_object
].dwType
& 0x00ffffff;
1395 ddoi
.dwOfs
= This
->user_df
->rgodf
[user_object
].dwOfs
;
1396 sprintf(ddoi
.tszName
, "Button %d", i
);
1397 _dump_OBJECTINSTANCEA(&ddoi
);
1398 if (lpCallback(&ddoi
, lpvRef
) != DIENUM_CONTINUE
) return DI_OK
;
1405 /******************************************************************************
1406 * EnumObjects : enumerate the different buttons and axis...
1408 static HRESULT WINAPI
JoystickWImpl_EnumObjects(
1409 LPDIRECTINPUTDEVICE8W iface
,
1410 LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback
,
1414 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1416 device_enumobjects_AtoWcb_data data
;
1418 data
.lpCallBack
= lpCallback
;
1419 data
.lpvRef
= lpvRef
;
1421 return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A
) This
, (LPDIENUMDEVICEOBJECTSCALLBACKA
) DIEnumDevicesCallbackAtoW
, (LPVOID
) &data
, dwFlags
);
1424 /******************************************************************************
1425 * GetProperty : get input device properties
1427 static HRESULT WINAPI
JoystickAImpl_GetProperty(
1428 LPDIRECTINPUTDEVICE8A iface
,
1430 LPDIPROPHEADER pdiph
)
1432 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1434 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(rguid
), pdiph
);
1436 if (TRACE_ON(dinput
))
1437 _dump_DIPROPHEADER(pdiph
);
1439 if (!HIWORD(rguid
)) {
1440 switch (LOWORD(rguid
)) {
1441 case (DWORD
) DIPROP_BUFFERSIZE
: {
1442 LPDIPROPDWORD pd
= (LPDIPROPDWORD
)pdiph
;
1443 TRACE(" return buffersize = %d\n",This
->queue_len
);
1444 pd
->dwData
= This
->queue_len
;
1447 case (DWORD
) DIPROP_RANGE
: {
1448 LPDIPROPRANGE pr
= (LPDIPROPRANGE
) pdiph
;
1449 int obj
= find_property(This
, pdiph
);
1450 /* The app is querying the current range of the axis
1451 * return the lMin and lMax values */
1453 pr
->lMin
= This
->props
[obj
].lMin
;
1454 pr
->lMax
= This
->props
[obj
].lMax
;
1455 TRACE("range(%ld, %ld) obj=%d\n", pr
->lMin
, pr
->lMax
, obj
);
1460 case (DWORD
) DIPROP_DEADZONE
: {
1461 LPDIPROPDWORD pd
= (LPDIPROPDWORD
)pdiph
;
1462 int obj
= find_property(This
, pdiph
);
1464 pd
->dwData
= This
->props
[obj
].lDeadZone
;
1465 TRACE("deadzone(%ld) obj=%d\n", pd
->dwData
, obj
);
1470 case (DWORD
) DIPROP_SATURATION
: {
1471 LPDIPROPDWORD pd
= (LPDIPROPDWORD
)pdiph
;
1472 int obj
= find_property(This
, pdiph
);
1474 pd
->dwData
= This
->props
[obj
].lSaturation
;
1475 TRACE("saturation(%ld) obj=%d\n", pd
->dwData
, obj
);
1481 FIXME("Unknown type %p (%s)\n",rguid
,debugstr_guid(rguid
));
1489 /******************************************************************************
1490 * GetObjectInfo : get object info
1492 HRESULT WINAPI
JoystickAImpl_GetObjectInfo(
1493 LPDIRECTINPUTDEVICE8A iface
,
1494 LPDIDEVICEOBJECTINSTANCEA pdidoi
,
1498 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1499 DIDEVICEOBJECTINSTANCEA didoiA
;
1502 TRACE("(%p,%p,%ld,0x%08lx(%s))\n",
1503 iface
, pdidoi
, dwObj
, dwHow
,
1504 dwHow
== DIPH_BYOFFSET
? "DIPH_BYOFFSET" :
1505 dwHow
== DIPH_BYID
? "DIPH_BYID" :
1506 dwHow
== DIPH_BYUSAGE
? "DIPH_BYUSAGE" :
1509 if (pdidoi
== NULL
) {
1510 WARN("invalid parameter: pdidoi = NULL\n");
1511 return DIERR_INVALIDPARAM
;
1514 if ((pdidoi
->dwSize
!= sizeof(DIDEVICEOBJECTINSTANCEA
)) &&
1515 (pdidoi
->dwSize
!= sizeof(DIDEVICEOBJECTINSTANCE_DX3A
))) {
1516 WARN("invalid parameter: pdidoi->dwSize = %ld != %d or %d\n",
1517 pdidoi
->dwSize
, sizeof(DIDEVICEOBJECTINSTANCEA
),
1518 sizeof(DIDEVICEOBJECTINSTANCE_DX3A
));
1519 return DIERR_INVALIDPARAM
;
1522 ZeroMemory(&didoiA
, sizeof(didoiA
));
1523 didoiA
.dwSize
= pdidoi
->dwSize
;
1526 case DIPH_BYOFFSET
: {
1530 for (i
= 0; i
< This
->user_df
->dwNumObjs
; i
++) {
1531 if (This
->user_df
->rgodf
[i
].dwOfs
== dwObj
) {
1532 if (This
->user_df
->rgodf
[i
].pguid
)
1533 didoiA
.guidType
= *This
->user_df
->rgodf
[i
].pguid
;
1535 didoiA
.guidType
= GUID_NULL
;
1537 didoiA
.dwOfs
= dwObj
;
1538 didoiA
.dwType
= This
->user_df
->rgodf
[i
].dwType
;
1539 didoiA
.dwFlags
= This
->user_df
->rgodf
[i
].dwFlags
;
1541 if (DIDFT_GETTYPE(This
->user_df
->rgodf
[i
].dwType
) & DIDFT_AXIS
)
1542 sprintf(didoiA
.tszName
, "Axis %d", axis
);
1543 else if (DIDFT_GETTYPE(This
->user_df
->rgodf
[i
].dwType
) & DIDFT_POV
)
1544 sprintf(didoiA
.tszName
, "POV %d", pov
);
1545 else if (DIDFT_GETTYPE(This
->user_df
->rgodf
[i
].dwType
) & DIDFT_BUTTON
)
1546 sprintf(didoiA
.tszName
, "Button %d", button
);
1548 CopyMemory(pdidoi
, &didoiA
, pdidoi
->dwSize
);
1552 if (DIDFT_GETTYPE(This
->user_df
->rgodf
[i
].dwType
) & DIDFT_AXIS
)
1554 else if (DIDFT_GETTYPE(This
->user_df
->rgodf
[i
].dwType
) & DIDFT_POV
)
1556 else if (DIDFT_GETTYPE(This
->user_df
->rgodf
[i
].dwType
) & DIDFT_BUTTON
)
1562 FIXME("dwHow = DIPH_BYID not implemented\n");
1565 FIXME("dwHow = DIPH_BYUSAGE not implemented\n");
1568 WARN("invalid parameter: dwHow = %08lx\n", dwHow
);
1569 return DIERR_INVALIDPARAM
;
1572 CopyMemory(pdidoi
, &didoiA
, pdidoi
->dwSize
);
1577 /******************************************************************************
1578 * GetDeviceInfo : get information about a device's identity
1580 HRESULT WINAPI
JoystickAImpl_GetDeviceInfo(
1581 LPDIRECTINPUTDEVICE8A iface
,
1582 LPDIDEVICEINSTANCEA pdidi
)
1584 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1586 TRACE("(%p,%p)\n", iface
, pdidi
);
1588 if (pdidi
== NULL
) {
1589 WARN("invalid pointer\n");
1593 if ((pdidi
->dwSize
!= sizeof(DIDEVICEINSTANCE_DX3A
)) &&
1594 (pdidi
->dwSize
!= sizeof(DIDEVICEINSTANCEA
))) {
1595 WARN("invalid parameter: pdidi->dwSize = %ld != %d or %d\n",
1596 pdidi
->dwSize
, sizeof(DIDEVICEINSTANCE_DX3A
),
1597 sizeof(DIDEVICEINSTANCEA
));
1598 return DIERR_INVALIDPARAM
;
1601 /* Return joystick */
1602 pdidi
->guidInstance
= GUID_Joystick
;
1603 pdidi
->guidProduct
= DInput_Wine_Joystick_GUID
;
1604 /* we only support traditional joysticks for now */
1605 pdidi
->dwDevType
= This
->devcaps
.dwDevType
;
1606 strcpy(pdidi
->tszInstanceName
, "Joystick");
1607 strcpy(pdidi
->tszProductName
, This
->name
);
1608 if (pdidi
->dwSize
> sizeof(DIDEVICEINSTANCE_DX3A
)) {
1609 pdidi
->guidFFDriver
= GUID_NULL
;
1610 pdidi
->wUsagePage
= 0;
1617 /******************************************************************************
1618 * GetDeviceInfo : get information about a device's identity
1620 HRESULT WINAPI
JoystickWImpl_GetDeviceInfo(
1621 LPDIRECTINPUTDEVICE8W iface
,
1622 LPDIDEVICEINSTANCEW pdidi
)
1624 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1626 TRACE("(%p,%p)\n", iface
, pdidi
);
1628 if ((pdidi
->dwSize
!= sizeof(DIDEVICEINSTANCE_DX3W
)) &&
1629 (pdidi
->dwSize
!= sizeof(DIDEVICEINSTANCEW
))) {
1630 WARN("invalid parameter: pdidi->dwSize = %ld != %d or %d\n",
1631 pdidi
->dwSize
, sizeof(DIDEVICEINSTANCE_DX3W
),
1632 sizeof(DIDEVICEINSTANCEW
));
1633 return DIERR_INVALIDPARAM
;
1636 /* Return joystick */
1637 pdidi
->guidInstance
= GUID_Joystick
;
1638 pdidi
->guidProduct
= DInput_Wine_Joystick_GUID
;
1639 /* we only support traditional joysticks for now */
1640 pdidi
->dwDevType
= This
->devcaps
.dwDevType
;
1641 MultiByteToWideChar(CP_ACP
, 0, "Joystick", -1, pdidi
->tszInstanceName
, MAX_PATH
);
1642 MultiByteToWideChar(CP_ACP
, 0, This
->name
, -1, pdidi
->tszProductName
, MAX_PATH
);
1643 if (pdidi
->dwSize
> sizeof(DIDEVICEINSTANCE_DX3W
)) {
1644 pdidi
->guidFFDriver
= GUID_NULL
;
1645 pdidi
->wUsagePage
= 0;
1652 static const IDirectInputDevice8AVtbl JoystickAvt
=
1654 IDirectInputDevice2AImpl_QueryInterface
,
1655 IDirectInputDevice2AImpl_AddRef
,
1656 JoystickAImpl_Release
,
1657 JoystickAImpl_GetCapabilities
,
1658 JoystickAImpl_EnumObjects
,
1659 JoystickAImpl_GetProperty
,
1660 JoystickAImpl_SetProperty
,
1661 JoystickAImpl_Acquire
,
1662 JoystickAImpl_Unacquire
,
1663 JoystickAImpl_GetDeviceState
,
1664 JoystickAImpl_GetDeviceData
,
1665 JoystickAImpl_SetDataFormat
,
1666 JoystickAImpl_SetEventNotification
,
1667 IDirectInputDevice2AImpl_SetCooperativeLevel
,
1668 JoystickAImpl_GetObjectInfo
,
1669 JoystickAImpl_GetDeviceInfo
,
1670 IDirectInputDevice2AImpl_RunControlPanel
,
1671 IDirectInputDevice2AImpl_Initialize
,
1672 IDirectInputDevice2AImpl_CreateEffect
,
1673 IDirectInputDevice2AImpl_EnumEffects
,
1674 IDirectInputDevice2AImpl_GetEffectInfo
,
1675 IDirectInputDevice2AImpl_GetForceFeedbackState
,
1676 IDirectInputDevice2AImpl_SendForceFeedbackCommand
,
1677 IDirectInputDevice2AImpl_EnumCreatedEffectObjects
,
1678 IDirectInputDevice2AImpl_Escape
,
1680 IDirectInputDevice2AImpl_SendDeviceData
,
1681 IDirectInputDevice7AImpl_EnumEffectsInFile
,
1682 IDirectInputDevice7AImpl_WriteEffectToFile
,
1683 IDirectInputDevice8AImpl_BuildActionMap
,
1684 IDirectInputDevice8AImpl_SetActionMap
,
1685 IDirectInputDevice8AImpl_GetImageInfo
1688 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
1689 # define XCAST(fun) (typeof(SysJoystickWvt.fun))
1691 # define XCAST(fun) (void*)
1694 static const IDirectInputDevice8WVtbl SysJoystickWvt
=
1696 IDirectInputDevice2WImpl_QueryInterface
,
1697 XCAST(AddRef
)IDirectInputDevice2AImpl_AddRef
,
1698 XCAST(Release
)JoystickAImpl_Release
,
1699 XCAST(GetCapabilities
)JoystickAImpl_GetCapabilities
,
1700 JoystickWImpl_EnumObjects
,
1701 XCAST(GetProperty
)JoystickAImpl_GetProperty
,
1702 XCAST(SetProperty
)JoystickAImpl_SetProperty
,
1703 XCAST(Acquire
)JoystickAImpl_Acquire
,
1704 XCAST(Unacquire
)JoystickAImpl_Unacquire
,
1705 XCAST(GetDeviceState
)JoystickAImpl_GetDeviceState
,
1706 XCAST(GetDeviceData
)JoystickAImpl_GetDeviceData
,
1707 XCAST(SetDataFormat
)JoystickAImpl_SetDataFormat
,
1708 XCAST(SetEventNotification
)JoystickAImpl_SetEventNotification
,
1709 XCAST(SetCooperativeLevel
)IDirectInputDevice2AImpl_SetCooperativeLevel
,
1710 IDirectInputDevice2WImpl_GetObjectInfo
,
1711 JoystickWImpl_GetDeviceInfo
,
1712 XCAST(RunControlPanel
)IDirectInputDevice2AImpl_RunControlPanel
,
1713 XCAST(Initialize
)IDirectInputDevice2AImpl_Initialize
,
1714 XCAST(CreateEffect
)IDirectInputDevice2AImpl_CreateEffect
,
1715 IDirectInputDevice2WImpl_EnumEffects
,
1716 IDirectInputDevice2WImpl_GetEffectInfo
,
1717 XCAST(GetForceFeedbackState
)IDirectInputDevice2AImpl_GetForceFeedbackState
,
1718 XCAST(SendForceFeedbackCommand
)IDirectInputDevice2AImpl_SendForceFeedbackCommand
,
1719 XCAST(EnumCreatedEffectObjects
)IDirectInputDevice2AImpl_EnumCreatedEffectObjects
,
1720 XCAST(Escape
)IDirectInputDevice2AImpl_Escape
,
1721 XCAST(Poll
)JoystickAImpl_Poll
,
1722 XCAST(SendDeviceData
)IDirectInputDevice2AImpl_SendDeviceData
,
1723 IDirectInputDevice7WImpl_EnumEffectsInFile
,
1724 IDirectInputDevice7WImpl_WriteEffectToFile
,
1725 IDirectInputDevice8WImpl_BuildActionMap
,
1726 IDirectInputDevice8WImpl_SetActionMap
,
1727 IDirectInputDevice8WImpl_GetImageInfo
1731 #else /* HAVE_LINUX_22_JOYSTICK_API */
1733 const struct dinput_device joystick_linux_device
= {
1734 "Wine Linux joystick driver",
1741 #endif /* HAVE_LINUX_22_JOYSTICK_API */