From 3f0fc05a3e8ea623638b759db40c68949b1aad14 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 24 Oct 2017 02:54:32 +0200 Subject: [PATCH] Input: finish work on remapping evdev and some more crap --- rpcs3/Emu/Io/PadHandler.h | 4 +- rpcs3/ds4_pad_handler.cpp | 37 +- rpcs3/ds4_pad_handler.h | 11 +- rpcs3/evdev_joystick_handler.cpp | 421 +++++++++------------ rpcs3/evdev_joystick_handler.h | 394 ++++++++++--------- rpcs3/keyboard_pad_handler.cpp | 6 - rpcs3/keyboard_pad_handler.h | 1 - rpcs3/rpcs3qt/gamepads_settings_dialog.cpp | 115 +++--- rpcs3/rpcs3qt/gamepads_settings_dialog.h | 1 - rpcs3/rpcs3qt/pad_settings_dialog.cpp | 24 +- rpcs3/rpcs3qt/pad_settings_dialog.h | 5 +- rpcs3/rpcs3qt/pad_settings_dialog.ui | 5 +- rpcs3/xinput_pad_handler.cpp | 37 +- rpcs3/xinput_pad_handler.h | 3 +- 14 files changed, 528 insertions(+), 536 deletions(-) diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index 166c73067783..7f900df6bb8e 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -469,9 +469,9 @@ class PadHandlerBase bool has_config() { return b_has_config; }; bool has_rumble() { return b_has_rumble; }; bool has_deadzones() { return b_has_deadzones; }; + pad_config* GetConfig() { return &m_pad_config; }; //Sets window to config the controller(optional) - virtual void ConfigController(const std::string& device) {}; - virtual void GetNextButtonPress(const std::string& padId, const std::function& callback) {}; + virtual void GetNextButtonPress(const std::string& padId, const std::vector& deadzones, const std::function& callback) {}; virtual void TranslateButtonPress(u32 keyCode, bool& pressed, u16& value, bool ignore_threshold = false) {}; virtual void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) {}; //Return list of devices for that handler diff --git a/rpcs3/ds4_pad_handler.cpp b/rpcs3/ds4_pad_handler.cpp index ad7b3d6a04e3..bc00db228605 100644 --- a/rpcs3/ds4_pad_handler.cpp +++ b/rpcs3/ds4_pad_handler.cpp @@ -156,25 +156,24 @@ ds4_pad_handler::ds4_pad_handler() : is_init(false) b_has_deadzones = true; } -void ds4_pad_handler::ConfigController(const std::string& device) -{ - pad_settings_dialog dlg(&m_pad_config, device, *this); - dlg.exec(); -} - -void ds4_pad_handler::GetNextButtonPress(const std::string& padid, const std::function& callback) +void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::vector& deadzones, const std::function& callback) { if (!Init()) { return; } + int ltriggerthreshold = deadzones[0]; + int rtriggerthreshold = deadzones[1]; + int lstickdeadzone = deadzones[2]; + int rstickdeadzone = deadzones[3]; + // Get the DS4 Device or return if none found - size_t pos = padid.find("Ds4 Pad #"); + size_t pos = padId.find("Ds4 Pad #"); if (pos == std::string::npos) return; - std::string pad_serial = padid.substr(pos + 9); + std::string pad_serial = padId.substr(pos + 9); std::shared_ptr device = nullptr; @@ -207,20 +206,30 @@ void ds4_pad_handler::GetNextButtonPress(const std::string& padid, const std::fu // Check for each button in our list if its corresponding (maybe remapped) button or axis was pressed. // Return the new value if the button was pressed (aka. its value was bigger than 0 or the defined threshold) + // Use a pair to get all the legally pressed buttons and use the one with highest value (prioritize first) + std::pair pressed_button = { 0, "" }; for (const auto& button : button_list) { u32 keycode = button.first; u16 value = data[keycode]; if (((keycode < DS4KeyCodes::L2) && (value > 0)) - || ((keycode == DS4KeyCodes::L2) && (value > m_pad_config.ltriggerthreshold)) - || ((keycode == DS4KeyCodes::R2) && (value > m_pad_config.rtriggerthreshold)) - || ((keycode >= DS4KeyCodes::LSXNeg && keycode <= DS4KeyCodes::LSYPos) && (value > m_pad_config.lstickdeadzone)) - || ((keycode >= DS4KeyCodes::RSXNeg && keycode <= DS4KeyCodes::RSYPos) && (value > m_pad_config.rstickdeadzone))) + || ((keycode == DS4KeyCodes::L2) && (value > ltriggerthreshold)) + || ((keycode == DS4KeyCodes::R2) && (value > rtriggerthreshold)) + || ((keycode >= DS4KeyCodes::LSXNeg && keycode <= DS4KeyCodes::LSYPos) && (value > lstickdeadzone)) + || ((keycode >= DS4KeyCodes::RSXNeg && keycode <= DS4KeyCodes::RSYPos) && (value > rstickdeadzone))) { - return callback(button.second); + if (value > pressed_button.first) + { + pressed_button = { value, button.second}; + } } } + if (pressed_button.first > 0) + { + LOG_NOTICE(HLE, "GetNextButtonPress: %s button %s pressed with value %d", m_pad_config.cfg_type, pressed_button.second, pressed_button.first); + return callback(pressed_button.second); + } } void ds4_pad_handler::TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) diff --git a/rpcs3/ds4_pad_handler.h b/rpcs3/ds4_pad_handler.h index 36976e5d0fdd..b891a597d418 100644 --- a/rpcs3/ds4_pad_handler.h +++ b/rpcs3/ds4_pad_handler.h @@ -22,16 +22,16 @@ class ds4_pad_handler final : public PadHandlerBase Up, Down, R1, - R2, + R3, L1, - L2, + L3, Share, Options, PSButton, TouchPad, - L3, - R3, + L2, + R2, LSXNeg, LSXPos, @@ -135,8 +135,7 @@ class ds4_pad_handler final : public PadHandlerBase std::vector ListDevices() override; bool bindPadToDevice(std::shared_ptr pad, const std::string& device) override; void ThreadProc() override; - void ConfigController(const std::string& device) override; - void GetNextButtonPress(const std::string& padid, const std::function& buttonCallback) override; + void GetNextButtonPress(const std::string& padId, const std::vector& deadzones, const std::function& buttonCallback) override; void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override; void TranslateButtonPress(u32 keyCode, bool& pressed, u16& value, bool ignore_threshold = false) override; diff --git a/rpcs3/evdev_joystick_handler.cpp b/rpcs3/evdev_joystick_handler.cpp index 2b82378b4b0b..8094ae4a74a7 100644 --- a/rpcs3/evdev_joystick_handler.cpp +++ b/rpcs3/evdev_joystick_handler.cpp @@ -32,35 +32,35 @@ evdev_joystick_handler::evdev_joystick_handler() m_pad_config.cfg_name = fs::get_config_dir() + "/config_evdev.yml"; // Set default button mapping - m_pad_config.ls_left.def = rev_axis_list.at(EvdevAxisCodes::ABS_X); - m_pad_config.ls_down.def = rev_axis_list.at(EvdevAxisCodes::ABS_Y); - m_pad_config.ls_right.def = axis_list.at(EvdevAxisCodes::ABS_X); - m_pad_config.ls_up.def = axis_list.at(EvdevAxisCodes::ABS_Y); - m_pad_config.rs_left.def = rev_axis_list.at(EvdevAxisCodes::ABS_RX); - m_pad_config.rs_down.def = rev_axis_list.at(EvdevAxisCodes::ABS_RY); - m_pad_config.rs_right.def = axis_list.at(EvdevAxisCodes::ABS_RX); - m_pad_config.rs_up.def = axis_list.at(EvdevAxisCodes::ABS_RY); - m_pad_config.start.def = button_list.at(EvdevKeyCodes::BTN_START); - m_pad_config.select.def = button_list.at(EvdevKeyCodes::BTN_SELECT); - m_pad_config.ps.def = button_list.at(EvdevKeyCodes::BTN_GAMEPAD); - m_pad_config.square.def = button_list.at(EvdevKeyCodes::BTN_X); - m_pad_config.cross.def = button_list.at(EvdevKeyCodes::BTN_A); - m_pad_config.circle.def = button_list.at(EvdevKeyCodes::BTN_B); - m_pad_config.triangle.def = button_list.at(EvdevKeyCodes::BTN_Y); - m_pad_config.left.def = rev_axis_list.at(EvdevAxisCodes::ABS_HAT0X); - m_pad_config.down.def = rev_axis_list.at(EvdevAxisCodes::ABS_HAT0Y); - m_pad_config.right.def = rev_axis_list.at(EvdevAxisCodes::ABS_HAT0X); - m_pad_config.up.def = rev_axis_list.at(EvdevAxisCodes::ABS_HAT0Y); - m_pad_config.r1.def = button_list.at(EvdevKeyCodes::BTN_TR); - m_pad_config.r2.def = axis_list.at(EvdevAxisCodes::ABS_Z); - m_pad_config.r3.def = button_list.at(EvdevKeyCodes::BTN_THUMB); - m_pad_config.l1.def = button_list.at(EvdevKeyCodes::BTN_TL); - m_pad_config.l2.def = axis_list.at(EvdevAxisCodes::ABS_RZ); - m_pad_config.l3.def = button_list.at(EvdevKeyCodes::BTN_THUMB2); + m_pad_config.ls_left.def = rev_axis_list.at(ABS_X); + m_pad_config.ls_down.def = rev_axis_list.at(ABS_Y); + m_pad_config.ls_right.def = axis_list.at(ABS_X); + m_pad_config.ls_up.def = axis_list.at(ABS_Y); + m_pad_config.rs_left.def = rev_axis_list.at(ABS_RX); + m_pad_config.rs_down.def = rev_axis_list.at(ABS_RY); + m_pad_config.rs_right.def = axis_list.at(ABS_RX); + m_pad_config.rs_up.def = axis_list.at(ABS_RY); + m_pad_config.start.def = button_list.at(BTN_START); + m_pad_config.select.def = button_list.at(BTN_SELECT); + m_pad_config.ps.def = button_list.at(BTN_MODE); + m_pad_config.square.def = button_list.at(BTN_X); + m_pad_config.cross.def = button_list.at(BTN_A); + m_pad_config.circle.def = button_list.at(BTN_B); + m_pad_config.triangle.def = button_list.at(BTN_Y); + m_pad_config.left.def = rev_axis_list.at(ABS_HAT0X); + m_pad_config.down.def = rev_axis_list.at(ABS_HAT0Y); + m_pad_config.right.def = axis_list.at(ABS_HAT0X); + m_pad_config.up.def = axis_list.at(ABS_HAT0Y); + m_pad_config.r1.def = button_list.at(BTN_TR); + m_pad_config.r2.def = axis_list.at(ABS_RZ); + m_pad_config.r3.def = button_list.at(BTN_THUMBR); + m_pad_config.l1.def = button_list.at(BTN_TL); + m_pad_config.l2.def = axis_list.at(ABS_Z); + m_pad_config.l3.def = button_list.at(BTN_THUMBL); // Set default misc variables - m_pad_config.lstickdeadzone.def = 10; // between 0 and 255 - m_pad_config.rstickdeadzone.def = 10; // between 0 and 255 + m_pad_config.lstickdeadzone.def = 30; // between 0 and 255 + m_pad_config.rstickdeadzone.def = 30; // between 0 and 255 m_pad_config.ltriggerthreshold.def = 0; // between 0 and 255 m_pad_config.rtriggerthreshold.def = 0; // between 0 and 255 m_pad_config.padsquircling.def = 5000; @@ -85,102 +85,76 @@ bool evdev_joystick_handler::Init() return true; } -void evdev_joystick_handler::update_devs() +bool evdev_joystick_handler::update_device(EvdevDevice device, bool use_cell) { - for (u32 index = 0; index < joy_devs.size(); ++index) - { - libevdev*& dev = joy_devs[index]; - bool was_connected = dev != nullptr; + std::shared_ptr pad = device.pad; + const auto& path = device.path; + libevdev*& dev = device.device; - if (index >= joy_paths.size()) return false; - const auto& path = joy_paths[index]; + bool was_connected = dev != nullptr; - if (access(path.c_str(), R_OK) == -1) + if (access(path.c_str(), R_OK) == -1) + { + if (was_connected) { - if (was_connected) - { - // It was disconnected. - pads[index]->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; + // It was disconnected. + if (use_cell) pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; - int fd = libevdev_get_fd(dev); - libevdev_free(dev); - close(fd); - dev = nullptr; - } - pads[index]->m_port_status &= ~CELL_PAD_STATUS_CONNECTED; - LOG_ERROR(GENERAL, "Joystick %s is not present or accessible [previous status: %d]", path.c_str(), - was_connected ? 1 : 0); - return false; + int fd = libevdev_get_fd(dev); + libevdev_free(dev); + close(fd); + dev = nullptr; } - if (was_connected) return true; // It's already been connected, and the js is still present. - int fd = open(path.c_str(), O_RDONLY | O_NONBLOCK); + if (use_cell) pad->m_port_status &= ~CELL_PAD_STATUS_CONNECTED; + LOG_ERROR(GENERAL, "Joystick %s is not present or accessible [previous status: %d]", path.c_str(), + was_connected ? 1 : 0); + return false; + } - if (fd == -1) - { - int err = errno; - LOG_ERROR(GENERAL, "Failed to open joystick #%d: %s [errno %d]", index, strerror(err), err); - return false; - } + if (was_connected) return true; // It's already been connected, and the js is still present. + int fd = open(path.c_str(), O_RDONLY | O_NONBLOCK); - int ret = libevdev_new_from_fd(fd, &dev); - if (ret < 0) - { - LOG_ERROR(GENERAL, "Failed to initialize libevdev for joystick #%d: %s [errno %d]", index, strerror(-ret), -ret); - return false; - } + if (fd == -1) + { + int err = errno; + LOG_ERROR(GENERAL, "Failed to open joystick: %s [errno %d]", strerror(err), err); + return false; + } - LOG_NOTICE(GENERAL, "Opened joystick #%d '%s' at %s (fd %d)", index, libevdev_get_name(dev), path, fd); + int ret = libevdev_new_from_fd(fd, &dev); + if (ret < 0) + { + LOG_ERROR(GENERAL, "Failed to initialize libevdev for joystick: %s [errno %d]", strerror(-ret), -ret); + return false; + } + + LOG_NOTICE(GENERAL, "Opened joystick: '%s' at %s (fd %d)", libevdev_get_name(dev), path, fd); + if (use_cell) + { if (!was_connected) // Connection status changed from disconnected to connected. - pads[index]->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; - pads[index]->m_port_status |= CELL_PAD_STATUS_CONNECTED; - - //int buttons = 0; - //for (u32 i = BTN_JOYSTICK; i < KEY_MAX; i++) - //{ - // if (libevdev_has_event_code(dev, EV_KEY, i)) - // { - // LOG_NOTICE(GENERAL, "Joystick #%d has button %d as %d", index, i, buttons); - // joy_button_maps[index][i - BTN_MISC] = buttons++; - // } - //} - - //int axes = 0; - //for (u32 i = ABS_X; i <= ABS_RZ; i++) - //{ - // if (libevdev_has_event_code(dev, EV_ABS, i)) - // { - // LOG_NOTICE(GENERAL, "Joystick #%d has axis %d as %d", index, i, axes); - // - // axis_ranges[i].first = libevdev_get_abs_minimum(dev, i); - // axis_ranges[i].second = libevdev_get_abs_maximum(dev, i); - // - // // Skip ABS_Z and ABS_RZ on controllers where it's used for the triggers. - // if (m_pad_config.has_axis_triggers && (i == ABS_Z || i == ABS_RZ)) continue; - // joy_axis_maps[index][i - ABS_X] = axes++; - // } - //} - - //for (u32 i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) - //{ - // if (libevdev_has_event_code(dev, EV_ABS, i) || - // libevdev_has_event_code(dev, EV_ABS, i + 1)) - // { - // LOG_NOTICE(GENERAL, "Joystick #%d has hat %d", index, i); - // joy_hat_ids[index] = i - ABS_HAT0X; - // } - //} - - return true; + pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; + pad->m_port_status |= CELL_PAD_STATUS_CONNECTED; + } + + return true; +} + +void evdev_joystick_handler::update_devs(bool use_cell) +{ + for (auto& device : devices) + { + update_device(device, use_cell); } } void evdev_joystick_handler::Close() { - for (auto& dev : joy_devs) + for (auto& device : devices) { + auto& dev = device.device; if (dev != nullptr) { int fd = libevdev_get_fd(dev); @@ -190,31 +164,16 @@ void evdev_joystick_handler::Close() } } -void evdev_joystick_handler::ConfigController(const std::string& device) +void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const std::vector& deadzones, const std::function& callback) { - pad_settings_dialog dlg(&m_pad_config, device, *this); - dlg.exec(); -} - -void evdev_joystick_handler::GetNextButtonPress(const std::string& padid, const std::function& callback) -{ - u32 device_number = 0; - size_t pos = padid.find("evdev Pad #"); - - if (pos != std::string::npos) - { - device_number = std::stoul(padid.substr(pos + 11)); - } - - if (pos == std::string::npos || device_number >= MAX_GAMEPADS) - { - return; - } + // Add device if not yet present + int index = add_device(padId); + if (index < 0) return; - update_devs(); + // Check if our device is connected + if (!update_device(devices[index], false)) return; - auto& dev = joy_devs[device_number]; - if (dev == nullptr) return; + auto& dev = devices[index].device; // Try to query the latest event from the joystick. input_event evt; @@ -225,26 +184,23 @@ void evdev_joystick_handler::GetNextButtonPress(const std::string& padid, const { ret = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_SYNC, &evt); } - - if (ret < 0) - { - // -EAGAIN signifies no available events, not an actual *error*. - if (ret != -EAGAIN) - LOG_ERROR(GENERAL, "Failed to read latest event from joystick #%d: %s [errno %d]", device_number, strerror(-ret), -ret); - return; - } + if (ret < 0) return; // Get the button info corresponding to our current event bool is_negative = false; int value; - int button_code = GetButtonInfo(evt, device_number, value, is_negative); + int button_code = GetButtonInfo(evt, dev, value, is_negative); + if (button_code == -1) return; - if (button_code == -1) - return; + int ltriggerthreshold = deadzones[0]; + int rtriggerthreshold = deadzones[1]; + int lstickdeadzone = deadzones[2]; + int rstickdeadzone = deadzones[3]; switch (evt.type) { case EV_KEY: + { // handle normal button presses auto button = button_list.find(button_code); if (button == button_list.end()) @@ -254,17 +210,20 @@ void evdev_joystick_handler::GetNextButtonPress(const std::string& padid, const return callback(button->second); return; + } case EV_ABS: + { // handle positive and negative axis movement + std::unordered_map::const_iterator button; if (is_negative) { - auto button = rev_axis_list.find(button_code); + button = rev_axis_list.find(button_code); if (button == rev_axis_list.end()) return; } else { - auto button = axis_list.find(button_code); + button = axis_list.find(button_code); if (button == axis_list.end()) return; } @@ -273,21 +232,21 @@ void evdev_joystick_handler::GetNextButtonPress(const std::string& padid, const switch (button_code) { case ABS_Z: - if (value > m_pad_config.ltriggerthreshold) + if (value > ltriggerthreshold) return callback(button->second); return; case ABS_RZ: - if (value > m_pad_config.rtriggerthreshold) + if (value > rtriggerthreshold) return callback(button->second); return; case ABS_X: case ABS_Y: - if (value > m_pad_config.lstickdeadzone) + if (value > lstickdeadzone) return callback(button->second); return; case ABS_RX: case ABS_RY: - if (value > m_pad_config.rstickdeadzone) + if (value > rstickdeadzone) return callback(button->second); return; default: @@ -295,6 +254,7 @@ void evdev_joystick_handler::GetNextButtonPress(const std::string& padid, const return callback(button->second); return; } + } default: return; } @@ -310,21 +270,21 @@ void evdev_joystick_handler::TranslateButtonPress(u32 keyCode, bool& pressed, u1 // With this you can use axis or triggers as buttons or vice versa switch (keyCode) { - case EvdevAxisCodes::ABS_Z: + case ABS_Z: value = value > (ignore_threshold ? 0 : m_pad_config.ltriggerthreshold) ? value : 0; pressed = value > 0; break; - case EvdevAxisCodes::ABS_RZ: + case ABS_RZ: value = value > (ignore_threshold ? 0 : m_pad_config.rtriggerthreshold) ? value : 0; pressed = value > 0; break; - case EvdevAxisCodes::ABS_X: - case EvdevAxisCodes::ABS_Y: + case ABS_X: + case ABS_Y: value = value > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone) ? value : 0; pressed = value > 0; break; - case EvdevAxisCodes::ABS_RX: - case EvdevAxisCodes::ABS_RY: + case ABS_RX: + case ABS_RY: value = value > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone) ? value : 0; pressed = value > 0; break; @@ -335,13 +295,11 @@ void evdev_joystick_handler::TranslateButtonPress(u32 keyCode, bool& pressed, u1 } } -int evdev_joystick_handler::GetButtonInfo(const input_event& evt, int device_number, int& value, bool& is_negative) +int evdev_joystick_handler::GetButtonInfo(const input_event& evt, libevdev* dev, int& value, bool& is_negative) { int code = evt.code; int val = evt.value; - auto& dev = joy_devs[device_number]; - switch (evt.type) { case EV_KEY: @@ -355,26 +313,22 @@ int evdev_joystick_handler::GetButtonInfo(const input_event& evt, int device_num } case EV_ABS: { - // get the hat value and return its code - if (code >= EvdevAxisCodes::ABS_HAT0X && code <= EvdevAxisCodes::ABS_HAT3Y) - { - is_negative = val < 0; - value = val != 0 ? 255 : 0; - return code; - } - // get the axis value and return its code - else if (code >= EvdevAxisCodes::ABS_X && code <= EvdevAxisCodes::ABS_RZ) + value = NormalizeStickInput(val, 0, libevdev_get_abs_minimum(dev, code), libevdev_get_abs_maximum(dev, code), true); + is_negative = value <= 127; + + if (is_negative) + value = Clamp0To255((127.5f - value) * 2.0f); + else + value = Clamp0To255((value - 127.5f) * 2.0f); + + // choose arbitrary deadzone for hats + if (code >= ABS_HAT0X && code <= ABS_HAT3Y) { - value = NormalizeStickInput(val, 0, libevdev_get_abs_minimum(dev, code), libevdev_get_abs_maximum(dev, code), true); - is_negative = value <= 127; - - if (is_negative) - value = Clamp0To255((127.5f - value) * 2.0f); - else - value = Clamp0To255((value - 127.5f) * 2.0f); - return code; + // Choose one of these depending on how it behaves in test + // value = val > 0 ? 255 : 0; + value = val > 50 ? val : 0; } - return -1; + return code; } default: return -1; @@ -419,64 +373,61 @@ std::vector evdev_joystick_handler::ListDevices() return evdev_joystick_list; } +int evdev_joystick_handler::add_device(const std::string& device, std::shared_ptr pad) +{ + // Now we need to find the device with the same name, and make sure not to grab any duplicates. + fs::dir devdir{ "/dev/input/" }; + fs::dir_entry et; + while (devdir.read(et)) + { + // Check if the entry starts with event (a 5-letter word) + if (et.name.size() > 5 && et.name.compare(0, 5, "event") == 0) + { + std::string path = ""; + int fd = open(("/dev/input/" + et.name).c_str(), O_RDONLY | O_NONBLOCK); + struct libevdev *dev = NULL; + int rc = libevdev_new_from_fd(fd, &dev); + if (rc < 0) + { + // If it's just a bad file descriptor, don't bother logging, but otherwise, log it. + if (rc != -9) + LOG_WARNING(GENERAL, "Failed to connect to device at %s, the error was: %s", "/dev/input/" + et.name, strerror(-rc)); + libevdev_free(dev); + close(fd); + continue; + } + const std::string name = libevdev_get_name(dev); + if (libevdev_has_event_type(dev, EV_KEY) && + libevdev_has_event_code(dev, EV_ABS, ABS_X) && + libevdev_has_event_code(dev, EV_ABS, ABS_Y) && + name == device) + { + // It's a joystick. + + // Now let's make sure we don't already have this one. + auto it = std::find_if(devices.begin(), devices.end(), [path](EvdevDevice device) { return path == device.path; }); + if (it != devices.end()) + { + libevdev_free(dev); + close(fd); + return std::distance(devices.begin(), it); + } + + // Alright, now that we've confirmed we haven't added this joystick yet, les do dis. + devices.push_back({nullptr, fmt::format("/dev/input/%s", et.name), pad }); + return devices.size() - 1; + } + libevdev_free(dev); + close(fd); + } + } + return -1; +} + bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std::string& device) { Init(); - // Now we need to find the device with the same name, and make sure not to grab any duplicates. - fs::dir devdir{"/dev/input/"}; - fs::dir_entry et; - while (devdir.read(et)) - { - // Check if the entry starts with event (a 5-letter word) - if (et.name.size() > 5 && et.name.compare(0, 5,"event") == 0) - { - int fd = open(("/dev/input/" + et.name).c_str(), O_RDONLY|O_NONBLOCK); - struct libevdev *dev = NULL; - int rc = libevdev_new_from_fd(fd, &dev); - if (rc < 0) - { - // If it's just a bad file descriptor, don't bother logging, but otherwise, log it. - if (rc != -9) - LOG_WARNING(GENERAL, "Failed to connect to device at %s, the error was: %s", "/dev/input/" + et.name, strerror(-rc)); - libevdev_free(dev); - close(fd); - continue; - } - const std::string name = libevdev_get_name(dev); - if (libevdev_has_event_type(dev, EV_KEY) && - libevdev_has_event_code(dev, EV_ABS, ABS_X) && - libevdev_has_event_code(dev, EV_ABS, ABS_Y) && - name == device) - { - // It's a joystick. - - // Now let's make sure we don't already have this one. - bool alreadyIn = false; - for (int i = 0; i < joy_paths.size(); i++) - { - if (joy_paths[i] == fmt::format("/dev/input/%s", et.name)) - { - alreadyIn = true; - break; - } - } - - if (alreadyIn == true) - { - libevdev_free(dev); - close(fd); - continue; - } - - // Alright, now that we've confirmed we haven't added this joystick yet, les do dis. - joy_paths.emplace_back(fmt::format("/dev/input/%s", et.name)); - } - libevdev_free(dev); - close(fd); - } - } - auto find_key = [=](const std::string& name) { int key = FindKeyCode(button_list, name); @@ -484,11 +435,11 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std key = FindKeyCode(axis_list, name); if (key < 1) key = FindKeyCode(rev_axis_list, name); + if (key < 1) + key = std::stoi(name); return key; }; - joy_devs.push_back(nullptr); - joy_axis.emplace_back(127, 127, 127, 127); pad->Init( CELL_PAD_STATUS_DISCONNECTED, CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF, @@ -520,7 +471,11 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, find_key(m_pad_config.rs_down), find_key(m_pad_config.rs_up)); pad->m_vibrateMotors.emplace_back(true, 0); pad->m_vibrateMotors.emplace_back(false, 0); - pads.emplace_back(pad); + + if (!add_device(device, pad)) + { + //return; + } update_devs(); return true; } @@ -529,10 +484,10 @@ void evdev_joystick_handler::ThreadProc() { update_devs(); - for (int i = 0; i button_list = { - { EvdevKeyCodes::BTN_0 , "0" }, - { EvdevKeyCodes::BTN_1 , "1" }, - { EvdevKeyCodes::BTN_2 , "2" }, - { EvdevKeyCodes::BTN_3 , "3" }, - { EvdevKeyCodes::BTN_4 , "4" }, - { EvdevKeyCodes::BTN_5 , "5" }, - { EvdevKeyCodes::BTN_6 , "6" }, - { EvdevKeyCodes::BTN_7 , "7" }, - { EvdevKeyCodes::BTN_8 , "8" }, - { EvdevKeyCodes::BTN_9 , "9" }, - { EvdevKeyCodes::BTN_MOUSE , "Mouse" }, - { EvdevKeyCodes::BTN_LEFT , "Left" }, - { EvdevKeyCodes::BTN_RIGHT , "Right" }, - { EvdevKeyCodes::BTN_MIDDLE , "Middle" }, - { EvdevKeyCodes::BTN_SIDE , "Side" }, - { EvdevKeyCodes::BTN_EXTRA , "Extra" }, - { EvdevKeyCodes::BTN_FORWARD , "Forward" }, - { EvdevKeyCodes::BTN_BACK , "Back" }, - { EvdevKeyCodes::BTN_JOYSTICK, "Joystick" }, - { EvdevKeyCodes::BTN_TRIGGER , "Trgigger" }, - { EvdevKeyCodes::BTN_THUMB , "Thumb" }, - { EvdevKeyCodes::BTN_THUMB2 , "Thumb 2" }, - { EvdevKeyCodes::BTN_TOP , "Top" }, - { EvdevKeyCodes::BTN_TOP2 , "Top 2" }, - { EvdevKeyCodes::BTN_PINKIE , "Pinkie" }, - { EvdevKeyCodes::BTN_BASE , "Base" }, - { EvdevKeyCodes::BTN_BASE2 , "Base 2" }, - { EvdevKeyCodes::BTN_BASE3 , "Base 3" }, - { EvdevKeyCodes::BTN_BASE4 , "Base 4" }, - { EvdevKeyCodes::BTN_BASE5 , "Base 5" }, - { EvdevKeyCodes::BTN_BASE6 , "Base 6" }, - { EvdevKeyCodes::BTN_GAMEPAD , "Gamepad" }, - { EvdevKeyCodes::BTN_A , "A" }, - { EvdevKeyCodes::BTN_B , "B" }, - { EvdevKeyCodes::BTN_C , "C" }, - { EvdevKeyCodes::BTN_X , "X" }, - { EvdevKeyCodes::BTN_Y , "Y" }, - { EvdevKeyCodes::BTN_Z , "Z" }, - { EvdevKeyCodes::BTN_TL , "TL" }, - { EvdevKeyCodes::BTN_TR , "TR" }, - { EvdevKeyCodes::BTN_TL2 , "TL 2" }, - { EvdevKeyCodes::BTN_TR2 , "TR 2" }, - { EvdevKeyCodes::BTN_SELECT , "Select" }, - { EvdevKeyCodes::BTN_START , "Start" }, - { EvdevKeyCodes::BTN_MODE , "Mode" } + //{ BTN_MISC , "Misc" }, same as BTN_0 + { BTN_0 , "0" }, + { BTN_1 , "1" }, + { BTN_2 , "2" }, + { BTN_3 , "3" }, + { BTN_4 , "4" }, + { BTN_5 , "5" }, + { BTN_6 , "6" }, + { BTN_7 , "7" }, + { BTN_8 , "8" }, + { BTN_9 , "9" }, + //{ BTN_MOUSE , "Mouse" }, same as BTN_LEFT + { BTN_LEFT , "Left" }, + { BTN_RIGHT , "Right" }, + { BTN_MIDDLE , "Middle" }, + { BTN_SIDE , "Side" }, + { BTN_EXTRA , "Extra" }, + { BTN_FORWARD , "Forward" }, + { BTN_BACK , "Back" }, + { BTN_TASK , "Task" }, + { BTN_JOYSTICK , "Joystick" }, + { BTN_TRIGGER , "Trigger" }, + { BTN_THUMB , "Thumb" }, + { BTN_THUMB2 , "Thumb 2" }, + { BTN_TOP , "Top" }, + { BTN_TOP2 , "Top 2" }, + { BTN_PINKIE , "Pinkie" }, + { BTN_BASE , "Base" }, + { BTN_BASE2 , "Base 2" }, + { BTN_BASE3 , "Base 3" }, + { BTN_BASE4 , "Base 4" }, + { BTN_BASE5 , "Base 5" }, + { BTN_BASE6 , "Base 6" }, + { BTN_DEAD , "Dead" }, + //{ BTN_GAMEPAD , "Gamepad" }, same as BTN_A + //{ BTN_SOUTH , "South" }, same as BTN_A + { BTN_A , "A" }, + //{ BTN_EAST , "South" }, same as BTN_B + { BTN_B , "B" }, + { BTN_C , "C" }, + //{ BTN_NORTH , "North" }, same as BTN_X + { BTN_X , "X" }, + //{ BTN_WEST , "West" }, same as BTN_Y + { BTN_Y , "Y" }, + { BTN_Z , "Z" }, + { BTN_TL , "TL" }, + { BTN_TR , "TR" }, + { BTN_TL2 , "TL 2" }, + { BTN_TR2 , "TR 2" }, + { BTN_SELECT , "Select" }, + { BTN_START , "Start" }, + { BTN_MODE , "Mode" }, + { BTN_THUMBL , "Thumb L" }, + { BTN_THUMBR , "Thumb R" }, + //{ BTN_DIGI , "Digi" }, same as BTN_TOOL_PEN + { BTN_TOOL_PEN , "Pen" }, + { BTN_TOOL_RUBBER , "Rubber" }, + { BTN_TOOL_BRUSH , "Brush" }, + { BTN_TOOL_PENCIL , "Pencil" }, + { BTN_TOOL_AIRBRUSH , "Airbrush" }, + { BTN_TOOL_FINGER , "Finger" }, + { BTN_TOOL_MOUSE , "Mouse" }, + { BTN_TOOL_LENS , "Lense" }, + { BTN_TOOL_QUINTTAP , "Quinttap" }, + { BTN_TOUCH , "Touch" }, + { BTN_STYLUS , "Stylus" }, + { BTN_STYLUS2 , "Stylus 2" }, + { BTN_TOOL_DOUBLETAP , "Doubletap" }, + { BTN_TOOL_TRIPLETAP , "Tripletap" }, + { BTN_TOOL_QUADTAP , "Quadtap" }, + //{ BTN_WHEEL , "Wheel" }, same as BTN_GEAR_DOWN + { BTN_GEAR_DOWN , "Gear Up" }, + { BTN_GEAR_UP , "Gear Down" }, + { BTN_DPAD_UP , "D-Pad Up" }, + { BTN_DPAD_DOWN , "D-Pad Down" }, + { BTN_DPAD_LEFT , "D-Pad Left" }, + { BTN_DPAD_RIGHT , "D-Pad Right" }, + { BTN_TRIGGER_HAPPY , "Happy" }, + { BTN_TRIGGER_HAPPY1 , "Happy 1" }, + { BTN_TRIGGER_HAPPY2 , "Happy 2" }, + { BTN_TRIGGER_HAPPY3 , "Happy 3" }, + { BTN_TRIGGER_HAPPY4 , "Happy 4" }, + { BTN_TRIGGER_HAPPY5 , "Happy 5" }, + { BTN_TRIGGER_HAPPY6 , "Happy 6" }, + { BTN_TRIGGER_HAPPY7 , "Happy 7" }, + { BTN_TRIGGER_HAPPY8 , "Happy 8" }, + { BTN_TRIGGER_HAPPY9 , "Happy 9" }, + { BTN_TRIGGER_HAPPY10 , "Happy 10" }, + { BTN_TRIGGER_HAPPY11 , "Happy 11" }, + { BTN_TRIGGER_HAPPY12 , "Happy 12" }, + { BTN_TRIGGER_HAPPY13 , "Happy 13" }, + { BTN_TRIGGER_HAPPY14 , "Happy 14" }, + { BTN_TRIGGER_HAPPY15 , "Happy 15" }, + { BTN_TRIGGER_HAPPY16 , "Happy 16" }, + { BTN_TRIGGER_HAPPY17 , "Happy 17" }, + { BTN_TRIGGER_HAPPY18 , "Happy 18" }, + { BTN_TRIGGER_HAPPY19 , "Happy 19" }, + { BTN_TRIGGER_HAPPY20 , "Happy 20" }, + { BTN_TRIGGER_HAPPY21 , "Happy 21" }, + { BTN_TRIGGER_HAPPY22 , "Happy 22" }, + { BTN_TRIGGER_HAPPY23 , "Happy 23" }, + { BTN_TRIGGER_HAPPY24 , "Happy 24" }, + { BTN_TRIGGER_HAPPY25 , "Happy 25" }, + { BTN_TRIGGER_HAPPY26 , "Happy 26" }, + { BTN_TRIGGER_HAPPY27 , "Happy 27" }, + { BTN_TRIGGER_HAPPY28 , "Happy 28" }, + { BTN_TRIGGER_HAPPY29 , "Happy 29" }, + { BTN_TRIGGER_HAPPY30 , "Happy 30" }, + { BTN_TRIGGER_HAPPY31 , "Happy 31" }, + { BTN_TRIGGER_HAPPY32 , "Happy 32" }, + { BTN_TRIGGER_HAPPY33 , "Happy 33" }, + { BTN_TRIGGER_HAPPY34 , "Happy 34" }, + { BTN_TRIGGER_HAPPY35 , "Happy 35" }, + { BTN_TRIGGER_HAPPY36 , "Happy 36" }, + { BTN_TRIGGER_HAPPY37 , "Happy 37" }, + { BTN_TRIGGER_HAPPY38 , "Happy 38" }, + { BTN_TRIGGER_HAPPY39 , "Happy 39" }, + { BTN_TRIGGER_HAPPY40 , "Happy 40" }, }; // Unique positive axis names for the config files and our pad settings dialog const std::unordered_map axis_list = { - { EvdevAxisCodes::ABS_X , "LX +" }, - { EvdevAxisCodes::ABS_Y , "LY +" }, - { EvdevAxisCodes::ABS_Z , "LZ +" }, - { EvdevAxisCodes::ABS_RX , "RX +" }, - { EvdevAxisCodes::ABS_RY , "RY +" }, - { EvdevAxisCodes::ABS_RZ , "RZ +" }, - { EvdevAxisCodes::ABS_THROTTLE , "Throttle +" }, - { EvdevAxisCodes::ABS_RUDDER , "Rudder +" }, - { EvdevAxisCodes::ABS_WHEEL , "Wheel +" }, - { EvdevAxisCodes::ABS_GAS , "Gas +" }, - { EvdevAxisCodes::ABS_BRAKE , "Brake +" }, - { EvdevAxisCodes::ABS_HAT0X , "Hat0 X +" }, - { EvdevAxisCodes::ABS_HAT0Y , "Hat0 Y +" }, - { EvdevAxisCodes::ABS_HAT1X , "Hat1 X +" }, - { EvdevAxisCodes::ABS_HAT1Y , "Hat1 Y +" }, - { EvdevAxisCodes::ABS_HAT2X , "Hat2 X +" }, - { EvdevAxisCodes::ABS_HAT2Y , "Hat2 Y +" }, - { EvdevAxisCodes::ABS_HAT3X , "Hat3 X +" }, - { EvdevAxisCodes::ABS_HAT3Y , "Hat3 Y +" }, - { EvdevAxisCodes::ABS_PRESSURE , "Pressure +" }, - { EvdevAxisCodes::ABS_DISTANCE , "Distance +" }, - { EvdevAxisCodes::ABS_TILT_X , "Tilt X +" }, - { EvdevAxisCodes::ABS_TILT_Y , "Tilt Y +" }, - { EvdevAxisCodes::ABS_MISC , "Misc +" } + { ABS_X , "LX+" }, + { ABS_Y , "LY+" }, + { ABS_Z , "LZ+" }, + { ABS_RX , "RX+" }, + { ABS_RY , "RY+" }, + { ABS_RZ , "RZ+" }, + { ABS_THROTTLE , "Throttle+" }, + { ABS_RUDDER , "Rudder+" }, + { ABS_WHEEL , "Wheel+" }, + { ABS_GAS , "Gas+" }, + { ABS_BRAKE , "Brake+" }, + { ABS_HAT0X , "Hat0 X+" }, + { ABS_HAT0Y , "Hat0 Y+" }, + { ABS_HAT1X , "Hat1 X+" }, + { ABS_HAT1Y , "Hat1 Y+" }, + { ABS_HAT2X , "Hat2 X+" }, + { ABS_HAT2Y , "Hat2 Y+" }, + { ABS_HAT3X , "Hat3 X+" }, + { ABS_HAT3Y , "Hat3 Y+" }, + { ABS_PRESSURE , "Pressure+" }, + { ABS_DISTANCE , "Distance+" }, + { ABS_TILT_X , "Tilt X+" }, + { ABS_TILT_Y , "Tilt Y+" }, + { ABS_TOOL_WIDTH , "Width+" }, + { ABS_VOLUME , "Volume+" }, + { ABS_MISC , "Misc+" }, + { ABS_MT_SLOT , "Slot+" }, + { ABS_MT_TOUCH_MAJOR , "MT TMaj+" }, + { ABS_MT_TOUCH_MINOR , "MT TMin+" }, + { ABS_MT_WIDTH_MAJOR , "MT WMaj+" }, + { ABS_MT_WIDTH_MINOR , "MT WMin+" }, + { ABS_MT_ORIENTATION , "MT Orient+" }, + { ABS_MT_POSITION_X , "MT PosX+" }, + { ABS_MT_POSITION_Y , "MT PosY+" }, + { ABS_MT_TOOL_TYPE , "MT TType+" }, + { ABS_MT_BLOB_ID , "MT Blob ID+" }, + { ABS_MT_TRACKING_ID , "MT Track ID+" }, + { ABS_MT_PRESSURE , "MT Pressure+" }, + { ABS_MT_DISTANCE , "MT Distance+" }, + { ABS_MT_TOOL_X , "MT Tool X+" }, + { ABS_MT_TOOL_Y , "MT Tool Y+" }, }; // Unique negative axis names for the config files and our pad settings dialog const std::unordered_map rev_axis_list = { - { EvdevAxisCodes::ABS_X , "LX -" }, - { EvdevAxisCodes::ABS_Y , "LY -" }, - { EvdevAxisCodes::ABS_Z , "LZ -" }, - { EvdevAxisCodes::ABS_RX , "RX -" }, - { EvdevAxisCodes::ABS_RY , "RY -" }, - { EvdevAxisCodes::ABS_RZ , "RZ -" }, - { EvdevAxisCodes::ABS_THROTTLE , "Throttle -" }, - { EvdevAxisCodes::ABS_RUDDER , "Rudder -" }, - { EvdevAxisCodes::ABS_WHEEL , "Wheel -" }, - { EvdevAxisCodes::ABS_GAS , "Gas -" }, - { EvdevAxisCodes::ABS_BRAKE , "Brake -" }, - { EvdevAxisCodes::ABS_HAT0X , "Hat0 X -" }, - { EvdevAxisCodes::ABS_HAT0Y , "Hat0 Y -" }, - { EvdevAxisCodes::ABS_HAT1X , "Hat1 X -" }, - { EvdevAxisCodes::ABS_HAT1Y , "Hat1 Y -" }, - { EvdevAxisCodes::ABS_HAT2X , "Hat2 X -" }, - { EvdevAxisCodes::ABS_HAT2Y , "Hat2 Y -" }, - { EvdevAxisCodes::ABS_HAT3X , "Hat3 X -" }, - { EvdevAxisCodes::ABS_HAT3Y , "Hat3 Y -" }, - { EvdevAxisCodes::ABS_PRESSURE , "Pressure -" }, - { EvdevAxisCodes::ABS_DISTANCE , "Distance -" }, - { EvdevAxisCodes::ABS_TILT_X , "Tilt X -" }, - { EvdevAxisCodes::ABS_TILT_Y , "Tilt Y -" }, - { EvdevAxisCodes::ABS_MISC , "Misc -" } + { ABS_X , "LX-" }, + { ABS_Y , "LY-" }, + { ABS_Z , "LZ-" }, + { ABS_RX , "RX-" }, + { ABS_RY , "RY-" }, + { ABS_RZ , "RZ-" }, + { ABS_THROTTLE , "Throttle-" }, + { ABS_RUDDER , "Rudder-" }, + { ABS_WHEEL , "Wheel-" }, + { ABS_GAS , "Gas-" }, + { ABS_BRAKE , "Brake-" }, + { ABS_HAT0X , "Hat0 X-" }, + { ABS_HAT0Y , "Hat0 Y-" }, + { ABS_HAT1X , "Hat1 X-" }, + { ABS_HAT1Y , "Hat1 Y-" }, + { ABS_HAT2X , "Hat2 X-" }, + { ABS_HAT2Y , "Hat2 Y-" }, + { ABS_HAT3X , "Hat3 X-" }, + { ABS_HAT3Y , "Hat3 Y-" }, + { ABS_PRESSURE , "Pressure-" }, + { ABS_DISTANCE , "Distance-" }, + { ABS_TILT_X , "Tilt X-" }, + { ABS_TILT_Y , "Tilt Y-" }, + { ABS_TOOL_WIDTH , "Width-" }, + { ABS_VOLUME , "Volume-" }, + { ABS_MISC , "Misc-" }, + { ABS_MT_SLOT , "Slot-" }, + { ABS_MT_TOUCH_MAJOR , "MT TMaj-" }, + { ABS_MT_TOUCH_MINOR , "MT TMin-" }, + { ABS_MT_WIDTH_MAJOR , "MT WMaj-" }, + { ABS_MT_WIDTH_MINOR , "MT WMin-" }, + { ABS_MT_ORIENTATION , "MT Orient-" }, + { ABS_MT_POSITION_X , "MT PosX-" }, + { ABS_MT_POSITION_Y , "MT PosY-" }, + { ABS_MT_TOOL_TYPE , "MT TType-" }, + { ABS_MT_BLOB_ID , "MT Blob ID-" }, + { ABS_MT_TRACKING_ID , "MT Track ID-" }, + { ABS_MT_PRESSURE , "MT Pressure-" }, + { ABS_MT_DISTANCE , "MT Distance-" }, + { ABS_MT_TOOL_X , "MT Tool X-" }, + { ABS_MT_TOOL_Y , "MT Tool Y-" }, + }; + + struct EvdevDevice + { + libevdev* device; + std::string path; + std::shared_ptr pad; }; public: @@ -208,16 +241,15 @@ class evdev_joystick_handler final : public PadHandlerBase bool bindPadToDevice(std::shared_ptr pad, const std::string& device) override; void ThreadProc() override; void Close(); - void ConfigController(const std::string& device) override; - void GetNextButtonPress(const std::string& padid, const std::function& callback) override; + void GetNextButtonPress(const std::string& padId, const std::vector& deadzones, const std::function& callback) override; void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override; void TranslateButtonPress(u32 keyCode, bool& pressed, u16& value, bool ignore_threshold = false) override; private: - void update_devs(); - int GetButtonInfo(const input_event& evt, int device_number, int& button_code, bool& is_negative); + bool update_device(EvdevDevice device, bool use_cell = true); + void update_devs(bool use_cell = true); + int add_device(const std::string& device, std::shared_ptr pad = nullptr); + int GetButtonInfo(const input_event& evt, libevdev* dev, int& button_code, bool& is_negative); - std::vector joy_paths; - std::vector> pads; - std::vector joy_devs; + std::vector devices; }; diff --git a/rpcs3/keyboard_pad_handler.cpp b/rpcs3/keyboard_pad_handler.cpp index c99b834fcbd6..b0f787b0743f 100644 --- a/rpcs3/keyboard_pad_handler.cpp +++ b/rpcs3/keyboard_pad_handler.cpp @@ -54,12 +54,6 @@ keyboard_pad_handler::keyboard_pad_handler() : QObject() b_has_config = true; } -void keyboard_pad_handler::ConfigController(const std::string& device) -{ - pad_settings_dialog dlg(&m_pad_config, device, *this); - dlg.exec(); -} - void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value) { for (auto pad : bindings) diff --git a/rpcs3/keyboard_pad_handler.h b/rpcs3/keyboard_pad_handler.h index 119f3ee0069a..2fb0525a941c 100644 --- a/rpcs3/keyboard_pad_handler.h +++ b/rpcs3/keyboard_pad_handler.h @@ -24,7 +24,6 @@ class keyboard_pad_handler final : public QObject, public PadHandlerBase std::vector ListDevices() override; bool bindPadToDevice(std::shared_ptr pad, const std::string& device) override; void ThreadProc() override; - void ConfigController(const std::string& device) override; const std::string GetKeyName(const QKeyEvent* keyEvent); const std::string GetKeyName(const u32& keyCode); diff --git a/rpcs3/rpcs3qt/gamepads_settings_dialog.cpp b/rpcs3/rpcs3qt/gamepads_settings_dialog.cpp index 6f0718af9728..6f6efdb8a529 100644 --- a/rpcs3/rpcs3qt/gamepads_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/gamepads_settings_dialog.cpp @@ -1,4 +1,5 @@ #include "gamepads_settings_dialog.h" +#include "pad_settings_dialog.h" #include "../Emu/Io/PadHandler.h" #include "../ds4_pad_handler.h" #ifdef _WIN32 @@ -16,6 +17,9 @@ input_config input_cfg; +inline std::string sstr(const QString& _in) { return _in.toUtf8().toStdString(); } +constexpr auto qstr = QString::fromStdString; + // taken from https://stackoverflow.com/a/30818424/8353754 // because size policies won't work as expected (see similar bugs in Qt bugtracker) inline void resizeComboBoxView(QComboBox* combo) @@ -54,43 +58,6 @@ gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent) input_cfg.from_default(); input_cfg.load(); - auto fill_device_combo = [](QComboBox *combo) - { - std::vector str_inputs = input_cfg.player_input[0].to_list(); - for (int index = 0; index < str_inputs.size(); index++) - { - combo->addItem(str_inputs[index].c_str()); - } - resizeComboBoxView(combo); - }; - - auto configure_combos = [=] - { - //Set the values from config - for (int i = 0; i < MAX_PLAYERS; i++) - { - for (int j = 0; j < co_inputtype[i]->count(); j++) - { - if (co_inputtype[i]->itemText(j).toStdString() == input_cfg.player_input[i].to_string()) - { - co_inputtype[i]->setCurrentIndex(j); - ChangeInputType(i); - break; - } - } - - for (int j = 0; j < co_deviceID[i]->count(); j++) - { - if (co_deviceID[i]->itemText(j).toStdString() == input_cfg.player_device[i]->to_string()) - { - co_deviceID[i]->setCurrentIndex(j); - ChangeDevice(i); - break; - } - } - } - }; - for (int i = 0; i < MAX_PLAYERS; i++) { QGroupBox *grp_player = new QGroupBox(QString(tr("Player %1").arg(i+1))); @@ -126,7 +93,12 @@ gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent) grp_player->setFixedSize(grp_player->sizeHint()); // fill comboboxes after setting the groupbox's size to prevent stretch - fill_device_combo(co_inputtype[i]); + std::vector str_inputs = input_cfg.player_input[0].to_list(); + for (int index = 0; index < str_inputs.size(); index++) + { + co_inputtype[i]->addItem(qstr(str_inputs[index])); + } + resizeComboBoxView(co_inputtype[i]); all_players->addWidget(grp_player); @@ -154,17 +126,38 @@ gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent) setLayout(dialog_layout); layout()->setSizeConstraint(QLayout::SetFixedSize); - configure_combos(); + auto configure_combos = [=] + { + //Set the values from config + for (int i = 0; i < MAX_PLAYERS; i++) + { + // No extra loops are necessary because setCurrentText does it for us + co_inputtype[i]->setCurrentText(qstr(input_cfg.player_input[i].to_string())); + // Device will be empty on some rare occasions, so fill them by force + ChangeInputType(i); + } + }; for (int i = 0; i < MAX_PLAYERS; i++) { connect(co_inputtype[i], &QComboBox::currentTextChanged, [=] { ChangeInputType(i); }); - connect(co_deviceID[i], &QComboBox::currentTextChanged, [=] { ChangeDevice(i); }); + connect(co_deviceID[i], &QComboBox::currentTextChanged, [=](const QString& dev) + { + std::string device = sstr(dev); + if (!input_cfg.player_device[i]->from_string(device)) + { + //Something went wrong + LOG_ERROR(GENERAL, "Failed to convert device string: %s", device); + return; + } + }); connect(bu_config[i], &QAbstractButton::clicked, [=] { ClickConfigButton(i); }); } connect(ok_button, &QPushButton::pressed, this, &gamepads_settings_dialog::SaveExit); connect(cancel_button, &QPushButton::pressed, this, &gamepads_settings_dialog::CancelExit); connect(refresh_button, &QPushButton::pressed, [=] { configure_combos(); }); + + configure_combos(); } void gamepads_settings_dialog::SaveExit() @@ -193,20 +186,6 @@ void gamepads_settings_dialog::CancelExit() QDialog::accept(); } -void gamepads_settings_dialog::ChangeDevice(int player) -{ - bool success; - - success = input_cfg.player_device[player]->from_string(co_deviceID[player]->currentText().toStdString()); - - if (!success) - { - //Something went wrong - LOG_ERROR(GENERAL, "Failed to convert device string:%s", co_deviceID[player]->currentText().toStdString().c_str()); - return; - } -} - std::shared_ptr gamepads_settings_dialog::GetHandler(pad_handler type) { std::shared_ptr ret_handler; @@ -244,24 +223,28 @@ std::shared_ptr gamepads_settings_dialog::GetHandler(pad_handler void gamepads_settings_dialog::ChangeInputType(int player) { - bool success; + std::string device = sstr(co_inputtype[player]->currentText()); - success = input_cfg.player_input[player].from_string(co_inputtype[player]->currentText().toStdString()); - - if (!success) + // Change this player's current handler + if (!input_cfg.player_input[player].from_string(device)) { //Something went wrong - LOG_ERROR(GENERAL, "Failed to convert input string:%s", co_inputtype[player]->currentText().toStdString().c_str()); + LOG_ERROR(GENERAL, "Failed to convert input string:%s", device); return; } + // Get this player's current handler and it's currently available devices std::shared_ptr cur_pad_handler = GetHandler(input_cfg.player_input[player]); - std::vector list_devices = cur_pad_handler->ListDevices(); + // Refill the device combobox with currently available devices co_deviceID[player]->clear(); - for (int i = 0; i < list_devices.size(); i++) co_deviceID[player]->addItem(list_devices[i].c_str(), i); + for (int i = 0; i < list_devices.size(); i++) + { + co_deviceID[player]->addItem(qstr(list_devices[i]), i); + } + // Handle empty device list if (list_devices.size() == 0) { co_deviceID[player]->addItem(tr("No Device Detected"), -1); @@ -270,14 +253,22 @@ void gamepads_settings_dialog::ChangeInputType(int player) else { co_deviceID[player]->setEnabled(true); + co_deviceID[player]->setCurrentText(qstr(device)); } + // Update view and enable configuration if possible resizeComboBoxView(co_deviceID[player]); bu_config[player]->setEnabled(cur_pad_handler->has_config()); } void gamepads_settings_dialog::ClickConfigButton(int player) { + // Get this player's current handler and open its pad settings dialog std::shared_ptr cur_pad_handler = GetHandler(input_cfg.player_input[player]); - if (cur_pad_handler->has_config()) cur_pad_handler->ConfigController(*input_cfg.player_device[player]); + if (cur_pad_handler->has_config()) + { + std::string device = sstr(co_deviceID[player]->currentText()); + pad_settings_dialog dlg(device, cur_pad_handler); + dlg.exec(); + } } diff --git a/rpcs3/rpcs3qt/gamepads_settings_dialog.h b/rpcs3/rpcs3qt/gamepads_settings_dialog.h index 4355db6703ac..08ff5c7e85c0 100644 --- a/rpcs3/rpcs3qt/gamepads_settings_dialog.h +++ b/rpcs3/rpcs3qt/gamepads_settings_dialog.h @@ -65,7 +65,6 @@ class gamepads_settings_dialog : public QDialog protected: std::shared_ptr GetHandler(pad_handler type); void ChangeInputType(int player); - void ChangeDevice(int player); void ClickConfigButton(int player); void SaveExit(); void CancelExit(); diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index 5dc475b042db..d2a998ea0c6d 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -12,8 +12,8 @@ inline std::string sstr(const QString& _in) { return _in.toUtf8().toStdString(); } constexpr auto qstr = QString::fromStdString; -pad_settings_dialog::pad_settings_dialog(pad_config* pad_cfg, const std::string& device, PadHandlerBase& handler, QWidget *parent) - : QDialog(parent), ui(new Ui::pad_settings_dialog), m_handler_cfg(pad_cfg), m_device_name(device), m_handler(&handler) +pad_settings_dialog::pad_settings_dialog(const std::string& device, std::shared_ptr handler, QWidget *parent) + : QDialog(parent), ui(new Ui::pad_settings_dialog), m_handler_cfg(handler->GetConfig()), m_device_name(device), m_handler(handler) { m_handler_cfg->load(); @@ -64,7 +64,6 @@ pad_settings_dialog::pad_settings_dialog(pad_config* pad_cfg, const std::string& // Use timer to get button input const auto& callback = [=](std::string name) { - LOG_NOTICE(GENERAL, "Pad Settings: %s button %s pressed (0x%x)", m_handler_cfg->cfg_type, name); m_cfg_entries[m_button_id].key = name; m_cfg_entries[m_button_id].text = qstr(name); ReactivateButtons(); @@ -74,11 +73,18 @@ pad_settings_dialog::pad_settings_dialog(pad_config* pad_cfg, const std::string& { if (m_button_id > id_pad_begin && m_button_id < id_pad_end) { - m_handler->GetNextButtonPress(m_device_name, callback); + std::vector deadzones = + { + ui->slider_trigger_left->value(), + ui->slider_trigger_right->value(), + ui->slider_stick_left->value(), + ui->slider_stick_right->value() + }; + m_handler->GetNextButtonPress(m_device_name, deadzones, callback); } }); - m_timer_input.start(10); + m_timer_input.start(2); }; // Enable Vibration Checkboxes @@ -178,6 +184,7 @@ pad_settings_dialog::pad_settings_dialog(pad_config* pad_cfg, const std::string& insertButton(id_pad_start, ui->b_start, &m_handler_cfg->start); insertButton(id_pad_select, ui->b_select, &m_handler_cfg->select); + insertButton(id_pad_ps, ui->b_ps, &m_handler_cfg->ps); insertButton(id_pad_r1, ui->b_shift_r1, &m_handler_cfg->r1); insertButton(id_pad_r2, ui->b_shift_r2, &m_handler_cfg->r2); @@ -258,7 +265,7 @@ void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent) } else { - m_cfg_entries[m_button_id].key = ((keyboard_pad_handler*)m_handler)->GetKeyName(keyEvent); + m_cfg_entries[m_button_id].key = ((keyboard_pad_handler*)m_handler.get())->GetKeyName(keyEvent); m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key); } @@ -293,9 +300,9 @@ void pad_settings_dialog::UpdateLabel(bool is_reset) void pad_settings_dialog::SwitchButtons(bool is_enabled) { - for (const auto& button : m_padButtons->buttons()) + for (int i = id_pad_begin + 1; i < id_pad_end; i++) { - button->setEnabled(is_enabled); + m_padButtons->button(i)->setEnabled(is_enabled); } } @@ -324,6 +331,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id) case id_cancel: return; case id_reset_parameters: + ReactivateButtons(); m_handler_cfg->from_default(); UpdateLabel(true); return; diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.h b/rpcs3/rpcs3qt/pad_settings_dialog.h index 776b2caec9c8..ccfe42f9cb4b 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/pad_settings_dialog.h @@ -39,6 +39,7 @@ enum button_ids id_pad_start, id_pad_select, + id_pad_ps, id_pad_r1, id_pad_r2, @@ -101,7 +102,7 @@ private Q_SLOTS: QPalette m_palette; // Pad Handlers - PadHandlerBase* m_handler; + std::shared_ptr m_handler; handler_type m_handler_type; pad_config* m_handler_cfg; std::string m_device_name; @@ -118,7 +119,7 @@ private Q_SLOTS: void ReactivateButtons(); public: - explicit pad_settings_dialog(pad_config* pad_cfg, const std::string& device, PadHandlerBase& handler, QWidget *parent = nullptr); + explicit pad_settings_dialog(const std::string& device, std::shared_ptr handler, QWidget *parent = nullptr); ~pad_settings_dialog(); /** Handle keyboard handler input */ diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.ui b/rpcs3/rpcs3qt/pad_settings_dialog.ui index bf7041e3d9be..4282f21eddae 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.ui +++ b/rpcs3/rpcs3qt/pad_settings_dialog.ui @@ -844,11 +844,8 @@ - - false - - Null + Backspace false diff --git a/rpcs3/xinput_pad_handler.cpp b/rpcs3/xinput_pad_handler.cpp index e224332b8597..5c135149f31d 100644 --- a/rpcs3/xinput_pad_handler.cpp +++ b/rpcs3/xinput_pad_handler.cpp @@ -65,15 +65,20 @@ xinput_pad_handler::~xinput_pad_handler() Close(); } -void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std::function& callback) +void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std::vector& deadzones, const std::function& callback) { if (!Init()) { return; } - u32 device_number = 0; + int ltriggerthreshold = deadzones[0]; + int rtriggerthreshold = deadzones[1]; + int lstickdeadzone = deadzones[2]; + int rstickdeadzone = deadzones[3]; + size_t pos = padId.find("Xinput Pad #"); + int device_number; if (pos != std::string::npos) { @@ -84,7 +89,7 @@ void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std: { return; } - + DWORD dwResult; XINPUT_STATE state; ZeroMemory(&state, sizeof(XINPUT_STATE)); @@ -99,6 +104,8 @@ void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std: // Check for each button in our list if its corresponding (maybe remapped) button or axis was pressed. // Return the new value if the button was pressed (aka. its value was bigger than 0 or the defined threshold) + // Use a pair to get all the legally pressed buttons and use the one with highest value (prioritize first) + std::pair pressed_button = { 0, "" }; auto data = GetButtonValues(state); for (const auto& button : button_list) { @@ -106,14 +113,22 @@ void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std: u16 value = data[keycode]; if (((keycode < XInputKeyCodes::LT) && (value > 0)) - || ((keycode == XInputKeyCodes::LT) && (value > m_pad_config.ltriggerthreshold)) - || ((keycode == XInputKeyCodes::RT) && (value > m_pad_config.rtriggerthreshold)) - || ((keycode >= XInputKeyCodes::LSXNeg && keycode <= XInputKeyCodes::LSYPos) && (value > m_pad_config.lstickdeadzone)) - || ((keycode >= XInputKeyCodes::RSXNeg && keycode <= XInputKeyCodes::RSYPos) && (value > m_pad_config.rstickdeadzone))) + || ((keycode == XInputKeyCodes::LT) && (value > ltriggerthreshold)) + || ((keycode == XInputKeyCodes::RT) && (value > rtriggerthreshold)) + || ((keycode >= XInputKeyCodes::LSXNeg && keycode <= XInputKeyCodes::LSYPos) && (value > lstickdeadzone)) + || ((keycode >= XInputKeyCodes::RSXNeg && keycode <= XInputKeyCodes::RSYPos) && (value > rstickdeadzone))) { - return callback(button.second); + if (value > pressed_button.first) + { + pressed_button = { value, button.second }; + } } } + if (pressed_button.first > 0) + { + LOG_NOTICE(HLE, "GetNextButtonPress: %s button %s pressed with value %d", m_pad_config.cfg_type, pressed_button.second, pressed_button.first); + return callback(pressed_button.second); + } } void xinput_pad_handler::TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) @@ -243,12 +258,6 @@ std::array xinput_pad_han return values; } -void xinput_pad_handler::ConfigController(const std::string& device) -{ - pad_settings_dialog dlg(&m_pad_config, device, *this); - dlg.exec(); -} - bool xinput_pad_handler::Init() { if (is_init) return true; diff --git a/rpcs3/xinput_pad_handler.h b/rpcs3/xinput_pad_handler.h index ba07fc4ff0e1..8135ca17abc5 100644 --- a/rpcs3/xinput_pad_handler.h +++ b/rpcs3/xinput_pad_handler.h @@ -99,8 +99,7 @@ class xinput_pad_handler final : public PadHandlerBase std::vector ListDevices() override; bool bindPadToDevice(std::shared_ptr pad, const std::string& device) override; void ThreadProc() override; - void ConfigController(const std::string& device) override; - void GetNextButtonPress(const std::string& padid, const std::function& callback) override; + void GetNextButtonPress(const std::string& padId, const std::vector& deadzones, const std::function& callback) override; void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override; void TranslateButtonPress(u32 keyCode, bool& pressed, u16& value, bool ignore_threshold = false) override;