From 6e476e77a3be854681162ade2488496eed6ff1ca Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 28 Jan 2018 10:58:39 +0100 Subject: [PATCH] input: support imitation SNES USB gamepad on Windows --- panda/src/device/winInputDeviceManager.cxx | 9 +++- panda/src/device/winRawInputDevice.cxx | 53 ++++++++++++++++------ 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/panda/src/device/winInputDeviceManager.cxx b/panda/src/device/winInputDeviceManager.cxx index 124229b5ea..8d3d0c769a 100644 --- a/panda/src/device/winInputDeviceManager.cxx +++ b/panda/src/device/winInputDeviceManager.cxx @@ -245,8 +245,15 @@ on_input_device_arrival(HANDLE handle) { if (dev_class == "HIDClass" && _CM_Get_DevNode_PropertyW != nullptr && _CM_Get_DevNode_PropertyW(cur, &bus_reported_device_desc, &type, (PBYTE)buffer, &buflen, 0) == CR_SUCCESS && type == DEVPROP_TYPE_STRING) { + + // Some devices insert quite some trailing space here. + wchar_t *wbuffer = (wchar_t *)buffer; + size_t wlen = wcslen(wbuffer); + while (iswspace(wbuffer[wlen - 1])) { + wbuffer[--wlen] = 0; + } TextEncoder encoder; - name.assign(encoder.encode_wtext((wchar_t *)buffer)); + name.assign(encoder.encode_wtext(wstring(wbuffer, wlen))); break; } else { buflen = 4096; diff --git a/panda/src/device/winRawInputDevice.cxx b/panda/src/device/winRawInputDevice.cxx index 68e8e89bf3..391140eb31 100644 --- a/panda/src/device/winRawInputDevice.cxx +++ b/panda/src/device/winRawInputDevice.cxx @@ -265,6 +265,11 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, string name) { info.hid.usUsage == HID_USAGE_GENERIC_JOYSTICK) { _device_class = DC_flight_stick; + if (_name == "usb gamepad") { + // Well, it claims to be a gamepad... + _device_class = DC_gamepad; + } + // Mice } else if (info.hid.usUsagePage == HID_USAGE_PAGE_GENERIC && info.hid.usUsage == HID_USAGE_GENERIC_MOUSE) { @@ -320,6 +325,39 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, string name) { return false; } + // Do we have a button mapping? + static const ButtonHandle gamepad_buttons_common[] = { + ButtonHandle::none(), + GamepadButton::action_a(), + GamepadButton::action_b(), + GamepadButton::action_x(), + GamepadButton::action_y(), + GamepadButton::lshoulder(), + GamepadButton::rshoulder(), + GamepadButton::start(), + GamepadButton::back(), + GamepadButton::lstick(), + GamepadButton::rstick(), + }; + const ButtonHandle *gamepad_buttons = gamepad_buttons_common; + if (_vendor_id == 0x0810 && _product_id == 0xe501) { + // SNES-style USB gamepad + static const ButtonHandle gamepad_buttons_snes[] = { + ButtonHandle::none(), + GamepadButton::action_x(), + GamepadButton::action_a(), + GamepadButton::action_b(), + GamepadButton::action_y(), + GamepadButton::lshoulder(), + GamepadButton::rshoulder(), + ButtonHandle::none(), + ButtonHandle::none(), + GamepadButton::back(), + GamepadButton::start(), + }; + gamepad_buttons = gamepad_buttons_snes; + } + // Prepare a mapping of data indices to button/control indices. _indices.resize(caps.NumberInputDataIndices); @@ -369,20 +407,7 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, string name) { switch (cap.UsagePage) { case HID_USAGE_PAGE_BUTTON: if (_device_class == DC_gamepad) { - static const ButtonHandle gamepad_buttons[] = { - ButtonHandle::none(), - GamepadButton::action_a(), - GamepadButton::action_b(), - GamepadButton::action_x(), - GamepadButton::action_y(), - GamepadButton::lshoulder(), - GamepadButton::rshoulder(), - GamepadButton::start(), - GamepadButton::back(), - GamepadButton::lstick(), - GamepadButton::rstick(), - }; - if (usage < sizeof(gamepad_buttons) / sizeof(ButtonHandle)) { + if (usage < sizeof(gamepad_buttons_common) / sizeof(ButtonHandle)) { handle = gamepad_buttons[usage]; } } else if (_device_class == DC_flight_stick) {