{
char device[MAX_PATH];
char name[MAX_PATH];
+ GUID guid_product;
BYTE axis_count;
BYTE button_count;
int *dev_axes_map;
+
+ WORD vendor_id, product_id, bus_type;
};
typedef struct JoystickImpl JoystickImpl;
return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface),
JoystickGenericImpl, base), JoystickImpl, generic);
}
-static inline IDirectInputDevice8A *IDirectInputDevice8A_from_impl(JoystickImpl *This)
-{
- return &This->generic.base.IDirectInputDevice8A_iface;
-}
+
static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl *This)
{
return &This->generic.base.IDirectInputDevice8W_iface;
{0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
};
+/*
+ * Construct the GUID in the same way of Windows doing this.
+ * Data1 is concatenation of productid and vendorid.
+ * Data2 and Data3 are NULL.
+ * Data4 seems to be a constant.
+ */
+static const GUID DInput_Wine_Joystick_Constant_Part_GUID = {
+ 0x000000000,
+ 0x0000,
+ 0x0000,
+ {0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44}
+};
+
#define MAX_JOYSTICKS 64
static INT joystick_devices_count = -1;
static struct JoyDev *joystick_devices;
static void joy_polldev(LPDIRECTINPUTDEVICE8A iface);
+#define SYS_PATH_FORMAT "/sys/class/input/js%d/device/id/%s"
+static BOOL read_sys_id_variable(int index, const char *property, WORD *value)
+{
+ char sys_path[sizeof(SYS_PATH_FORMAT) + 16], id_str[5];
+ int sys_fd;
+ BOOL ret = FALSE;
+
+ sprintf(sys_path, SYS_PATH_FORMAT, index, property);
+ if ((sys_fd = open(sys_path, O_RDONLY)) != -1)
+ {
+ if (read(sys_fd, id_str, 4) == 4)
+ {
+ id_str[4] = '\0';
+ *value = strtol(id_str, NULL, 16);
+ ret = TRUE;
+ }
+
+ close(sys_fd);
+ }
+ return ret;
+}
+#undef SYS_PATH_FORMAT
+
static INT find_joystick_devices(void)
{
INT i;
BYTE axes_map[ABS_MAX + 1];
snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_NEW, i);
- if ((fd = open(joydev.device, O_RDONLY)) < 0)
+ if ((fd = open(joydev.device, O_RDONLY)) == -1)
{
snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_OLD, i);
- if ((fd = open(joydev.device, O_RDONLY)) < 0) continue;
+ if ((fd = open(joydev.device, O_RDONLY)) == -1) continue;
}
strcpy(joydev.name, "Wine Joystick");
#ifdef JSIOCGAXES
if (ioctl(fd, JSIOCGAXES, &joydev.axis_count) < 0)
{
- WARN("ioctl(%s,JSIOCGAXES) failed: %s, defauting to 2\n", joydev.device, strerror(errno));
+ WARN("ioctl(%s,JSIOCGAXES) failed: %s, defaulting to 2\n", joydev.device, strerror(errno));
joydev.axis_count = 2;
}
+#else
+ WARN("reading number of joystick axes unsupported in this platform, defaulting to 2\n");
+ joydev.axis_count = 2;
#endif
#ifdef JSIOCGBUTTONS
if (ioctl(fd, JSIOCGBUTTONS, &joydev.button_count) < 0)
{
- WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defauting to 2\n", joydev.device, strerror(errno));
+ WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defaulting to 2\n", joydev.device, strerror(errno));
joydev.button_count = 2;
}
+#else
+ WARN("reading number of joystick buttons unsupported in this platform, defaulting to 2\n");
+ joydev.button_count = 2;
#endif
if (ioctl(fd, JSIOCGAXMAP, axes_map) < 0)
else
if ((joydev.dev_axes_map = HeapAlloc(GetProcessHeap(), 0, joydev.axis_count * sizeof(int))))
{
- INT j;
+ INT j, found_axes = 0;
/* Remap to DI numbers */
for (j = 0; j < joydev.axis_count; j++)
+ {
if (axes_map[j] < 8)
+ {
/* Axis match 1-to-1 */
joydev.dev_axes_map[j] = j;
+ found_axes++;
+ }
else if (axes_map[j] == 16 ||
axes_map[j] == 17)
+ {
/* POV axis */
joydev.dev_axes_map[j] = 8;
+ found_axes++;
+ }
else
joydev.dev_axes_map[j] = -1;
+ }
+
+ /* If no axes were configured but there are axes assume a 1-to-1 (wii controller) */
+ if (joydev.axis_count && !found_axes)
+ {
+ int axes_limit = min(joydev.axis_count, 8); /* generic driver limit */
+
+ ERR("Incoherent joystick data, advertised %d axes, detected 0. Assuming 1-to-1.\n",
+ joydev.axis_count);
+ for (j = 0; j < axes_limit; j++)
+ joydev.dev_axes_map[j] = j;
+
+ joydev.axis_count = axes_limit;
+ }
}
+ /* Find vendor_id and product_id in sysfs */
+ joydev.vendor_id = 0;
+ joydev.product_id = 0;
+
+ read_sys_id_variable(i, "vendor", &joydev.vendor_id);
+ read_sys_id_variable(i, "product", &joydev.product_id);
+ read_sys_id_variable(i, "bustype", &joydev.bus_type);
+
+ if (joydev.vendor_id == 0 || joydev.product_id == 0)
+ {
+ joydev.guid_product = DInput_Wine_Joystick_GUID;
+ }
+ else
+ {
+ /* Concatenate product_id with vendor_id to mimic Windows behaviour */
+ joydev.guid_product = DInput_Wine_Joystick_Constant_Part_GUID;
+ joydev.guid_product.Data1 = MAKELONG(joydev.vendor_id, joydev.product_id);
+ }
+
close(fd);
if (!joystick_devices_count)
return joystick_devices_count;
}
+static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
+{
+ DWORD dwSize = lpddi->dwSize;
+
+ TRACE("%d %p\n", dwSize, lpddi);
+ memset(lpddi, 0, dwSize);
+
+ /* Return joystick */
+ lpddi->dwSize = dwSize;
+ lpddi->guidInstance = DInput_Wine_Joystick_GUID;
+ lpddi->guidInstance.Data3 = id;
+ lpddi->guidProduct = joystick_devices[id].guid_product;
+ /* we only support traditional joysticks for now */
+ if (version >= 0x0800)
+ lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
+ else
+ lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
+
+ /* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */
+ if (joystick_devices[id].bus_type == BUS_USB &&
+ joystick_devices[id].vendor_id && joystick_devices[id].product_id)
+ {
+ lpddi->dwDevType |= DIDEVTYPE_HID;
+ lpddi->wUsagePage = 0x01; /* Desktop */
+ if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType == DIDEVTYPE_JOYSTICK)
+ lpddi->wUsage = 0x04; /* Joystick */
+ else
+ lpddi->wUsage = 0x05; /* Game Pad */
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
+ MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszProductName, MAX_PATH);
+ lpddi->guidFFDriver = GUID_NULL;
+}
+
+static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
+{
+ DIDEVICEINSTANCEW lpddiW;
+ DWORD dwSize = lpddi->dwSize;
+
+ lpddiW.dwSize = sizeof(lpddiW);
+ fill_joystick_dideviceinstanceW(&lpddiW, version, id);
+
+ TRACE("%d %p\n", dwSize, lpddi);
+ memset(lpddi, 0, dwSize);
+
+ /* Convert W->A */
+ lpddi->dwSize = dwSize;
+ lpddi->guidInstance = lpddiW.guidInstance;
+ lpddi->guidProduct = lpddiW.guidProduct;
+ lpddi->dwDevType = lpddiW.dwDevType;
+ strcpy(lpddi->tszInstanceName, joystick_devices[id].name);
+ strcpy(lpddi->tszProductName, joystick_devices[id].name);
+ lpddi->guidFFDriver = lpddiW.guidFFDriver;
+ lpddi->wUsagePage = lpddiW.wUsagePage;
+ lpddi->wUsage = lpddiW.wUsage;
+}
+
static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
{
int fd = -1;
((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
/* check whether we have a joystick */
- if ((fd = open(joystick_devices[id].device, O_RDONLY)) < 0)
+ if ((fd = open(joystick_devices[id].device, O_RDONLY)) == -1)
{
- WARN("open(%s, O_RDONLY) failed: %s\n", joystick_devices[id].name, strerror(errno));
+ WARN("open(%s, O_RDONLY) failed: %s\n", joystick_devices[id].device, strerror(errno));
return S_FALSE;
}
-
- /* Return joystick */
- lpddi->guidInstance = DInput_Wine_Joystick_GUID;
- lpddi->guidInstance.Data3 = id;
- lpddi->guidProduct = DInput_Wine_Joystick_GUID;
- /* we only support traditional joysticks for now */
- if (version >= 0x0800)
- lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
- else
- lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
-
- strcpy(lpddi->tszInstanceName, joystick_devices[id].name);
- strcpy(lpddi->tszProductName, joystick_devices[id].name);
-
- lpddi->guidFFDriver = GUID_NULL;
+ fill_joystick_dideviceinstanceA( lpddi, version, id );
close(fd);
- TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id].device, lpddi->tszProductName);
+ TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id].device, joystick_devices[id].name);
return S_OK;
}
((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
/* check whether we have a joystick */
- if ((fd = open(joystick_devices[id].device, O_RDONLY)) < 0)
+ if ((fd = open(joystick_devices[id].device, O_RDONLY)) == -1)
{
- WARN("open(%s,O_RDONLY) failed: %s\n", joystick_devices[id].device, strerror(errno));
+ WARN("open(%s, O_RDONLY) failed: %s\n", joystick_devices[id].device, strerror(errno));
return S_FALSE;
}
-
- /* Return joystick */
- lpddi->guidInstance = DInput_Wine_Joystick_GUID;
- lpddi->guidInstance.Data3 = id;
- lpddi->guidProduct = DInput_Wine_Joystick_GUID;
- /* we only support traditional joysticks for now */
- if (version >= 0x0800)
- lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
- else
- lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
-
- MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
- MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszProductName, MAX_PATH);
- lpddi->guidFFDriver = GUID_NULL;
+ fill_joystick_dideviceinstanceW( lpddi, version, id );
close(fd);
TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id].device, joystick_devices[id].name);
return S_OK;
HRESULT hr;
LPDIDATAFORMAT df = NULL;
int idx = 0;
+ DIDEVICEINSTANCEW ddi;
TRACE("%s %p %p %hu\n", debugstr_guid(rguid), dinput, pdev, index);
newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
- if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
- newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
- else
- newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
+
+ ddi.dwSize = sizeof(ddi);
+ fill_joystick_dideviceinstanceW(&ddi, newDevice->generic.base.dinput->dwVersion, index);
+ newDevice->generic.devcaps.dwDevType = ddi.dwDevType;
+
newDevice->generic.devcaps.dwFFSamplePeriod = 0;
newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
newDevice->generic.devcaps.dwFirmwareRevision = 0;
switch (LOWORD(rguid)) {
+ case (DWORD_PTR) DIPROP_VIDPID:
+ {
+ LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
+
+ if (!This->joydev->product_id || !This->joydev->vendor_id)
+ return DIERR_UNSUPPORTED;
+ pd->dwData = MAKELONG(This->joydev->vendor_id, This->joydev->product_id);
+ TRACE("DIPROP_VIDPID(%08x)\n", pd->dwData);
+ break;
+ }
case (DWORD_PTR) DIPROP_JOYSTICKID:
{
LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
return JoystickLinuxWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
}
+/******************************************************************************
+ * GetDeviceInfo : get information about a device's identity
+ */
+static HRESULT WINAPI JoystickLinuxAImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8A iface, LPDIDEVICEINSTANCEA ddi)
+{
+ JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
+
+ TRACE("(%p) %p\n", This, ddi);
+
+ if (ddi == NULL) return E_POINTER;
+ if ((ddi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) &&
+ (ddi->dwSize != sizeof(DIDEVICEINSTANCEA)))
+ return DIERR_INVALIDPARAM;
+
+ fill_joystick_dideviceinstanceA( ddi, This->generic.base.dinput->dwVersion,
+ get_joystick_index(&This->generic.base.guid) );
+ return DI_OK;
+}
+
+static HRESULT WINAPI JoystickLinuxWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW ddi)
+{
+ JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
+
+ TRACE("(%p) %p\n", This, ddi);
+
+ if (ddi == NULL) return E_POINTER;
+ if ((ddi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) &&
+ (ddi->dwSize != sizeof(DIDEVICEINSTANCEW)))
+ return DIERR_INVALIDPARAM;
+
+ fill_joystick_dideviceinstanceW( ddi, This->generic.base.dinput->dwVersion,
+ get_joystick_index(&This->generic.base.guid) );
+ return DI_OK;
+}
+
/******************************************************************************
* Unacquire : frees the joystick
*/
IDirectInputDevice2AImpl_SetEventNotification,
IDirectInputDevice2AImpl_SetCooperativeLevel,
JoystickAGenericImpl_GetObjectInfo,
- JoystickAGenericImpl_GetDeviceInfo,
+ JoystickLinuxAImpl_GetDeviceInfo,
IDirectInputDevice2AImpl_RunControlPanel,
IDirectInputDevice2AImpl_Initialize,
IDirectInputDevice2AImpl_CreateEffect,
IDirectInputDevice2WImpl_SetEventNotification,
IDirectInputDevice2WImpl_SetCooperativeLevel,
JoystickWGenericImpl_GetObjectInfo,
- JoystickWGenericImpl_GetDeviceInfo,
+ JoystickLinuxWImpl_GetDeviceInfo,
IDirectInputDevice2WImpl_RunControlPanel,
IDirectInputDevice2WImpl_Initialize,
IDirectInputDevice2WImpl_CreateEffect,