29 #include "wine/port.h" 38 #ifdef HAVE_SYS_TIME_H 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> 53 #ifdef HAVE_SYS_POLL_H 54 # include <sys/poll.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;
92 typedef struct JoystickImpl JoystickImpl;
93 static const IDirectInputDevice8AVtbl JoystickAvt;
94 static const IDirectInputDevice8WVtbl JoystickWvt;
99 struct JoyDev *joydev;
119 return &
This->generic.base.IDirectInputDevice8W_iface;
122 static const GUID DInput_Wine_Joystick_GUID = {
126 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
129 #define MAX_JOYSTICKS 64 130 static INT joystick_devices_count = -1;
131 static 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 158 static 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]);
600 static 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:
924 static const IDirectInputDevice8AVtbl JoystickAvt =
931 JoystickLinuxAImpl_GetProperty,
933 JoystickLinuxAImpl_Acquire,
934 JoystickLinuxAImpl_Unacquire,
941 JoystickLinuxAImpl_GetDeviceInfo,
960 static const IDirectInputDevice8WVtbl JoystickWvt =
967 JoystickLinuxWImpl_GetProperty,
969 JoystickLinuxWImpl_Acquire,
970 JoystickLinuxWImpl_Unacquire,
977 JoystickLinuxWImpl_GetDeviceInfo,
999 "Wine Linux joystick driver",
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
char * strcat(char *DstString, const char *SrcString)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
const char * strerror(int err)
DWORD joystick_map_pov(const POINTL *p) DECLSPEC_HIDDEN
#define sprintf(buf, format,...)
__WINE_SERVER_LIST_INLINE void list_add_tail(struct list *list, struct list *elem)
static size_t double number
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
static const WCHAR version[]
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
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
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
int poll(struct pollfd *ufds, int nfds, int timeout)
WCHAR tszProductName[MAX_PATH]
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
#define memcpy(s1, s2, n)
CHAR tszInstanceName[MAX_PATH]
GLsizei const GLfloat * value
WCHAR tszInstanceName[MAX_PATH]
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
LONG joystick_map_axis(ObjProps *props, int val) DECLSPEC_HIDDEN
BOOL WINAPI IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
#define MultiByteToWideChar
CHAR tszProductName[MAX_PATH]
_Check_return_ long __cdecl strtol(_In_z_ const char *_Str, _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix)
char * strcpy(char *DstString, const char *SrcString)
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
#define HeapFree(x, y, z)
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
const struct dinput_device joystick_linux_device