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
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 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)
......
......@@ -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) :
DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8);
}
......
......@@ -84,6 +84,8 @@ struct JoyDev
int *dev_axes_map;
WORD vendor_id, product_id, bus_type;
BOOL is_joystick;
};
typedef struct JoystickImpl JoystickImpl;
......@@ -177,6 +179,7 @@ static INT find_joystick_devices(void)
int fd;
struct JoyDev joydev, *new_joydevs;
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);
if ((fd = open(joydev.device, O_RDONLY)) == -1)
......@@ -220,6 +223,42 @@ static INT find_joystick_devices(void)
joydev.button_count = 2;
#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)
{
WARN("ioctl(%s,JSIOCGAXMAP) failed: %s\n", joydev.device, strerror(errno));
......@@ -322,7 +361,7 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver
lpddi->guidInstance = DInput_Wine_Joystick_GUID;
lpddi->guidInstance.Data3 = id;
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 */
if (joystick_devices[id].bus_type == BUS_USB &&
......@@ -330,7 +369,10 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver
{
lpddi->dwDevType |= DIDEVTYPE_HID;
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);
......
......@@ -100,7 +100,7 @@ struct JoyDev {
GUID guid;
GUID guid_product;
BOOL has_ff;
BOOL has_ff, is_joystick;
int num_effects;
/* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */
......@@ -243,6 +243,24 @@ static void find_joydevs(void)
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)))
{
close(fd);
......@@ -350,7 +368,7 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver
lpddi->guidInstance = joydevs[id].guid;
lpddi->guidProduct = joydevs[id].guid_product;
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 */
if (joydevs[id].bus_type == BUS_USB &&
......@@ -358,7 +376,10 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver
{
lpddi->dwDevType |= DIDEVTYPE_HID;
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);
......
......@@ -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)
{
IOHIDDeviceRef device;
BOOL is_joystick;
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
if(get_ff(device, NULL) != S_OK)
return S_FALSE;
}
is_joystick = get_device_property_long(device, CFSTR(kIOHIDDeviceUsageKey)) == kHIDUsage_GD_Joystick;
/* Return joystick */
lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
lpddi->guidInstance.Data3 = id;
lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
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 */
lpddi->wUsage = 0x05; /* Game Pad */
if (is_joystick)
lpddi->wUsage = 0x04; /* Joystick */
else
lpddi->wUsage = 0x05; /* Game Pad */
sprintf(lpddi->tszInstanceName, "Joystick %d", id);
/* get the device name */
......@@ -988,6 +993,7 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS
char name[MAX_PATH];
char friendly[32];
IOHIDDeviceRef device;
BOOL is_joystick;
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
if(get_ff(device, NULL) != S_OK)
return S_FALSE;
}
is_joystick = get_device_property_long(device, CFSTR(kIOHIDDeviceUsageKey)) == kHIDUsage_GD_Joystick;
/* Return joystick */
lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
lpddi->guidInstance.Data3 = id;
lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
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);
MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
/* get the device name */
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