Commit ae849579 authored by Andrew Eikum's avatar Andrew Eikum Committed by Alexandre Julliard

dinput: Use heuristics to guess if a device is a gamepad or a joystick.

parent 9cbfd2c9
...@@ -81,7 +81,7 @@ extern void _copy_diactionformatWtoA(LPDIACTIONFORMATA, LPDIACTIONFORMATW) DECLS ...@@ -81,7 +81,7 @@ extern void _copy_diactionformatWtoA(LPDIACTIONFORMATA, LPDIACTIONFORMATW) DECLS
extern HRESULT _configure_devices(IDirectInput8W *iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) DECLSPEC_HIDDEN; extern HRESULT _configure_devices(IDirectInput8W *iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) DECLSPEC_HIDDEN;
extern WCHAR* get_mapping_path(const WCHAR *device, const WCHAR *username) DECLSPEC_HIDDEN; extern WCHAR* get_mapping_path(const WCHAR *device, const WCHAR *username) DECLSPEC_HIDDEN;
extern DWORD get_device_type(DWORD version) DECLSPEC_HIDDEN; extern DWORD get_device_type(DWORD version, BOOL is_joystick) DECLSPEC_HIDDEN;
#define IS_DIPROP(x) (((ULONG_PTR)(x) >> 16) == 0) #define IS_DIPROP(x) (((ULONG_PTR)(x) >> 16) == 0)
......
...@@ -76,8 +76,12 @@ DWORD typeFromGUID(REFGUID guid) ...@@ -76,8 +76,12 @@ DWORD typeFromGUID(REFGUID guid)
} }
} }
DWORD get_device_type(DWORD version) DWORD get_device_type(DWORD version, BOOL is_joystick)
{ {
if (is_joystick)
return version >= 0x0800 ? DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8) :
DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
return version >= 0x0800 ? DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEJOYSTICK_STANDARD << 8) : return version >= 0x0800 ? DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEJOYSTICK_STANDARD << 8) :
DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8); DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8);
} }
......
...@@ -84,6 +84,8 @@ struct JoyDev ...@@ -84,6 +84,8 @@ struct JoyDev
int *dev_axes_map; int *dev_axes_map;
WORD vendor_id, product_id, bus_type; WORD vendor_id, product_id, bus_type;
BOOL is_joystick;
}; };
typedef struct JoystickImpl JoystickImpl; typedef struct JoystickImpl JoystickImpl;
...@@ -177,6 +179,7 @@ static INT find_joystick_devices(void) ...@@ -177,6 +179,7 @@ static INT find_joystick_devices(void)
int fd; int fd;
struct JoyDev joydev, *new_joydevs; struct JoyDev joydev, *new_joydevs;
BYTE axes_map[ABS_MAX + 1]; BYTE axes_map[ABS_MAX + 1];
SHORT btn_map[KEY_MAX - BTN_MISC + 1];
snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_NEW, i); snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_NEW, i);
if ((fd = open(joydev.device, O_RDONLY)) == -1) if ((fd = open(joydev.device, O_RDONLY)) == -1)
...@@ -220,6 +223,42 @@ static INT find_joystick_devices(void) ...@@ -220,6 +223,42 @@ static INT find_joystick_devices(void)
joydev.button_count = 2; joydev.button_count = 2;
#endif #endif
joydev.is_joystick = FALSE;
if (ioctl(fd, JSIOCGBTNMAP, btn_map) < 0)
{
WARN("ioctl(%s,JSIOCGBTNMAP) failed: %s\n", joydev.device, strerror(errno));
}
else
{
INT j;
/* in lieu of properly reporting HID usage, detect presence of
* "joystick buttons" and report those devices as joysticks instead of
* gamepads */
for (j = 0; !joydev.is_joystick && j < joydev.button_count; j++)
{
switch (btn_map[j])
{
case BTN_TRIGGER:
case BTN_THUMB:
case BTN_THUMB2:
case BTN_TOP:
case BTN_TOP2:
case BTN_PINKIE:
case BTN_BASE:
case BTN_BASE2:
case BTN_BASE3:
case BTN_BASE4:
case BTN_BASE5:
case BTN_BASE6:
case BTN_DEAD:
joydev.is_joystick = TRUE;
break;
default:
break;
}
}
}
if (ioctl(fd, JSIOCGAXMAP, axes_map) < 0) if (ioctl(fd, JSIOCGAXMAP, axes_map) < 0)
{ {
WARN("ioctl(%s,JSIOCGAXMAP) failed: %s\n", joydev.device, strerror(errno)); WARN("ioctl(%s,JSIOCGAXMAP) failed: %s\n", joydev.device, strerror(errno));
...@@ -322,7 +361,7 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver ...@@ -322,7 +361,7 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver
lpddi->guidInstance = DInput_Wine_Joystick_GUID; lpddi->guidInstance = DInput_Wine_Joystick_GUID;
lpddi->guidInstance.Data3 = id; lpddi->guidInstance.Data3 = id;
lpddi->guidProduct = joystick_devices[id].guid_product; lpddi->guidProduct = joystick_devices[id].guid_product;
lpddi->dwDevType = get_device_type(version); lpddi->dwDevType = get_device_type(version, joystick_devices[id].is_joystick);
/* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */ /* 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 && if (joystick_devices[id].bus_type == BUS_USB &&
...@@ -330,7 +369,10 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver ...@@ -330,7 +369,10 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver
{ {
lpddi->dwDevType |= DIDEVTYPE_HID; lpddi->dwDevType |= DIDEVTYPE_HID;
lpddi->wUsagePage = 0x01; /* Desktop */ lpddi->wUsagePage = 0x01; /* Desktop */
lpddi->wUsage = 0x05; /* Game Pad */ if (joystick_devices[id].is_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->tszInstanceName, MAX_PATH);
......
...@@ -100,7 +100,7 @@ struct JoyDev { ...@@ -100,7 +100,7 @@ struct JoyDev {
GUID guid; GUID guid;
GUID guid_product; GUID guid_product;
BOOL has_ff; BOOL has_ff, is_joystick;
int num_effects; int num_effects;
/* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */ /* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */
...@@ -243,6 +243,24 @@ static void find_joydevs(void) ...@@ -243,6 +243,24 @@ static void find_joydevs(void)
continue; continue;
} }
/* in lieu of properly reporting HID usage, detect presence of
* "joystick buttons" and report those devices as joysticks instead of
* gamepads */
joydev.is_joystick =
test_bit(joydev.keybits, BTN_TRIGGER) ||
test_bit(joydev.keybits, BTN_THUMB) ||
test_bit(joydev.keybits, BTN_THUMB2) ||
test_bit(joydev.keybits, BTN_TOP) ||
test_bit(joydev.keybits, BTN_TOP2) ||
test_bit(joydev.keybits, BTN_PINKIE) ||
test_bit(joydev.keybits, BTN_BASE) ||
test_bit(joydev.keybits, BTN_BASE2) ||
test_bit(joydev.keybits, BTN_BASE3) ||
test_bit(joydev.keybits, BTN_BASE4) ||
test_bit(joydev.keybits, BTN_BASE5) ||
test_bit(joydev.keybits, BTN_BASE6) ||
test_bit(joydev.keybits, BTN_DEAD);
if (!(joydev.device = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1))) if (!(joydev.device = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1)))
{ {
close(fd); close(fd);
...@@ -350,7 +368,7 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver ...@@ -350,7 +368,7 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver
lpddi->guidInstance = joydevs[id].guid; lpddi->guidInstance = joydevs[id].guid;
lpddi->guidProduct = joydevs[id].guid_product; lpddi->guidProduct = joydevs[id].guid_product;
lpddi->guidFFDriver = GUID_NULL; lpddi->guidFFDriver = GUID_NULL;
lpddi->dwDevType = get_device_type(version); lpddi->dwDevType = get_device_type(version, joydevs[id].is_joystick);
/* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */ /* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */
if (joydevs[id].bus_type == BUS_USB && if (joydevs[id].bus_type == BUS_USB &&
...@@ -358,7 +376,10 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver ...@@ -358,7 +376,10 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver
{ {
lpddi->dwDevType |= DIDEVTYPE_HID; lpddi->dwDevType |= DIDEVTYPE_HID;
lpddi->wUsagePage = 0x01; /* Desktop */ lpddi->wUsagePage = 0x01; /* Desktop */
lpddi->wUsage = 0x05; /* Game Pad */ if (joydevs[id].is_joystick)
lpddi->wUsage = 0x04; /* Joystick */
else
lpddi->wUsage = 0x05; /* Game Pad */
} }
MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH); MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
......
...@@ -945,6 +945,7 @@ static DWORD make_vid_pid(IOHIDDeviceRef device) ...@@ -945,6 +945,7 @@ static DWORD make_vid_pid(IOHIDDeviceRef device)
static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
{ {
IOHIDDeviceRef device; IOHIDDeviceRef device;
BOOL is_joystick;
TRACE("dwDevType %u dwFlags 0x%08x version 0x%04x id %d\n", dwDevType, dwFlags, version, id); TRACE("dwDevType %u dwFlags 0x%08x version 0x%04x id %d\n", dwDevType, dwFlags, version, id);
...@@ -962,15 +963,19 @@ static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS ...@@ -962,15 +963,19 @@ static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS
if(get_ff(device, NULL) != S_OK) if(get_ff(device, NULL) != S_OK)
return S_FALSE; return S_FALSE;
} }
is_joystick = get_device_property_long(device, CFSTR(kIOHIDDeviceUsageKey)) == kHIDUsage_GD_Joystick;
/* Return joystick */ /* Return joystick */
lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID; lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
lpddi->guidInstance.Data3 = id; lpddi->guidInstance.Data3 = id;
lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID; lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
lpddi->guidProduct.Data1 = make_vid_pid(device); lpddi->guidProduct.Data1 = make_vid_pid(device);
lpddi->dwDevType = get_device_type(version); lpddi->dwDevType = get_device_type(version, is_joystick);
lpddi->dwDevType |= DIDEVTYPE_HID; lpddi->dwDevType |= DIDEVTYPE_HID;
lpddi->wUsagePage = 0x01; /* Desktop */ lpddi->wUsagePage = 0x01; /* Desktop */
lpddi->wUsage = 0x05; /* Game Pad */ if (is_joystick)
lpddi->wUsage = 0x04; /* Joystick */
else
lpddi->wUsage = 0x05; /* Game Pad */
sprintf(lpddi->tszInstanceName, "Joystick %d", id); sprintf(lpddi->tszInstanceName, "Joystick %d", id);
/* get the device name */ /* get the device name */
...@@ -988,6 +993,7 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS ...@@ -988,6 +993,7 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS
char name[MAX_PATH]; char name[MAX_PATH];
char friendly[32]; char friendly[32];
IOHIDDeviceRef device; IOHIDDeviceRef device;
BOOL is_joystick;
TRACE("dwDevType %u dwFlags 0x%08x version 0x%04x id %d\n", dwDevType, dwFlags, version, id); TRACE("dwDevType %u dwFlags 0x%08x version 0x%04x id %d\n", dwDevType, dwFlags, version, id);
...@@ -1005,14 +1011,22 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS ...@@ -1005,14 +1011,22 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS
if(get_ff(device, NULL) != S_OK) if(get_ff(device, NULL) != S_OK)
return S_FALSE; return S_FALSE;
} }
is_joystick = get_device_property_long(device, CFSTR(kIOHIDDeviceUsageKey)) == kHIDUsage_GD_Joystick;
/* Return joystick */ /* Return joystick */
lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID; lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
lpddi->guidInstance.Data3 = id; lpddi->guidInstance.Data3 = id;
lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID; lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
lpddi->guidProduct.Data1 = make_vid_pid(device); lpddi->guidProduct.Data1 = make_vid_pid(device);
lpddi->dwDevType = get_device_type(version); lpddi->dwDevType = get_device_type(version, is_joystick);
lpddi->dwDevType |= DIDEVTYPE_HID;
lpddi->wUsagePage = 0x01; /* Desktop */
if (is_joystick)
lpddi->wUsage = 0x04; /* Joystick */
else
lpddi->wUsage = 0x05; /* Game Pad */
sprintf(friendly, "Joystick %d", id); sprintf(friendly, "Joystick %d", id);
MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH); MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
/* get the device name */ /* get the device name */
get_osx_device_name(id, name, MAX_PATH); get_osx_device_name(id, name, MAX_PATH);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment