42#ifdef HAVE_SYS_IOCTL_H
46#ifdef HAVE_LINUX_IOCTL_H
47# include <linux/ioctl.h>
49#ifdef HAVE_LINUX_JOYSTICK_H
50# include <linux/joystick.h>
58#include "wine/unicode.h"
69#ifdef HAVE_LINUX_22_JOYSTICK_API
73#define JOYDEV_NEW "/dev/input/js"
74#define JOYDEV_OLD "/dev/js"
75#define JOYDEVDRIVER " (js)"
87 WORD vendor_id, product_id, bus_type;
92typedef struct JoystickImpl JoystickImpl;
93static const IDirectInputDevice8AVtbl JoystickAvt;
94static const IDirectInputDevice8WVtbl JoystickWvt;
99 struct JoyDev *joydev;
119 return &
This->generic.base.IDirectInputDevice8W_iface;
122static const GUID DInput_Wine_Joystick_GUID = {
126 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
129#define MAX_JOYSTICKS 64
130static INT joystick_devices_count = -1;
131static struct JoyDev *joystick_devices;
135#define SYS_PATH_FORMAT "/sys/class/input/js%d/device/id/%s"
138 char sys_path[
sizeof(SYS_PATH_FORMAT) + 16], id_str[5];
145 if (
read(sys_fd, id_str, 4) == 4)
156#undef SYS_PATH_FORMAT
158static INT find_joystick_devices(
void)
162 if (joystick_devices_count != -1)
return joystick_devices_count;
164 joystick_devices_count = 0;
165 for (
i = 0;
i < MAX_JOYSTICKS;
i++)
168 struct JoyDev joydev, *new_joydevs;
169 BYTE axes_map[ABS_MAX + 1];
170 SHORT btn_map[KEY_MAX - BTN_MISC + 1];
173 snprintf(joydev.device,
sizeof(joydev.device),
"%s%d", JOYDEV_NEW,
i);
176 snprintf(joydev.device,
sizeof(joydev.device),
"%s%d", JOYDEV_OLD,
i);
180 strcpy(joydev.name,
"Wine Joystick");
181#if defined(JSIOCGNAME)
182 if (
ioctl(
fd, JSIOCGNAME(
sizeof(joydev.name) -
sizeof(JOYDEVDRIVER)), joydev.name) < 0)
187 strcat(joydev.name, JOYDEVDRIVER);
195 if (
ioctl(
fd, JSIOCGAXES, &joydev.axis_count) < 0)
197 WARN(
"ioctl(%s,JSIOCGAXES) failed: %s, defaulting to 2\n", joydev.device,
strerror(
errno));
198 joydev.axis_count = 2;
201 WARN(
"reading number of joystick axes unsupported in this platform, defaulting to 2\n");
202 joydev.axis_count = 2;
205 if (
ioctl(
fd, JSIOCGBUTTONS, &joydev.button_count) < 0)
207 WARN(
"ioctl(%s,JSIOCGBUTTONS) failed: %s, defaulting to 2\n", joydev.device,
strerror(
errno));
208 joydev.button_count = 2;
211 WARN(
"reading number of joystick buttons unsupported in this platform, defaulting to 2\n");
212 joydev.button_count = 2;
215 joydev.is_joystick =
FALSE;
216 if (
ioctl(
fd, JSIOCGBTNMAP, btn_map) < 0)
226 for (
j = 0; !joydev.is_joystick &&
j < joydev.button_count;
j++)
243 joydev.is_joystick =
TRUE;
256 TRACE(
"Stylus detected. Skipping\n");
261 if (
ioctl(
fd, JSIOCGAXMAP, axes_map) < 0)
264 joydev.dev_axes_map =
NULL;
269 INT j, found_axes = 0;
272 for (
j = 0;
j < joydev.axis_count;
j++)
277 joydev.dev_axes_map[
j] =
j;
280 else if (axes_map[
j] <= 10)
285 joydev.dev_axes_map[
j] = axes_map[
j] - 8;
288 else if (axes_map[
j] == 16 ||
292 joydev.dev_axes_map[
j] = 8;
296 joydev.dev_axes_map[
j] = -1;
300 if (joydev.axis_count && !found_axes)
302 int axes_limit =
min(joydev.axis_count, 8);
304 ERR(
"Incoherent joystick data, advertised %d axes, detected 0. Assuming 1-to-1.\n",
306 for (
j = 0;
j < axes_limit;
j++)
307 joydev.dev_axes_map[
j] =
j;
309 joydev.axis_count = axes_limit;
314 joydev.vendor_id = 0;
315 joydev.product_id = 0;
317 read_sys_id_variable(
i,
"vendor", &joydev.vendor_id);
318 read_sys_id_variable(
i,
"product", &joydev.product_id);
319 read_sys_id_variable(
i,
"bustype", &joydev.bus_type);
321 if (joydev.vendor_id == 0 || joydev.product_id == 0)
323 joydev.guid_product = DInput_Wine_Joystick_GUID;
329 joydev.guid_product.Data1 =
MAKELONG(joydev.vendor_id, joydev.product_id);
334 if (!joystick_devices_count)
338 (joystick_devices_count + 1) *
sizeof(
struct JoyDev));
339 if (!new_joydevs)
continue;
341 TRACE(
"Found a joystick on %s: %s\n with %d axes and %d buttons\n", joydev.device,
342 joydev.name, joydev.axis_count, joydev.button_count);
344 joystick_devices = new_joydevs;
345 joystick_devices[joystick_devices_count++] = joydev;
348 return joystick_devices_count;
366 if (joystick_devices[
id].bus_type == BUS_USB &&
367 joystick_devices[
id].vendor_id && joystick_devices[
id].product_id)
371 if (joystick_devices[
id].is_joystick)
387 lpddiW.
dwSize =
sizeof(lpddiW);
388 fill_joystick_dideviceinstanceW(&lpddiW,
version,
id);
409 if (
id >= find_joystick_devices())
return E_FAIL;
412 WARN(
"force feedback not supported\n");
416 if ((dwDevType == 0) ||
425 fill_joystick_dideviceinstanceA( lpddi,
version,
id );
427 TRACE(
"Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[
id].
device, joystick_devices[
id].
name);
438 if (
id >= find_joystick_devices())
return E_FAIL;
441 WARN(
"force feedback not supported\n");
445 if ((dwDevType == 0) ||
454 fill_joystick_dideviceinstanceW( lpddi,
version,
id );
456 TRACE(
"Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[
id].
device, joystick_devices[
id].
name);
464 JoystickImpl **pdev,
unsigned short index)
467 JoystickImpl* newDevice;
476 if (newDevice == 0) {
477 WARN(
"out of memory\n");
482 newDevice->joydev = &joystick_devices[
index];
483 newDevice->joyfd = -1;
484 newDevice->generic.guidInstance = DInput_Wine_Joystick_GUID;
485 newDevice->generic.guidInstance.Data3 =
index;
486 newDevice->generic.guidProduct = DInput_Wine_Joystick_GUID;
487 newDevice->generic.joy_polldev = joy_polldev;
488 newDevice->generic.name = newDevice->joydev->name;
489 newDevice->generic.device_axis_count = newDevice->joydev->axis_count;
490 newDevice->generic.devcaps.dwButtons = newDevice->joydev->button_count;
492 if (newDevice->generic.devcaps.dwButtons > 128)
494 WARN(
"Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
495 newDevice->generic.devcaps.dwButtons = 128;
498 newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt;
499 newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt;
500 newDevice->generic.base.ref = 1;
501 newDevice->generic.base.dinput = dinput;
502 newDevice->generic.base.guid = *rguid;
504 newDevice->generic.base.crit.DebugInfo->Spare[0] = (
DWORD_PTR)(__FILE__
": JoystickImpl*->generic.base.crit");
507 newDevice->generic.deadzone = 0;
518 df->
dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
521 for (
i = 0;
i < newDevice->generic.device_axis_count;
i++)
523 int wine_obj = newDevice->generic.axis_map[
i];
525 if (wine_obj < 0)
continue;
536 for (
i = 0;
i < newDevice->generic.devcaps.dwButtons;
i++)
542 newDevice->generic.base.data_format.wine_df = df;
546 newDevice->generic.props[
i].lDevMin = -32767;
547 newDevice->generic.props[
i].lDevMax = +32767;
548 newDevice->generic.props[
i].lMin = 0;
549 newDevice->generic.props[
i].lMax = 0xffff;
550 newDevice->generic.props[
i].lDeadZone = newDevice->generic.deadzone;
551 newDevice->generic.props[
i].lSaturation = 0;
560 newDevice->generic.devcaps.dwSize =
sizeof(newDevice->generic.devcaps);
564 fill_joystick_dideviceinstanceW(&ddi, newDevice->generic.base.dinput->dwVersion,
index);
565 newDevice->generic.devcaps.dwDevType = ddi.
dwDevType;
567 newDevice->generic.devcaps.dwFFSamplePeriod = 0;
568 newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
569 newDevice->generic.devcaps.dwFirmwareRevision = 0;
570 newDevice->generic.devcaps.dwHardwareRevision = 0;
571 newDevice->generic.devcaps.dwFFDriverVersion = 0;
575 for (
i = 0;
i < (newDevice->generic.device_axis_count);
i++)
576 TRACE(
"axis_map[%d] = %d\n",
i, newDevice->generic.axis_map[
i]);
600static unsigned short get_joystick_index(
REFGUID guid)
602 GUID wine_joystick = DInput_Wine_Joystick_GUID;
605 wine_joystick.Data3 = 0;
614 return MAX_JOYSTICKS;
619 unsigned short index;
622 find_joystick_devices();
625 if ((
index = get_joystick_index(rguid)) < MAX_JOYSTICKS &&
626 joystick_devices_count &&
index < joystick_devices_count)
649 WARN(
"no interface\n");
657 *pdev = &
This->generic.base.IDirectInputDevice8W_iface;
659 *pdev = &
This->generic.base.IDirectInputDevice8A_iface;
670 "Wine Linux joystick driver",
691 if (
This->joyfd==-1) {
692 TRACE(
"opening joystick device %s\n",
This->joydev->device);
695 if (
This->joyfd==-1) {
729 if (!
This->joydev->product_id || !
This->joydev->vendor_id)
739 pd->
dwData = get_joystick_index(&
This->generic.base.guid);
746 static const WCHAR formatW[] = {
'\\',
'\\',
'?',
'\\',
'h',
'i',
'd',
'#',
'v',
'i',
'd',
'_',
'%',
'0',
'4',
'x',
'&',
747 'p',
'i',
'd',
'_',
'%',
'0',
'4',
'x',
'&',
'%',
's',
'_',
'%',
'h',
'u',0};
748 static const WCHAR miW[] = {
'm',
'i',0};
749 static const WCHAR igW[] = {
'i',
'g',0};
761 sprintfW(pd->
wszPath, formatW, vid,
pid, is_gamepad ? igW : miW, get_joystick_index(&
This->generic.base.guid));
794 fill_joystick_dideviceinstanceA( ddi,
This->generic.base.dinput->dwVersion,
795 get_joystick_index(&
This->generic.base.guid) );
810 fill_joystick_dideviceinstanceW( ddi,
This->generic.base.dinput->dwVersion,
811 get_joystick_index(&
This->generic.base.guid) );
830 if (
This->joyfd!=-1) {
831 TRACE(
"closing joystick device\n");
854 if (
This->joyfd==-1) {
863 plfd.fd =
This->joyfd;
865 if (
poll(&plfd,1,0) != 1)
868 if (
sizeof(jse)!=
read(
This->joyfd,&jse,
sizeof(jse))) {
871 TRACE(
"js_event: type 0x%x, number %d, value %d\n",
872 jse.type,jse.number,jse.value);
873 if (jse.type & JS_EVENT_BUTTON)
876 if (jse.number >=
This->generic.devcaps.dwButtons)
return;
878 button =
This->generic.button_map[jse.number];
883 else if (jse.type & JS_EVENT_AXIS)
885 int number =
This->generic.axis_map[jse.number];
892 TRACE(
"changing axis %d => %d\n", jse.number,
number);
895 case 0:
This->generic.js.lX =
value;
break;
896 case 1:
This->generic.js.lY =
value;
break;
897 case 2:
This->generic.js.lZ =
value;
break;
898 case 3:
This->generic.js.lRx =
value;
break;
899 case 4:
This->generic.js.lRy =
value;
break;
900 case 5:
This->generic.js.lRz =
value;
break;
901 case 6:
This->generic.js.rglSlider[0] =
value;
break;
902 case 7:
This->generic.js.rglSlider[1] =
value;
break;
903 case 8:
case 9:
case 10:
case 11:
924static const IDirectInputDevice8AVtbl JoystickAvt =
931 JoystickLinuxAImpl_GetProperty,
933 JoystickLinuxAImpl_Acquire,
934 JoystickLinuxAImpl_Unacquire,
941 JoystickLinuxAImpl_GetDeviceInfo,
960static const IDirectInputDevice8WVtbl JoystickWvt =
967 JoystickLinuxWImpl_GetProperty,
969 JoystickLinuxWImpl_Acquire,
970 JoystickLinuxWImpl_Unacquire,
977 JoystickLinuxWImpl_GetDeviceInfo,
999 "Wine Linux joystick driver",
char * strcat(char *DstString, const char *SrcString)
char * strcpy(char *DstString, const char *SrcString)
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
static void list_add_tail(struct list_entry *head, struct list_entry *entry)
DWORD joystick_map_pov(const POINTL *p) DECLSPEC_HIDDEN
LONG joystick_map_axis(ObjProps *props, int val) DECLSPEC_HIDDEN
#define HeapFree(x, y, z)
#define MultiByteToWideChar
static const WCHAR version[]
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
_Check_return_ long __cdecl strtol(_In_z_ const char *_Str, _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix)
const struct dinput_device joystick_linux_device
#define memcpy(s1, s2, n)
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
#define sprintf(buf, format,...)
static unsigned int number
const char * strerror(int err)
#define IsEqualGUID(rguid1, rguid2)
CHAR tszInstanceName[MAX_PATH]
CHAR tszProductName[MAX_PATH]
WCHAR tszProductName[MAX_PATH]
WCHAR tszInstanceName[MAX_PATH]
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
#define CONTAINING_RECORD(address, type, field)
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid