Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47123 Signed-off-by: Andrew Eikum aeikum@codeweavers.com ---
Applies on top of Alistair's series.
dlls/dinput/dinput_private.h | 2 +- dlls/dinput/joystick.c | 6 +++- dlls/dinput/joystick_linux.c | 46 +++++++++++++++++++++++++++++-- dlls/dinput/joystick_linuxinput.c | 27 ++++++++++++++++-- dlls/dinput/joystick_osx.c | 20 ++++++++++++-- 5 files changed, 91 insertions(+), 10 deletions(-)
diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index c97a49334ad..289b2f1f63d 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -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)
diff --git a/dlls/dinput/joystick.c b/dlls/dinput/joystick.c index 5129bb85457..8b3edb2c540 100644 --- a/dlls/dinput/joystick.c +++ b/dlls/dinput/joystick.c @@ -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); } diff --git a/dlls/dinput/joystick_linux.c b/dlls/dinput/joystick_linux.c index 2644ed66a4e..b708db3e81c 100644 --- a/dlls/dinput/joystick_linux.c +++ b/dlls/dinput/joystick_linux.c @@ -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); diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c index c742c151c7a..d4512dc5ec1 100644 --- a/dlls/dinput/joystick_linuxinput.c +++ b/dlls/dinput/joystick_linuxinput.c @@ -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); diff --git a/dlls/dinput/joystick_osx.c b/dlls/dinput/joystick_osx.c index aad60765cfb..a448818bb9c 100644 --- a/dlls/dinput/joystick_osx.c +++ b/dlls/dinput/joystick_osx.c @@ -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);