From 459414840976a8e999b3ed40600444d26587df28 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Fri, 20 Sep 2019 16:28:55 +0200 Subject: [PATCH] Input: move some pad handler logic to the parent class --- Utilities/Config.h | 7 + rpcs3/Emu/Io/PadHandler.cpp | 342 ++++++++++++++- rpcs3/Emu/Io/PadHandler.h | 107 +++-- rpcs3/ds3_pad_handler.cpp | 409 +++++++++--------- rpcs3/ds3_pad_handler.h | 53 +-- rpcs3/ds4_pad_handler.cpp | 594 ++++++++++---------------- rpcs3/ds4_pad_handler.h | 62 +-- rpcs3/evdev_joystick_handler.cpp | 573 +++++++++++++------------ rpcs3/evdev_joystick_handler.h | 38 +- rpcs3/keyboard_pad_handler.cpp | 2 +- rpcs3/keyboard_pad_handler.h | 2 +- rpcs3/main_application.cpp | 2 +- rpcs3/mm_joystick_handler.cpp | 296 +++++-------- rpcs3/mm_joystick_handler.h | 27 +- rpcs3/pad_thread.cpp | 6 +- rpcs3/rpcs3qt/pad_settings_dialog.cpp | 18 +- rpcs3/rpcs3qt/pad_settings_dialog.h | 2 +- rpcs3/xinput_pad_handler.cpp | 541 ++++++++--------------- rpcs3/xinput_pad_handler.h | 95 ++-- 19 files changed, 1574 insertions(+), 1602 deletions(-) diff --git a/Utilities/Config.h b/Utilities/Config.h index 1997fd1b3a..e05e692db5 100644 --- a/Utilities/Config.h +++ b/Utilities/Config.h @@ -298,6 +298,7 @@ namespace cfg // Simple string entry with mutex class string final : public _base { + std::string m_name; std::string m_value; public: @@ -305,6 +306,7 @@ namespace cfg string(node* owner, const std::string& name, const std::string& def = {}) : _base(type::string, owner, name) + , m_name(name) , m_value(def) , def(def) { @@ -320,6 +322,11 @@ namespace cfg return m_value; } + std::string get_name() const + { + return m_name; + } + std::size_t size() const { return m_value.size(); diff --git a/rpcs3/Emu/Io/PadHandler.cpp b/rpcs3/Emu/Io/PadHandler.cpp index 596fd7d2d6..2561e570b2 100644 --- a/rpcs3/Emu/Io/PadHandler.cpp +++ b/rpcs3/Emu/Io/PadHandler.cpp @@ -2,6 +2,10 @@ #include "PadHandler.h" #include "pad_thread.h" +#ifdef _WIN32 +#include +#endif + cfg_input g_cfg_input; PadHandlerBase::PadHandlerBase(pad_handler type) : m_type(type) @@ -9,7 +13,7 @@ PadHandlerBase::PadHandlerBase(pad_handler type) : m_type(type) } // Search an unordered map for a string value and return found keycode -int PadHandlerBase::FindKeyCode(std::unordered_map map, const cfg::string& name, bool fallback) +int PadHandlerBase::FindKeyCode(const std::unordered_map& map, const cfg::string& name, bool fallback) { std::string def = name.def; std::string nam = name.to_string(); @@ -34,7 +38,7 @@ int PadHandlerBase::FindKeyCode(std::unordered_map map, const return def_code; } -long PadHandlerBase::FindKeyCode(std::unordered_map map, const cfg::string& name, bool fallback) +long PadHandlerBase::FindKeyCode(const std::unordered_map& map, const cfg::string& name, bool fallback) { std::string def = name.def; std::string nam = name.to_string(); @@ -60,7 +64,7 @@ long PadHandlerBase::FindKeyCode(std::unordered_map map, const } // Search an unordered map for a string value and return found keycode -int PadHandlerBase::FindKeyCodeByString(std::unordered_map map, const std::string& name, bool fallback) +int PadHandlerBase::FindKeyCodeByString(const std::unordered_map& map, const std::string& name, bool fallback) { for (auto it = map.begin(); it != map.end(); ++it) { @@ -70,7 +74,7 @@ int PadHandlerBase::FindKeyCodeByString(std::unordered_map map if (fallback) { - LOG_ERROR(HLE, "long FindKeyCodeByString fohr [name = %s] returned with 0", name); + LOG_ERROR(HLE, "long FindKeyCodeByString for [name = %s] returned with 0", name); return 0; } @@ -78,7 +82,7 @@ int PadHandlerBase::FindKeyCodeByString(std::unordered_map map } // Search an unordered map for a string value and return found keycode -long PadHandlerBase::FindKeyCodeByString(std::unordered_map map, const std::string& name, bool fallback) +long PadHandlerBase::FindKeyCodeByString(const std::unordered_map& map, const std::string& name, bool fallback) { for (auto it = map.begin(); it != map.end(); ++it) { @@ -88,7 +92,7 @@ long PadHandlerBase::FindKeyCodeByString(std::unordered_map ma if (fallback) { - LOG_ERROR(HLE, "long FindKeyCodeByString fohr [name = %s] returned with 0", name); + LOG_ERROR(HLE, "long FindKeyCodeByString for [name = %s] returned with 0", name); return 0; } @@ -246,7 +250,7 @@ std::string PadHandlerBase::name_string() return m_name_string; } -int PadHandlerBase::max_devices() +size_t PadHandlerBase::max_devices() { return m_max_devices; } @@ -306,3 +310,327 @@ void PadHandlerBase::init_configs() } } } + +void PadHandlerBase::get_next_button_press(const std::string& pad_id, const std::function)>& callback, const std::function& fail_callback, bool get_blacklist, const std::vector& /*buttons*/) +{ + if (get_blacklist) + blacklist.clear(); + + auto device = get_device(pad_id); + + const auto status = update_connection(device); + if (status == connection::disconnected) + return fail_callback(pad_id); + else if (status == connection::no_data) + return; + + // Get the current button values + auto data = get_button_values(device); + + // 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 (!get_blacklist && std::find(blacklist.begin(), blacklist.end(), keycode) != blacklist.end()) + continue; + + const bool is_trigger = get_is_left_trigger(keycode) || get_is_right_trigger(keycode); + const bool is_stick = !is_trigger && (get_is_left_stick(keycode) || get_is_right_stick(keycode)); + const bool is_button = !is_trigger && !is_stick; + + if ((is_trigger && (value > m_trigger_threshold)) || (is_stick && (value > m_thumb_threshold)) || (is_button && (value > 0))) + { + if (get_blacklist) + { + blacklist.emplace_back(keycode); + LOG_ERROR(HLE, "%s Calibration: Added key [ %d = %s ] to blacklist. Value = %d", m_type, keycode, button.second, value); + } + else if (value > pressed_button.first) + pressed_button = { value, button.second }; + } + } + + if (get_blacklist) + { + if (blacklist.empty()) + LOG_SUCCESS(HLE, "%s Calibration: Blacklist is clear. No input spam detected", m_type); + return; + } + + const auto preview_values = get_preview_values(data); + + if (pressed_button.first > 0) + return callback(pressed_button.first, pressed_button.second, pad_id, preview_values); + else + return callback(0, "", pad_id, preview_values); + + return; +} + +// Update the pad button values based on their type and thresholds. With this you can use axis or triggers as buttons or vice versa +void PadHandlerBase::TranslateButtonPress(const std::shared_ptr& device, u64 keyCode, bool& pressed, u16& val, bool ignore_stick_threshold, bool ignore_trigger_threshold) +{ + if (!device || !device->config) + { + return; + } + + if (get_is_left_trigger(keyCode)) + { + pressed = val > (ignore_trigger_threshold ? 0 : device->config->ltriggerthreshold); + val = pressed ? NormalizeTriggerInput(val, device->config->ltriggerthreshold) : 0; + } + else if (get_is_right_trigger(keyCode)) + { + pressed = val > (ignore_trigger_threshold ? 0 : device->config->rtriggerthreshold); + val = pressed ? NormalizeTriggerInput(val, device->config->rtriggerthreshold) : 0; + } + else if (get_is_left_stick(keyCode)) + { + pressed = val > (ignore_stick_threshold ? 0 : device->config->lstickdeadzone); + val = pressed ? NormalizeStickInput(val, device->config->lstickdeadzone, device->config->lstickmultiplier, ignore_stick_threshold) : 0; + } + else if (get_is_right_stick(keyCode)) + { + pressed = val > (ignore_stick_threshold ? 0 : device->config->rstickdeadzone); + val = pressed ? NormalizeStickInput(val, device->config->rstickdeadzone, device->config->rstickmultiplier, ignore_stick_threshold) : 0; + } + else // normal button (should in theory also support sensitive buttons) + { + pressed = val > 0; + val = pressed ? val : 0; + } +} + +bool PadHandlerBase::bindPadToDevice(std::shared_ptr pad, const std::string& device) +{ + std::shared_ptr pad_device = get_device(device); + if (!pad_device) + return false; + + int index = static_cast(bindings.size()); + m_pad_configs[index].load(); + pad_device->config = &m_pad_configs[index]; + pad_config* profile = pad_device->config; + if (profile == nullptr) + return false; + + std::array mapping = get_mapped_key_codes(pad_device, profile); + + pad->Init + ( + CELL_PAD_STATUS_DISCONNECTED, + CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE, + CELL_PAD_DEV_TYPE_STANDARD, + profile->device_class_type + ); + + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, mapping[button::up], CELL_PAD_CTRL_UP); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, mapping[button::down], CELL_PAD_CTRL_DOWN); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, mapping[button::left], CELL_PAD_CTRL_LEFT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, mapping[button::right], CELL_PAD_CTRL_RIGHT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, mapping[button::cross], CELL_PAD_CTRL_CROSS); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, mapping[button::square], CELL_PAD_CTRL_SQUARE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, mapping[button::circle], CELL_PAD_CTRL_CIRCLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, mapping[button::triangle], CELL_PAD_CTRL_TRIANGLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, mapping[button::l1], CELL_PAD_CTRL_L1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, mapping[button::l2], CELL_PAD_CTRL_L2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, mapping[button::l3], CELL_PAD_CTRL_L3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, mapping[button::r1], CELL_PAD_CTRL_R1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, mapping[button::r2], CELL_PAD_CTRL_R2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, mapping[button::r3], CELL_PAD_CTRL_R3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, mapping[button::start], CELL_PAD_CTRL_START); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, mapping[button::select], CELL_PAD_CTRL_SELECT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, mapping[button::ps], 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support + //pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved (and currently not in use by rpcs3 at all) + + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, mapping[button::ls_left], mapping[button::ls_right]); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, mapping[button::ls_down], mapping[button::ls_up]); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, mapping[button::rs_left], mapping[button::rs_right]); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, mapping[button::rs_down], mapping[button::rs_up]); + + pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); + pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); + pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 512); + pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 512); + + pad->m_vibrateMotors.emplace_back(true, 0); + pad->m_vibrateMotors.emplace_back(false, 0); + + bindings.emplace_back(pad_device, pad); + + return true; +} + +std::array PadHandlerBase::get_mapped_key_codes(const std::shared_ptr& /*device*/, const pad_config* profile) +{ + std::array mapping; + + mapping[button::up] = FindKeyCode(button_list, profile->up); + mapping[button::down] = FindKeyCode(button_list, profile->down); + mapping[button::left] = FindKeyCode(button_list, profile->left); + mapping[button::right] = FindKeyCode(button_list, profile->right); + mapping[button::cross] = FindKeyCode(button_list, profile->cross); + mapping[button::square] = FindKeyCode(button_list, profile->square); + mapping[button::circle] = FindKeyCode(button_list, profile->circle); + mapping[button::triangle] = FindKeyCode(button_list, profile->triangle); + mapping[button::start] = FindKeyCode(button_list, profile->start); + mapping[button::select] = FindKeyCode(button_list, profile->select); + mapping[button::l1] = FindKeyCode(button_list, profile->l1); + mapping[button::l2] = FindKeyCode(button_list, profile->l2); + mapping[button::l3] = FindKeyCode(button_list, profile->l3); + mapping[button::r1] = FindKeyCode(button_list, profile->r1); + mapping[button::r2] = FindKeyCode(button_list, profile->r2); + mapping[button::r3] = FindKeyCode(button_list, profile->r3); + mapping[button::ls_left] = FindKeyCode(button_list, profile->ls_left); + mapping[button::ls_right] = FindKeyCode(button_list, profile->ls_right); + mapping[button::ls_down] = FindKeyCode(button_list, profile->ls_down); + mapping[button::ls_up] = FindKeyCode(button_list, profile->ls_up); + mapping[button::rs_left] = FindKeyCode(button_list, profile->rs_left); + mapping[button::rs_right] = FindKeyCode(button_list, profile->rs_right); + mapping[button::rs_down] = FindKeyCode(button_list, profile->rs_down); + mapping[button::rs_up] = FindKeyCode(button_list, profile->rs_up); + + return mapping; +} + +void PadHandlerBase::get_mapping(const std::shared_ptr& device, const std::shared_ptr& pad) +{ + if (!device || !pad) + return; + + auto profile = device->config; + + auto button_values = get_button_values(device); + + // Translate any corresponding keycodes to our normal DS3 buttons and triggers + for (auto& btn : pad->m_buttons) + { + btn.m_value = button_values[btn.m_keyCode]; + TranslateButtonPress(device, btn.m_keyCode, btn.m_pressed, btn.m_value); + } + + // used to get the absolute value of an axis + s32 stick_val[4]{ 0 }; + + // Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now) + for (int i = 0; i < static_cast(pad->m_sticks.size()); i++) + { + bool pressed; + + // m_keyCodeMin is the mapped key for left or down + u32 key_min = pad->m_sticks[i].m_keyCodeMin; + u16 val_min = button_values[key_min]; + TranslateButtonPress(device, key_min, pressed, val_min, true); + + // m_keyCodeMax is the mapped key for right or up + u32 key_max = pad->m_sticks[i].m_keyCodeMax; + u16 val_max = button_values[key_max]; + TranslateButtonPress(device, key_max, pressed, val_max, true); + + // cancel out opposing values and get the resulting difference + stick_val[i] = val_max - val_min; + } + + u16 lx, ly, rx, ry; + + // Normalize our two stick's axis based on the thresholds + std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], profile->lstickdeadzone); + std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], profile->rstickdeadzone); + + if (profile->padsquircling != 0) + { + std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling); + std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling); + } + + if (m_type == pad_handler::ds4) + { + ly = 255 - ly; + ry = 255 - ry; + + // these are added with previous value and divided to 'smooth' out the readings + // the ds4 seems to rapidly flicker sometimes between two values and this seems to stop that + + pad->m_sticks[0].m_value = (lx + pad->m_sticks[0].m_value) / 2; // LX + pad->m_sticks[1].m_value = (ly + pad->m_sticks[1].m_value) / 2; // LY + pad->m_sticks[2].m_value = (rx + pad->m_sticks[2].m_value) / 2; // RX + pad->m_sticks[3].m_value = (ry + pad->m_sticks[3].m_value) / 2; // RY + } + else + { + pad->m_sticks[0].m_value = lx; + pad->m_sticks[1].m_value = 255 - ly; + pad->m_sticks[2].m_value = rx; + pad->m_sticks[3].m_value = 255 - ry; + } +} + +void PadHandlerBase::ThreadProc() +{ + for (size_t i = 0; i < bindings.size(); ++i) + { + auto device = bindings[i].first; + auto pad = bindings[i].second; + + if (!device || !pad) + continue; + + const auto status = update_connection(device); + + switch (status) + { + case connection::no_data: + case connection::connected: + { + if (!last_connection_status[i]) + { + LOG_SUCCESS(HLE, "%s device %d connected", m_type, i); + pad->m_port_status |= CELL_PAD_STATUS_CONNECTED; + pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; + last_connection_status[i] = true; + connected_devices++; + } + + if (status == connection::no_data) + continue; + + break; + } + case connection::disconnected: + { + if (last_connection_status[i]) + { + LOG_ERROR(HLE, "%s device %d disconnected", m_type, i); + pad->m_port_status &= ~CELL_PAD_STATUS_CONNECTED; + pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; + last_connection_status[i] = false; + connected_devices--; + } + continue; + } + default: + break; + } + + get_mapping(device, pad); + get_extended_info(device, pad); + apply_pad_data(device, pad); + +#ifdef _WIN32 + for (const auto& btn : pad->m_buttons) + { + if (pad->m_buttons[i].m_pressed) + { + SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); + break; + } + } +#endif + } +} diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index 3232296742..cc66417f31 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -59,11 +59,11 @@ enum Digital2Flags enum DeviceCapability { - CELL_PAD_CAPABILITY_PS3_CONFORMITY = 0x00000001, //PS3 Conformity Controller - CELL_PAD_CAPABILITY_PRESS_MODE = 0x00000002, //Press mode supported - CELL_PAD_CAPABILITY_SENSOR_MODE = 0x00000004, //Sensor mode supported - CELL_PAD_CAPABILITY_HP_ANALOG_STICK = 0x00000008, //High Precision analog stick - CELL_PAD_CAPABILITY_ACTUATOR = 0x00000010, //Motor supported + CELL_PAD_CAPABILITY_PS3_CONFORMITY = 0x00000001, // PS3 Conformity Controller + CELL_PAD_CAPABILITY_PRESS_MODE = 0x00000002, // Press mode supported + CELL_PAD_CAPABILITY_SENSOR_MODE = 0x00000004, // Sensor mode supported + CELL_PAD_CAPABILITY_HP_ANALOG_STICK = 0x00000008, // High Precision analog stick + CELL_PAD_CAPABILITY_ACTUATOR = 0x00000010, // Motor supported }; enum DeviceType @@ -184,11 +184,11 @@ struct Pad std::vector m_sensors; std::vector m_vibrateMotors; - //These hold bits for their respective buttons + // These hold bits for their respective buttons u16 m_digital_1; u16 m_digital_2; - //All sensors go from 0-255 + // All sensors go from 0-255 u16 m_analog_left_x; u16 m_analog_left_y; u16 m_analog_right_x; @@ -207,8 +207,8 @@ struct Pad u16 m_press_R1; u16 m_press_R2; - //Except for these...0-1023 - //~399 on sensor y is a level non moving controller + // Except for these...0-1023 + // ~399 on sensor y is a level non moving controller u16 m_sensor_x; u16 m_sensor_y; u16 m_sensor_z; @@ -396,15 +396,59 @@ struct pad_config final : cfg::node } }; +struct PadDevice +{ + pad_config* config{ nullptr }; +}; + class PadHandlerBase { protected: + enum button + { + up, + down, + left, + right, + cross, + square, + circle, + triangle, + l1, + l2, + l3, + r1, + r2, + r3, + start, + select, + ps, + //reserved, + ls_left, + ls_right, + ls_down, + ls_up, + rs_left, + rs_right, + rs_down, + rs_up, + + button_count + }; + + enum connection + { + no_data, + connected, + disconnected + }; + static const u32 MAX_GAMEPADS = 7; std::array last_connection_status{{ false, false, false, false, false, false, false }}; std::string m_name_string; - int m_max_devices = 0; + size_t m_max_devices = 0; int m_trigger_threshold = 0; int m_thumb_threshold = 0; @@ -413,6 +457,9 @@ protected: bool b_has_rumble = false; bool b_has_config = false; std::array m_pad_configs; + std::vector, std::shared_ptr>> bindings; + std::unordered_map button_list; + std::vector blacklist; template T lerp(T v0, T v1, T t) { @@ -420,16 +467,16 @@ protected: } // Search an unordered map for a string value and return found keycode - int FindKeyCode(std::unordered_map map, const cfg::string& name, bool fallback = true); + int FindKeyCode(const std::unordered_map& map, const cfg::string& name, bool fallback = true); // Search an unordered map for a string value and return found keycode - long FindKeyCode(std::unordered_map map, const cfg::string& name, bool fallback = true); + long FindKeyCode(const std::unordered_map& map, const cfg::string& name, bool fallback = true); // Search an unordered map for a string value and return found keycode - int FindKeyCodeByString(std::unordered_map map, const std::string& name, bool fallback = true); + int FindKeyCodeByString(const std::unordered_map& map, const std::string& name, bool fallback = true); // Search an unordered map for a string value and return found keycode - long FindKeyCodeByString(std::unordered_map map, const std::string& name, bool fallback = true); + long FindKeyCodeByString(const std::unordered_map& map, const std::string& name, bool fallback = true); // Get new scaled value between 0 and 255 based on its minimum and maximum float ScaleStickInput(s32 raw_value, int minimum, int maximum); @@ -472,12 +519,12 @@ public: s32 trigger_max = 255; s32 vibration_min = 0; s32 vibration_max = 255; - u32 connected = 0; + u32 connected_devices = 0; pad_handler m_type = pad_handler::null; std::string name_string(); - int max_devices(); + size_t max_devices(); bool has_config(); bool has_rumble(); bool has_deadzones(); @@ -489,20 +536,32 @@ public: virtual bool Init() { return true; } PadHandlerBase(pad_handler type = pad_handler::null); virtual ~PadHandlerBase() = default; - //Sets window to config the controller(optional) - virtual void GetNextButtonPress(const std::string& /*padId*/, const std::function& /*callback*/, const std::function& /*fail_callback*/, bool /*get_blacklist*/ = false, const std::vector& /*buttons*/ = {}) {} + // Sets window to config the controller(optional) virtual void SetPadData(const std::string& /*padId*/, u32 /*largeMotor*/, u32 /*smallMotor*/, s32 /*r*/, s32 /*g*/, s32 /*b*/) {} - //Return list of devices for that handler + // Return list of devices for that handler virtual std::vector ListDevices() = 0; - //Callback called during pad_thread::ThreadFunc - virtual void ThreadProc() = 0; - //Binds a Pad to a device - virtual bool bindPadToDevice(std::shared_ptr /*pad*/, const std::string& /*device*/) = 0; + // Callback called during pad_thread::ThreadFunc + virtual void ThreadProc(); + // Binds a Pad to a device + virtual bool bindPadToDevice(std::shared_ptr pad, const std::string& device); virtual void init_config(pad_config* /*cfg*/, const std::string& /*name*/) = 0; + virtual void get_next_button_press(const std::string& padId, const std::function)>& callback, const std::function& fail_callback, bool get_blacklist, const std::vector& buttons = {}); private: - virtual void TranslateButtonPress(u64 /*keyCode*/, bool& /*pressed*/, u16& /*val*/, bool /*ignore_threshold*/ = false) {} + virtual std::shared_ptr get_device(const std::string& /*device*/) { return nullptr; }; + virtual bool get_is_left_trigger(u64 /*keyCode*/) { return false; }; + virtual bool get_is_right_trigger(u64 /*keyCode*/) { return false; }; + virtual bool get_is_left_stick(u64 /*keyCode*/) { return false; }; + virtual bool get_is_right_stick(u64 /*keyCode*/) { return false; }; + virtual PadHandlerBase::connection update_connection(const std::shared_ptr& /*device*/) { return connection::disconnected; }; + virtual void get_extended_info(const std::shared_ptr& /*device*/, const std::shared_ptr& /*pad*/) {}; + virtual void apply_pad_data(const std::shared_ptr& /*device*/, const std::shared_ptr& /*pad*/) {}; + virtual std::unordered_map get_button_values(const std::shared_ptr& /*device*/) { return {}; }; + virtual std::array get_preview_values(std::unordered_map /*data*/) { return {}; }; protected: + virtual std::array get_mapped_key_codes(const std::shared_ptr& /*device*/, const pad_config* profile); + virtual void get_mapping(const std::shared_ptr& device, const std::shared_ptr& pad); + void TranslateButtonPress(const std::shared_ptr& device, u64 keyCode, bool& pressed, u16& val, bool ignore_stick_threshold = false, bool ignore_trigger_threshold = false); void init_configs(); }; diff --git a/rpcs3/ds3_pad_handler.cpp b/rpcs3/ds3_pad_handler.cpp index c381c7d6dc..c4cf0e8c18 100644 --- a/rpcs3/ds3_pad_handler.cpp +++ b/rpcs3/ds3_pad_handler.cpp @@ -2,21 +2,49 @@ #include -#ifdef _WIN32 -#include -#endif - ds3_pad_handler::ds3_pad_handler() : PadHandlerBase(pad_handler::ds3) { + button_list = + { + { DS3KeyCodes::Triangle, "Triangle" }, + { DS3KeyCodes::Circle, "Circle" }, + { DS3KeyCodes::Cross, "Cross" }, + { DS3KeyCodes::Square, "Square" }, + { DS3KeyCodes::Left, "Left" }, + { DS3KeyCodes::Right, "Right" }, + { DS3KeyCodes::Up, "Up" }, + { DS3KeyCodes::Down, "Down" }, + { DS3KeyCodes::R1, "R1" }, + { DS3KeyCodes::R2, "R2" }, + { DS3KeyCodes::R3, "R3" }, + { DS3KeyCodes::Start, "Start" }, + { DS3KeyCodes::Select, "Select" }, + { DS3KeyCodes::PSButton, "PS Button" }, + { DS3KeyCodes::L1, "L1" }, + { DS3KeyCodes::L2, "L2" }, + { DS3KeyCodes::L3, "L3" }, + { DS3KeyCodes::LSXNeg, "LS X-" }, + { DS3KeyCodes::LSXPos, "LS X+" }, + { DS3KeyCodes::LSYPos, "LS Y+" }, + { DS3KeyCodes::LSYNeg, "LS Y-" }, + { DS3KeyCodes::RSXNeg, "RS X-" }, + { DS3KeyCodes::RSXPos, "RS X+" }, + { DS3KeyCodes::RSYPos, "RS Y+" }, + { DS3KeyCodes::RSYNeg, "RS Y-" } + }; + init_configs(); // set capabilities b_has_config = true; b_has_rumble = true; - b_has_deadzones = false; + b_has_deadzones = true; m_name_string = "DS3 Pad #"; m_max_devices = CELL_PAD_MAX_PORT_NUM; + + m_trigger_threshold = trigger_max / 2; + m_thumb_threshold = thumb_max / 2; } ds3_pad_handler::~ds3_pad_handler() @@ -123,124 +151,9 @@ std::vector ds3_pad_handler::ListDevices() return ds3_pads_list; } -bool ds3_pad_handler::bindPadToDevice(std::shared_ptr pad, const std::string& device) -{ - std::shared_ptr ds3device = get_device(device); - if (ds3device == nullptr || ds3device->handle == nullptr) - return false; - - int index = static_cast(bindings.size()); - m_pad_configs[index].load(); - ds3device->config = &m_pad_configs[index]; - pad_config* p_profile = ds3device->config; - if (p_profile == nullptr) - return false; - - pad->Init - ( - CELL_PAD_STATUS_DISCONNECTED, - CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE, - CELL_PAD_DEV_TYPE_STANDARD, - p_profile->device_class_type - ); - - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l2), CELL_PAD_CTRL_L2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r2), CELL_PAD_CTRL_R2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->up), CELL_PAD_CTRL_UP); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->down), CELL_PAD_CTRL_DOWN); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->left), CELL_PAD_CTRL_LEFT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->right), CELL_PAD_CTRL_RIGHT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->square), CELL_PAD_CTRL_SQUARE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->cross), CELL_PAD_CTRL_CROSS); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->circle), CELL_PAD_CTRL_CIRCLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->triangle), CELL_PAD_CTRL_TRIANGLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l1), CELL_PAD_CTRL_L1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r1), CELL_PAD_CTRL_R1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->select), CELL_PAD_CTRL_SELECT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->start), CELL_PAD_CTRL_START); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->l3), CELL_PAD_CTRL_L3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->r3), CELL_PAD_CTRL_R3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support - //pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved (and currently not in use by rpcs3 at all) - - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 512); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 512); - - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, FindKeyCode(button_list, p_profile->ls_left), FindKeyCode(button_list, p_profile->ls_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, FindKeyCode(button_list, p_profile->ls_down), FindKeyCode(button_list, p_profile->ls_up)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, FindKeyCode(button_list, p_profile->rs_left), FindKeyCode(button_list, p_profile->rs_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, FindKeyCode(button_list, p_profile->rs_down), FindKeyCode(button_list, p_profile->rs_up)); - - pad->m_vibrateMotors.emplace_back(true, 0); - pad->m_vibrateMotors.emplace_back(false, 0); - - bindings.emplace_back(ds3device, pad); - - return true; -} - -void ds3_pad_handler::ThreadProc() -{ - for (int i = 0; i < static_cast(bindings.size()); i++) - { - m_dev = bindings[i].first; - auto thepad = bindings[i].second; - - if (m_dev->handle == nullptr) - { - hid_device* devhandle = hid_open_path(m_dev->device.c_str()); - if (!devhandle) - { - continue; - } - - m_dev->handle = devhandle; - } - - switch (get_data(m_dev)) - { - case DS3Status::NewData: - process_data(m_dev, thepad); - case DS3Status::Connected: - if (m_dev->status == DS3Status::Disconnected) - { - m_dev->status = DS3Status::Connected; - thepad->m_port_status = CELL_PAD_STATUS_CONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES; - LOG_WARNING(HLE, "[DS3] Pad was connected"); - - connected++; - } - - if (m_dev->large_motor != thepad->m_vibrateMotors[0].m_value || m_dev->small_motor != thepad->m_vibrateMotors[1].m_value) - { - m_dev->large_motor = (u8)thepad->m_vibrateMotors[0].m_value; - m_dev->small_motor = (u8)thepad->m_vibrateMotors[1].m_value; - send_output_report(m_dev); - } - - break; - case DS3Status::Disconnected: - if (m_dev->status == DS3Status::Connected) - { - m_dev->status = DS3Status::Disconnected; - thepad->m_port_status = CELL_PAD_STATUS_DISCONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES; - hid_close(m_dev->handle); - - m_dev->handle = nullptr; - LOG_WARNING(HLE, "[DS3] Pad was disconnected"); - - connected--; - } - break; - } - } -} - void ds3_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32/* r*/, s32/* g*/, s32 /* b*/) { - std::shared_ptr device = get_device(padId); + std::shared_ptr device = get_ds3_device(padId); if (device == nullptr || device->handle == nullptr) return; @@ -267,20 +180,11 @@ void ds3_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 s send_output_report(device); } -void ds3_pad_handler::GetNextButtonPress(const std::string& padId, const std::function& /*callback*/, const std::function& fail_callback, bool get_blacklist, const std::vector& /*buttons*/) -{ - if (get_blacklist) - blacklist.clear(); - - std::shared_ptr device = get_device(padId); - if (device == nullptr || device->handle == nullptr) - return fail_callback(padId); - - return; -} - void ds3_pad_handler::send_output_report(const std::shared_ptr& ds3dev) { + if (!ds3dev) + return; + #ifdef _WIN32 u8 report_buf[] = { 0x00, @@ -307,7 +211,7 @@ void ds3_pad_handler::send_output_report(const std::shared_ptr& ds3d hid_write(ds3dev->handle, report_buf, sizeof(report_buf)); } -std::shared_ptr ds3_pad_handler::get_device(const std::string& padId) +std::shared_ptr ds3_pad_handler::get_ds3_device(const std::string& padId) { if (!Init()) return nullptr; @@ -356,8 +260,8 @@ void ds3_pad_handler::init_config(pad_config* cfg, const std::string& name) cfg->l3.def = button_list.at(DS3KeyCodes::L3); // Set default misc variables - cfg->lstickdeadzone.def = 0; // between 0 and 255 - cfg->rstickdeadzone.def = 0; // between 0 and 255 + cfg->lstickdeadzone.def = 40; // between 0 and 255 + cfg->rstickdeadzone.def = 40; // between 0 and 255 cfg->ltriggerthreshold.def = 0; // between 0 and 255 cfg->rtriggerthreshold.def = 0; // between 0 and 255 cfg->padsquircling.def = 0; @@ -373,6 +277,9 @@ void ds3_pad_handler::init_config(pad_config* cfg, const std::string& name) ds3_pad_handler::DS3Status ds3_pad_handler::get_data(const std::shared_ptr& ds3dev) { + if (!ds3dev) + return DS3Status::Disconnected; + auto& dbuf = ds3dev->buf; #ifdef _WIN32 @@ -407,76 +314,85 @@ ds3_pad_handler::DS3Status ds3_pad_handler::get_data(const std::shared_ptr, ds3_pad_handler::DS3KeyCodes::KeyCodeCount> ds3_pad_handler::get_button_values(const std::shared_ptr& device) +std::unordered_map ds3_pad_handler::get_button_values(const std::shared_ptr& device) { - std::array, DS3KeyCodes::KeyCodeCount> key_buf; - auto& dbuf = device->buf; + std::unordered_map key_buf; + auto dev = std::static_pointer_cast(device); + if (!dev) + return key_buf; - key_buf[DS3KeyCodes::Up].second = dbuf[2 + DS3_HID_OFFSET] & 0x10; - key_buf[DS3KeyCodes::Right].second = dbuf[2 + DS3_HID_OFFSET] & 0x20; - key_buf[DS3KeyCodes::Down].second = dbuf[2 + DS3_HID_OFFSET] & 0x40; - key_buf[DS3KeyCodes::Left].second = dbuf[2 + DS3_HID_OFFSET] & 0x80; + auto& dbuf = dev->buf; - key_buf[DS3KeyCodes::Select].second = dbuf[2 + DS3_HID_OFFSET] & 0x01; - key_buf[DS3KeyCodes::L3].second = dbuf[2 + DS3_HID_OFFSET] & 0x02; - key_buf[DS3KeyCodes::R3].second = dbuf[2 + DS3_HID_OFFSET] & 0x04; - key_buf[DS3KeyCodes::Start].second = dbuf[2 + DS3_HID_OFFSET] & 0x08; + //key_buf[DS3KeyCodes::Up].second = dbuf[2 + DS3_HID_OFFSET] & 0x10; + //key_buf[DS3KeyCodes::Right].second = dbuf[2 + DS3_HID_OFFSET] & 0x20; + //key_buf[DS3KeyCodes::Down].second = dbuf[2 + DS3_HID_OFFSET] & 0x40; + //key_buf[DS3KeyCodes::Left].second = dbuf[2 + DS3_HID_OFFSET] & 0x80; - key_buf[DS3KeyCodes::Square].second = dbuf[3 + DS3_HID_OFFSET] & 0x80; - key_buf[DS3KeyCodes::Cross].second = dbuf[3 + DS3_HID_OFFSET] & 0x40; - key_buf[DS3KeyCodes::Circle].second = dbuf[3 + DS3_HID_OFFSET] & 0x20; - key_buf[DS3KeyCodes::Triangle].second = dbuf[3 + DS3_HID_OFFSET] & 0x10; + //key_buf[DS3KeyCodes::Select].second = dbuf[2 + DS3_HID_OFFSET] & 0x01; + //key_buf[DS3KeyCodes::L3].second = dbuf[2 + DS3_HID_OFFSET] & 0x02; + //key_buf[DS3KeyCodes::R3].second = dbuf[2 + DS3_HID_OFFSET] & 0x04; + //key_buf[DS3KeyCodes::Start].second = dbuf[2 + DS3_HID_OFFSET] & 0x08; - key_buf[DS3KeyCodes::R1].second = dbuf[3 + DS3_HID_OFFSET] & 0x08; - key_buf[DS3KeyCodes::L1].second = dbuf[3 + DS3_HID_OFFSET] & 0x04; - key_buf[DS3KeyCodes::R2].second = dbuf[3 + DS3_HID_OFFSET] & 0x02; - key_buf[DS3KeyCodes::L2].second = dbuf[3 + DS3_HID_OFFSET] & 0x01; + //key_buf[DS3KeyCodes::Square].second = dbuf[3 + DS3_HID_OFFSET] & 0x80; + //key_buf[DS3KeyCodes::Cross].second = dbuf[3 + DS3_HID_OFFSET] & 0x40; + //key_buf[DS3KeyCodes::Circle].second = dbuf[3 + DS3_HID_OFFSET] & 0x20; + //key_buf[DS3KeyCodes::Triangle].second = dbuf[3 + DS3_HID_OFFSET] & 0x10; - key_buf[DS3KeyCodes::PSButton].second = dbuf[4 + DS3_HID_OFFSET] & 0x01; + //key_buf[DS3KeyCodes::R1].second = dbuf[3 + DS3_HID_OFFSET] & 0x08; + //key_buf[DS3KeyCodes::L1].second = dbuf[3 + DS3_HID_OFFSET] & 0x04; + //key_buf[DS3KeyCodes::R2].second = dbuf[3 + DS3_HID_OFFSET] & 0x02; + //key_buf[DS3KeyCodes::L2].second = dbuf[3 + DS3_HID_OFFSET] & 0x01; - key_buf[DS3KeyCodes::LSXPos].first = dbuf[6 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::LSYPos].first = dbuf[7 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::RSXPos].first = dbuf[8 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::RSYPos].first = dbuf[9 + DS3_HID_OFFSET]; + //key_buf[DS3KeyCodes::PSButton].second = dbuf[4 + DS3_HID_OFFSET] & 0x01; - key_buf[DS3KeyCodes::Up].first = dbuf[14 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::Right].first = dbuf[15 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::Down].first = dbuf[16 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::Left].first = dbuf[17 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::Triangle].first = dbuf[22 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::Circle].first = dbuf[23 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::Cross].first = dbuf[24 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::Square].first = dbuf[25 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::L1].first = dbuf[20 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::R1].first = dbuf[21 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::L2].first = dbuf[18 + DS3_HID_OFFSET]; - key_buf[DS3KeyCodes::R2].first = dbuf[19 + DS3_HID_OFFSET]; + const u8 lsx = dbuf[6 + DS3_HID_OFFSET]; + const u8 lsy = dbuf[7 + DS3_HID_OFFSET]; + const u8 rsx = dbuf[8 + DS3_HID_OFFSET]; + const u8 rsy = dbuf[9 + DS3_HID_OFFSET]; + + // Left Stick X Axis + key_buf[DS3KeyCodes::LSXNeg] = Clamp0To255((127.5f - lsx) * 2.0f); + key_buf[DS3KeyCodes::LSXPos] = Clamp0To255((lsx - 127.5f) * 2.0f); + + // Left Stick Y Axis (Up is the negative for some reason) + key_buf[DS3KeyCodes::LSYNeg] = Clamp0To255((lsy - 127.5f) * 2.0f); + key_buf[DS3KeyCodes::LSYPos] = Clamp0To255((127.5f - lsy) * 2.0f); + + // Right Stick X Axis + key_buf[DS3KeyCodes::RSXNeg] = Clamp0To255((127.5f - rsx) * 2.0f); + key_buf[DS3KeyCodes::RSXPos] = Clamp0To255((rsx - 127.5f) * 2.0f); + + // Right Stick Y Axis (Up is the negative for some reason) + key_buf[DS3KeyCodes::RSYNeg] = Clamp0To255((rsy - 127.5f) * 2.0f); + key_buf[DS3KeyCodes::RSYPos] = Clamp0To255((127.5f - rsy) * 2.0f); + + // Buttons + key_buf[DS3KeyCodes::Up] = dbuf[14 + DS3_HID_OFFSET]; + key_buf[DS3KeyCodes::Right] = dbuf[15 + DS3_HID_OFFSET]; + key_buf[DS3KeyCodes::Down] = dbuf[16 + DS3_HID_OFFSET]; + key_buf[DS3KeyCodes::Left] = dbuf[17 + DS3_HID_OFFSET]; + key_buf[DS3KeyCodes::Triangle] = dbuf[22 + DS3_HID_OFFSET]; + key_buf[DS3KeyCodes::Circle] = dbuf[23 + DS3_HID_OFFSET]; + key_buf[DS3KeyCodes::Cross] = dbuf[24 + DS3_HID_OFFSET]; + key_buf[DS3KeyCodes::Square] = dbuf[25 + DS3_HID_OFFSET]; + key_buf[DS3KeyCodes::L1] = dbuf[20 + DS3_HID_OFFSET]; + key_buf[DS3KeyCodes::R1] = dbuf[21 + DS3_HID_OFFSET]; + key_buf[DS3KeyCodes::L2] = dbuf[18 + DS3_HID_OFFSET]; + key_buf[DS3KeyCodes::R2] = dbuf[19 + DS3_HID_OFFSET]; return key_buf; } -void ds3_pad_handler::process_data(const std::shared_ptr& ds3dev, const std::shared_ptr& pad) +std::array ds3_pad_handler::get_preview_values(std::unordered_map data) { - auto ds3_info = get_button_values(ds3dev); + return { data[L2], data[R2], data[LSXPos] - data[LSXNeg], data[LSYPos] - data[LSYNeg], data[RSXPos] - data[RSXNeg], data[RSYPos] - data[RSYNeg] }; +} - for (auto & btn : pad->m_buttons) - { - btn.m_value = ds3_info[btn.m_keyCode].first; - btn.m_pressed = ds3_info[btn.m_keyCode].second; - } - -#ifdef _WIN32 - if(ds3dev->buf[2] || ds3dev->buf[3] || ds3dev->buf[4]) - SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); -#endif - - // DS3 pad handler is only using the positive values for accuracy sake - for (int i = 0; i < static_cast(pad->m_sticks.size()); i++) - { - // m_keyCodeMax is the mapped key for right or up - u32 key_max = pad->m_sticks[i].m_keyCodeMax; - pad->m_sticks[i].m_value = ds3_info[key_max].first; - } +void ds3_pad_handler::get_extended_info(const std::shared_ptr& device, const std::shared_ptr& pad) +{ + auto ds3dev = std::static_pointer_cast(device); + if (!ds3dev || !pad) + return; // For unknown reasons the sixaxis values seem to be in little endian on linux @@ -511,3 +427,112 @@ void ds3_pad_handler::process_data(const std::shared_ptr& ds3dev, co //pad->m_sensors[2].m_value = polish_value(pad->m_sensors[2].m_value, 113, 113, 512, 512, 0, 1023); //pad->m_sensors[3].m_value = polish_value(pad->m_sensors[3].m_value, 1, 1, 512, 512, 0, 1023); } + +std::shared_ptr ds3_pad_handler::get_device(const std::string& device) +{ + std::shared_ptr ds3device = get_ds3_device(device); + if (ds3device == nullptr || ds3device->handle == nullptr) + return nullptr; + + return ds3device; +} + +bool ds3_pad_handler::get_is_left_trigger(u64 keyCode) +{ + return keyCode == DS3KeyCodes::L2; +} + +bool ds3_pad_handler::get_is_right_trigger(u64 keyCode) +{ + return keyCode == DS3KeyCodes::R2; +} + +bool ds3_pad_handler::get_is_left_stick(u64 keyCode) +{ + switch (keyCode) + { + case DS3KeyCodes::LSXNeg: + case DS3KeyCodes::LSXPos: + case DS3KeyCodes::LSYPos: + case DS3KeyCodes::LSYNeg: + return true; + default: + return false; + } +} + +bool ds3_pad_handler::get_is_right_stick(u64 keyCode) +{ + switch (keyCode) + { + case DS3KeyCodes::RSXNeg: + case DS3KeyCodes::RSXPos: + case DS3KeyCodes::RSYPos: + case DS3KeyCodes::RSYNeg: + return true; + default: + return false; + } +} + +PadHandlerBase::connection ds3_pad_handler::update_connection(const std::shared_ptr& device) +{ + auto dev = std::static_pointer_cast(device); + if (!dev) + return connection::disconnected; + + if (dev->handle == nullptr) + { + hid_device* devhandle = hid_open_path(dev->device.c_str()); + if (!devhandle) + { + return connection::disconnected; + } + + dev->handle = devhandle; + } + + switch (get_data(dev)) + { + case DS3Status::Disconnected: + { + if (dev->status == DS3Status::Connected) + { + dev->status = DS3Status::Disconnected; + hid_close(dev->handle); + dev->handle = nullptr; + } + return connection::disconnected; + } + case DS3Status::Connected: + { + if (dev->status == DS3Status::Disconnected) + { + dev->status = DS3Status::Connected; + } + return connection::no_data; + } + case DS3Status::NewData: + { + return connection::connected; + } + default: + break; + } + + return connection::disconnected; +} + +void ds3_pad_handler::apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) +{ + auto dev = std::static_pointer_cast(device); + if (!dev || !pad) + return; + + if (dev->large_motor != pad->m_vibrateMotors[0].m_value || dev->small_motor != pad->m_vibrateMotors[1].m_value) + { + dev->large_motor = (u8)pad->m_vibrateMotors[0].m_value; + dev->small_motor = (u8)pad->m_vibrateMotors[1].m_value; + send_output_report(dev); + } +} diff --git a/rpcs3/ds3_pad_handler.h b/rpcs3/ds3_pad_handler.h index fe58cdb3ca..b4229e0b25 100644 --- a/rpcs3/ds3_pad_handler.h +++ b/rpcs3/ds3_pad_handler.h @@ -72,40 +72,10 @@ class ds3_pad_handler final : public PadHandlerBase NewData }; - const std::unordered_map button_list = - { - { DS3KeyCodes::Triangle, "Triangle" }, - { DS3KeyCodes::Circle, "Circle" }, - { DS3KeyCodes::Cross, "Cross" }, - { DS3KeyCodes::Square, "Square" }, - { DS3KeyCodes::Left, "Left" }, - { DS3KeyCodes::Right, "Right" }, - { DS3KeyCodes::Up, "Up" }, - { DS3KeyCodes::Down, "Down" }, - { DS3KeyCodes::R1, "R1" }, - { DS3KeyCodes::R2, "R2" }, - { DS3KeyCodes::R3, "R3" }, - { DS3KeyCodes::Start, "Start" }, - { DS3KeyCodes::Select, "Select" }, - { DS3KeyCodes::PSButton, "PS Button" }, - { DS3KeyCodes::L1, "L1" }, - { DS3KeyCodes::L2, "L2" }, - { DS3KeyCodes::L3, "L3" }, - { DS3KeyCodes::LSXNeg, "LS X-" }, - { DS3KeyCodes::LSXPos, "LS X+" }, - { DS3KeyCodes::LSYPos, "LS Y+" }, - { DS3KeyCodes::LSYNeg, "LS Y-" }, - { DS3KeyCodes::RSXNeg, "RS X-" }, - { DS3KeyCodes::RSXPos, "RS X+" }, - { DS3KeyCodes::RSYPos, "RS Y+" }, - { DS3KeyCodes::RSYNeg, "RS Y-" } - }; - - struct ds3_device + struct ds3_device : public PadDevice { std::string device = {}; hid_device *handle = nullptr; - pad_config* config{ nullptr }; u8 buf[64]{ 0 }; u8 large_motor = 0; u8 small_motor = 0; @@ -131,17 +101,12 @@ public: bool Init() override; std::vector ListDevices() override; - bool bindPadToDevice(std::shared_ptr pad, const std::string& device) override; - void ThreadProc() override; - void GetNextButtonPress(const std::string& padId, const std::function& buttonCallback, const std::function& fail_callback, bool get_blacklist = false, const std::vector& buttons = {}) override; void SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b) override; void init_config(pad_config* cfg, const std::string& name) override; private: - std::shared_ptr get_device(const std::string& padId); + std::shared_ptr get_ds3_device(const std::string& padId); ds3_pad_handler::DS3Status get_data(const std::shared_ptr& ds3dev); - void process_data(const std::shared_ptr& ds3dev, const std::shared_ptr& pad); - std::array, ds3_pad_handler::DS3KeyCodes::KeyCodeCount> get_button_values(const std::shared_ptr& device); void send_output_report(const std::shared_ptr& ds3dev); private: @@ -150,8 +115,14 @@ private: private: bool is_init = false; - std::vector blacklist; - - std::vector, std::shared_ptr>> bindings; - std::shared_ptr m_dev; + std::shared_ptr get_device(const std::string& device) override; + bool get_is_left_trigger(u64 keyCode) override; + bool get_is_right_trigger(u64 keyCode) override; + bool get_is_left_stick(u64 keyCode) override; + bool get_is_right_stick(u64 keyCode) override; + PadHandlerBase::connection update_connection(const std::shared_ptr& device) override; + void get_extended_info(const std::shared_ptr& device, const std::shared_ptr& pad) override; + void apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) override; + std::unordered_map get_button_values(const std::shared_ptr& device) override; + std::array get_preview_values(std::unordered_map data) override; }; diff --git a/rpcs3/ds4_pad_handler.cpp b/rpcs3/ds4_pad_handler.cpp index c38374cb93..f695939bb6 100644 --- a/rpcs3/ds4_pad_handler.cpp +++ b/rpcs3/ds4_pad_handler.cpp @@ -2,10 +2,6 @@ #include -#ifdef _WIN32 -#include -#endif - namespace { const auto THREAD_SLEEP = 1ms; //ds4 has new data every ~4ms, @@ -81,6 +77,37 @@ namespace ds4_pad_handler::ds4_pad_handler() : PadHandlerBase(pad_handler::ds4) { + // Unique names for the config files and our pad settings dialog + button_list = + { + { DS4KeyCodes::Triangle, "Triangle" }, + { DS4KeyCodes::Circle, "Circle" }, + { DS4KeyCodes::Cross, "Cross" }, + { DS4KeyCodes::Square, "Square" }, + { DS4KeyCodes::Left, "Left" }, + { DS4KeyCodes::Right, "Right" }, + { DS4KeyCodes::Up, "Up" }, + { DS4KeyCodes::Down, "Down" }, + { DS4KeyCodes::R1, "R1" }, + { DS4KeyCodes::R2, "R2" }, + { DS4KeyCodes::R3, "R3" }, + { DS4KeyCodes::Options, "Options" }, + { DS4KeyCodes::Share, "Share" }, + { DS4KeyCodes::PSButton, "PS Button" }, + { DS4KeyCodes::TouchPad, "Touch Pad" }, + { DS4KeyCodes::L1, "L1" }, + { DS4KeyCodes::L2, "L2" }, + { DS4KeyCodes::L3, "L3" }, + { DS4KeyCodes::LSXNeg, "LS X-" }, + { DS4KeyCodes::LSXPos, "LS X+" }, + { DS4KeyCodes::LSYPos, "LS Y+" }, + { DS4KeyCodes::LSYNeg, "LS Y-" }, + { DS4KeyCodes::RSXNeg, "RS X-" }, + { DS4KeyCodes::RSXPos, "RS X+" }, + { DS4KeyCodes::RSYPos, "RS Y+" }, + { DS4KeyCodes::RSYNeg, "RS Y-" } + }; + init_configs(); // Define border values @@ -152,79 +179,9 @@ void ds4_pad_handler::init_config(pad_config* cfg, const std::string& name) cfg->from_default(); } -void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::function& callback, const std::function& fail_callback, bool get_blacklist, const std::vector& /*buttons*/) -{ - if (get_blacklist) - blacklist.clear(); - - std::shared_ptr device = GetDevice(padId, true); - if (device == nullptr || device->hidDevice == nullptr) - return fail_callback(padId); - - // Now that we have found a device, get its status - DS4DataStatus status = GetRawData(device); - - if (status == DS4DataStatus::ReadError) - { - // this also can mean disconnected, either way deal with it on next loop and reconnect - hid_close(device->hidDevice); - device->hidDevice = nullptr; - return fail_callback(padId); - } - - // return if nothing new has happened. ignore this to get the current state for blacklist - if (!get_blacklist && status != DS4DataStatus::NewData) - return; - - // Get the current button values - auto data = GetButtonValues(device); - - // 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 (!get_blacklist && std::find(blacklist.begin(), blacklist.end(), keycode) != blacklist.end()) - continue; - - if (((keycode < DS4KeyCodes::L2) && (value > 0)) - || ((keycode == DS4KeyCodes::L2) && (value > m_trigger_threshold)) - || ((keycode == DS4KeyCodes::R2) && (value > m_trigger_threshold)) - || ((keycode >= DS4KeyCodes::LSXNeg && keycode <= DS4KeyCodes::LSYPos) && (value > m_thumb_threshold)) - || ((keycode >= DS4KeyCodes::RSXNeg && keycode <= DS4KeyCodes::RSYPos) && (value > m_thumb_threshold))) - { - if (get_blacklist) - { - blacklist.emplace_back(keycode); - LOG_ERROR(HLE, "DS4 Calibration: Added key [ %d = %s ] to blacklist. Value = %d", keycode, button.second, value); - } - else if (value > pressed_button.first) - pressed_button = { value, button.second }; - } - } - - if (get_blacklist) - { - if (blacklist.empty()) - LOG_SUCCESS(HLE, "DS4 Calibration: Blacklist is clear. No input spam detected"); - return; - } - - int preview_values[6] = { data[L2], data[R2], data[LSXPos] - data[LSXNeg], data[LSYPos] - data[LSYNeg], data[RSXPos] - data[RSXNeg], data[RSYPos] - data[RSYNeg] }; - - if (pressed_button.first > 0) - return callback(pressed_button.first, pressed_button.second, padId, preview_values); - else - return callback(0, "", padId, preview_values); -} - void ds4_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b) { - std::shared_ptr device = GetDevice(padId); + std::shared_ptr device = GetDS4Device(padId); if (device == nullptr || device->hidDevice == nullptr) return; @@ -259,7 +216,7 @@ void ds4_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 s SendVibrateData(device); } -std::shared_ptr ds4_pad_handler::GetDevice(const std::string& padId, bool try_reconnect) +std::shared_ptr ds4_pad_handler::GetDS4Device(const std::string& padId, bool try_reconnect) { if (!Init()) return nullptr; @@ -294,46 +251,14 @@ std::shared_ptr ds4_pad_handler::GetDevice(const std return device; } -void ds4_pad_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold) +std::unordered_map ds4_pad_handler::get_button_values(const std::shared_ptr& device) { - // Update the pad button values based on their type and thresholds. - // With this you can use axis or triggers as buttons or vice versa - auto p_profile = m_dev->config; - switch (keyCode) - { - case DS4KeyCodes::L2: - pressed = val > p_profile->ltriggerthreshold; - val = pressed ? NormalizeTriggerInput(val, p_profile->ltriggerthreshold) : 0; - break; - case DS4KeyCodes::R2: - pressed = val > p_profile->rtriggerthreshold; - val = pressed ? NormalizeTriggerInput(val, p_profile->rtriggerthreshold) : 0; - break; - case DS4KeyCodes::LSXNeg: - case DS4KeyCodes::LSXPos: - case DS4KeyCodes::LSYNeg: - case DS4KeyCodes::LSYPos: - pressed = val > (ignore_threshold ? 0 : p_profile->lstickdeadzone); - val = pressed ? NormalizeStickInput(val, p_profile->lstickdeadzone, p_profile->lstickmultiplier, ignore_threshold) : 0; - break; - case DS4KeyCodes::RSXNeg: - case DS4KeyCodes::RSXPos: - case DS4KeyCodes::RSYNeg: - case DS4KeyCodes::RSYPos: - pressed = val > (ignore_threshold ? 0 : p_profile->rstickdeadzone); - val = pressed ? NormalizeStickInput(val, p_profile->rstickdeadzone, p_profile->rstickmultiplier, ignore_threshold) : 0; - break; - default: // normal button (should in theory also support sensitive buttons) - pressed = val > 0; - val = pressed ? val : 0; - break; - } -} + std::unordered_map keyBuffer; + auto ds4_dev = std::static_pointer_cast(device); + if (!ds4_dev) + return keyBuffer; -std::array ds4_pad_handler::GetButtonValues(const std::shared_ptr& device) -{ - std::array keyBuffer; - auto buf = device->padData; + auto buf = ds4_dev->padData; // Left Stick X Axis keyBuffer[DS4KeyCodes::LSXNeg] = Clamp0To255((127.5f - buf[1]) * 2.0f); @@ -440,104 +365,9 @@ std::array ds4_pad_handler::Get return keyBuffer; } -void ds4_pad_handler::ProcessDataToPad(const std::shared_ptr& device, const std::shared_ptr& pad) +std::array ds4_pad_handler::get_preview_values(std::unordered_map data) { - pad->m_battery_level = device->batteryLevel; - pad->m_cable_state = device->cableState; - - auto buf = device->padData; - auto button_values = GetButtonValues(device); - auto p_profile = device->config; - - // Translate any corresponding keycodes to our normal DS3 buttons and triggers - for (auto & btn : pad->m_buttons) - { - btn.m_value = button_values[btn.m_keyCode]; - TranslateButtonPress(btn.m_keyCode, btn.m_pressed, btn.m_value); - } - -#ifdef _WIN32 - for (int i = 6; i < 16; i++) - { - if (pad->m_buttons[i].m_pressed) - { - SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); - break; - } - } -#endif - - // used to get the absolute value of an axis - s32 stick_val[4]{0}; - - // Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now) - for (int i = 0; i < static_cast(pad->m_sticks.size()); i++) - { - bool pressed; - - // m_keyCodeMin is the mapped key for left or down - u32 key_min = pad->m_sticks[i].m_keyCodeMin; - u16 val_min = button_values[key_min]; - TranslateButtonPress(key_min, pressed, val_min, true); - - // m_keyCodeMax is the mapped key for right or up - u32 key_max = pad->m_sticks[i].m_keyCodeMax; - u16 val_max = button_values[key_max]; - TranslateButtonPress(key_max, pressed, val_max, true); - - // cancel out opposing values and get the resulting difference - stick_val[i] = val_max - val_min; - } - - u16 lx, ly, rx, ry; - - // Normalize our two stick's axis based on the thresholds - std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], p_profile->lstickdeadzone); - std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], p_profile->rstickdeadzone); - - if (p_profile->padsquircling != 0) - { - std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, p_profile->padsquircling); - std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, p_profile->padsquircling); - } - - ly = 255 - ly; - ry = 255 - ry; - - // these are added with previous value and divided to 'smooth' out the readings - // the ds4 seems to rapidly flicker sometimes between two values and this seems to stop that - - pad->m_sticks[0].m_value = (lx + pad->m_sticks[0].m_value) / 2; // LX - pad->m_sticks[1].m_value = (ly + pad->m_sticks[1].m_value) / 2; // LY - pad->m_sticks[2].m_value = (rx + pad->m_sticks[2].m_value) / 2; // RX - pad->m_sticks[3].m_value = (ry + pad->m_sticks[3].m_value) / 2; // RY - - // these values come already calibrated from our ds4Thread, - // all we need to do is convert to ds3 range - - // accel - f32 accelX = (((s16)((u16)(buf[20] << 8) | buf[19])) / static_cast(DS4_ACC_RES_PER_G)) * -1; - f32 accelY = (((s16)((u16)(buf[22] << 8) | buf[21])) / static_cast(DS4_ACC_RES_PER_G)) * -1; - f32 accelZ = (((s16)((u16)(buf[24] << 8) | buf[23])) / static_cast(DS4_ACC_RES_PER_G)) * -1; - - // now just use formula from ds3 - accelX = accelX * 113 + 512; - accelY = accelY * 113 + 512; - accelZ = accelZ * 113 + 512; - - pad->m_sensors[0].m_value = Clamp0To1023(accelX); - pad->m_sensors[1].m_value = Clamp0To1023(accelY); - pad->m_sensors[2].m_value = Clamp0To1023(accelZ); - - // gyroX is yaw, which is all that we need - f32 gyroX = (((s16)((u16)(buf[16] << 8) | buf[15])) / static_cast(DS4_GYRO_RES_PER_DEG_S)) * -1; - //const int gyroY = ((u16)(buf[14] << 8) | buf[13]) / 256; - //const int gyroZ = ((u16)(buf[18] << 8) | buf[17]) / 256; - - // convert to ds3 - gyroX = gyroX * (123.f / 90.f) + 512; - - pad->m_sensors[3].m_value = Clamp0To1023(gyroX); + return { data[L2], data[R2], data[LSXPos] - data[LSXNeg], data[LSYPos] - data[LSYNeg], data[RSXPos] - data[RSXNeg], data[RSYPos] - data[RSYNeg] }; } bool ds4_pad_handler::GetCalibrationData(const std::shared_ptr& ds4Dev) @@ -694,6 +524,9 @@ ds4_pad_handler::~ds4_pad_handler() int ds4_pad_handler::SendVibrateData(const std::shared_ptr& device) { + if (!device) + return -2; + auto p_profile = device->config; if (p_profile == nullptr) return -2; // hid_write and hid_write_control return -1 on error @@ -814,173 +647,11 @@ std::vector ds4_pad_handler::ListDevices() return ds4_pads_list; } -bool ds4_pad_handler::bindPadToDevice(std::shared_ptr pad, const std::string& device) -{ - std::shared_ptr ds4device = GetDevice(device); - if (ds4device == nullptr || ds4device->hidDevice == nullptr) - return false; - - int index = static_cast(bindings.size()); - m_pad_configs[index].load(); - ds4device->config = &m_pad_configs[index]; - pad_config* p_profile = ds4device->config; - if (p_profile == nullptr) - return false; - - pad->Init - ( - CELL_PAD_STATUS_DISCONNECTED, - CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE, - CELL_PAD_DEV_TYPE_STANDARD, - p_profile->device_class_type - ); - - // 'keycode' here is just 0 as we have to manually calculate this - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l2), CELL_PAD_CTRL_L2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r2), CELL_PAD_CTRL_R2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->up), CELL_PAD_CTRL_UP); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->down), CELL_PAD_CTRL_DOWN); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->left), CELL_PAD_CTRL_LEFT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->right), CELL_PAD_CTRL_RIGHT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->square), CELL_PAD_CTRL_SQUARE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->cross), CELL_PAD_CTRL_CROSS); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->circle), CELL_PAD_CTRL_CIRCLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->triangle), CELL_PAD_CTRL_TRIANGLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l1), CELL_PAD_CTRL_L1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r1), CELL_PAD_CTRL_R1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->select), CELL_PAD_CTRL_SELECT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->start), CELL_PAD_CTRL_START); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->l3), CELL_PAD_CTRL_L3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->r3), CELL_PAD_CTRL_R3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support - //pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved (and currently not in use by rpcs3 at all) - - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 512); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 512); - - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, FindKeyCode(button_list, p_profile->ls_left), FindKeyCode(button_list, p_profile->ls_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, FindKeyCode(button_list, p_profile->ls_down), FindKeyCode(button_list, p_profile->ls_up)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, FindKeyCode(button_list, p_profile->rs_left), FindKeyCode(button_list, p_profile->rs_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, FindKeyCode(button_list, p_profile->rs_down), FindKeyCode(button_list, p_profile->rs_up)); - - pad->m_vibrateMotors.emplace_back(true, 0); - pad->m_vibrateMotors.emplace_back(false, 0); - - bindings.emplace_back(ds4device, pad); - - return true; -} - -void ds4_pad_handler::ThreadProc() -{ - for (int i = 0; i < static_cast(bindings.size()); i++) - { - m_dev = bindings[i].first; - auto thepad = bindings[i].second; - auto profile = m_dev->config; - - if (m_dev->hidDevice == nullptr) - { - // try to reconnect - hid_device* dev = hid_open_path(m_dev->path.c_str()); - if (dev) - { - if (last_connection_status[i] == false) - { - LOG_SUCCESS(HLE, "DS4 device %d reconnected", i); - last_connection_status[i] = true; - connected++; - } - hid_set_nonblocking(dev, 1); - m_dev->hidDevice = dev; - thepad->m_port_status = CELL_PAD_STATUS_CONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES; - if (!m_dev->hasCalibData) - m_dev->hasCalibData = GetCalibrationData(m_dev); - } - else - { - // nope, not there - if (last_connection_status[i] == true) - { - LOG_ERROR(HLE, "DS4 device %d disconnected", i); - last_connection_status[i] = false; - connected--; - } - thepad->m_port_status = CELL_PAD_STATUS_DISCONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES; - continue; - } - } - else if (last_connection_status[i] == false) - { - LOG_NOTICE(HLE, "DS4 device %d connected", i); - thepad->m_port_status = CELL_PAD_STATUS_CONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES; - last_connection_status[i] = true; - connected++; - } - - DS4DataStatus status = GetRawData(m_dev); - - if (status == DS4DataStatus::ReadError) - { - // this also can mean disconnected, either way deal with it on next loop and reconnect - hid_close(m_dev->hidDevice); - m_dev->hidDevice = nullptr; - continue; - } - - // Attempt to send rumble no matter what - int idx_l = profile->switch_vibration_motors ? 1 : 0; - int idx_s = profile->switch_vibration_motors ? 0 : 1; - - int speed_large = profile->enable_vibration_motor_large ? thepad->m_vibrateMotors[idx_l].m_value : vibration_min; - int speed_small = profile->enable_vibration_motor_small ? thepad->m_vibrateMotors[idx_s].m_value : vibration_min; - - bool wireless = m_dev->cableState < 1; - bool lowBattery = m_dev->batteryLevel < 2; - bool isBlinking = m_dev->led_delay_on > 0 || m_dev->led_delay_off > 0; - bool newBlinkData = false; - - // we are now wired or have okay battery level -> stop blinking - if (isBlinking && !(wireless && lowBattery)) - { - m_dev->led_delay_on = 0; - m_dev->led_delay_off = 0; - newBlinkData = true; - } - // we are now wireless and low on battery -> blink - if (!isBlinking && wireless && lowBattery) - { - m_dev->led_delay_on = 100; - m_dev->led_delay_off = 100; - newBlinkData = true; - } - - m_dev->newVibrateData = m_dev->newVibrateData || m_dev->largeVibrate != speed_large || m_dev->smallVibrate != speed_small || newBlinkData; - - m_dev->largeVibrate = speed_large; - m_dev->smallVibrate = speed_small; - - if (m_dev->newVibrateData) - { - if (SendVibrateData(m_dev) >= 0) - { - m_dev->newVibrateData = false; - } - } - - // no data? keep going - if (status == DS4DataStatus::NoNewData) - continue; - - else if (status == DS4DataStatus::NewData) - ProcessDataToPad(m_dev, thepad); - } -} - ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr& device) { + if (!device) + return DS4DataStatus::ReadError; + std::array buf{}; const int res = hid_read(device->hidDevice, buf.data(), device->btCon ? 78 : 64); @@ -1019,7 +690,6 @@ ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr LOG_WARNING(HLE, "[DS4] Data packet CRC check failed, ignoring! Received 0x%x, Expected 0x%x", crcReported, crcCalc); return DS4DataStatus::NoNewData; } - } else if (!device->btCon && buf[0] == 0x01 && res == 64) { @@ -1052,3 +722,173 @@ ds4_pad_handler::DS4DataStatus ds4_pad_handler::GetRawData(const std::shared_ptr return DS4DataStatus::NewData; } + +std::shared_ptr ds4_pad_handler::get_device(const std::string& device) +{ + std::shared_ptr ds4device = GetDS4Device(device); + if (ds4device == nullptr || ds4device->hidDevice == nullptr) + return nullptr; + + return ds4device; +} + +bool ds4_pad_handler::get_is_left_trigger(u64 keyCode) +{ + return keyCode == DS4KeyCodes::L2; +} + +bool ds4_pad_handler::get_is_right_trigger(u64 keyCode) +{ + return keyCode == DS4KeyCodes::R2; +} + +bool ds4_pad_handler::get_is_left_stick(u64 keyCode) +{ + switch (keyCode) + { + case DS4KeyCodes::LSXNeg: + case DS4KeyCodes::LSXPos: + case DS4KeyCodes::LSYPos: + case DS4KeyCodes::LSYNeg: + return true; + default: + return false; + } +} + +bool ds4_pad_handler::get_is_right_stick(u64 keyCode) +{ + switch (keyCode) + { + case DS4KeyCodes::RSXNeg: + case DS4KeyCodes::RSXPos: + case DS4KeyCodes::RSYPos: + case DS4KeyCodes::RSYNeg: + return true; + default: + return false; + } +} + +PadHandlerBase::connection ds4_pad_handler::update_connection(const std::shared_ptr& device) +{ + auto ds4_dev = std::static_pointer_cast(device); + if (!ds4_dev) + return connection::disconnected; + + if (ds4_dev->hidDevice == nullptr) + { + // try to reconnect + hid_device* dev = hid_open_path(ds4_dev->path.c_str()); + if (dev) + { + hid_set_nonblocking(dev, 1); + ds4_dev->hidDevice = dev; + if (!ds4_dev->hasCalibData) + ds4_dev->hasCalibData = GetCalibrationData(ds4_dev); + } + else + { + // nope, not there + return connection::disconnected; + } + } + + status = GetRawData(ds4_dev); + + if (status == DS4DataStatus::ReadError) + { + // this also can mean disconnected, either way deal with it on next loop and reconnect + hid_close(ds4_dev->hidDevice); + ds4_dev->hidDevice = nullptr; + + return connection::no_data; + } + + return connection::connected; +} + +void ds4_pad_handler::get_extended_info(const std::shared_ptr& device, const std::shared_ptr& pad) +{ + auto ds4_device = std::static_pointer_cast(device); + if (!ds4_device || !pad) + return; + + auto buf = ds4_device->padData; + + pad->m_battery_level = ds4_device->batteryLevel; + pad->m_cable_state = ds4_device->cableState; + + // these values come already calibrated from our ds4Thread, + // all we need to do is convert to ds3 range + + // accel + f32 accelX = (((s16)((u16)(buf[20] << 8) | buf[19])) / static_cast(DS4_ACC_RES_PER_G)) * -1; + f32 accelY = (((s16)((u16)(buf[22] << 8) | buf[21])) / static_cast(DS4_ACC_RES_PER_G)) * -1; + f32 accelZ = (((s16)((u16)(buf[24] << 8) | buf[23])) / static_cast(DS4_ACC_RES_PER_G)) * -1; + + // now just use formula from ds3 + accelX = accelX * 113 + 512; + accelY = accelY * 113 + 512; + accelZ = accelZ * 113 + 512; + + pad->m_sensors[0].m_value = Clamp0To1023(accelX); + pad->m_sensors[1].m_value = Clamp0To1023(accelY); + pad->m_sensors[2].m_value = Clamp0To1023(accelZ); + + // gyroX is yaw, which is all that we need + f32 gyroX = (((s16)((u16)(buf[16] << 8) | buf[15])) / static_cast(DS4_GYRO_RES_PER_DEG_S)) * -1; + //const int gyroY = ((u16)(buf[14] << 8) | buf[13]) / 256; + //const int gyroZ = ((u16)(buf[18] << 8) | buf[17]) / 256; + + // convert to ds3 + gyroX = gyroX * (123.f / 90.f) + 512; + + pad->m_sensors[3].m_value = Clamp0To1023(gyroX); +} + +void ds4_pad_handler::apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) +{ + auto ds4_dev = std::static_pointer_cast(device); + if (!ds4_dev || !pad) + return; + + auto profile = ds4_dev->config; + + // Attempt to send rumble no matter what + int idx_l = profile->switch_vibration_motors ? 1 : 0; + int idx_s = profile->switch_vibration_motors ? 0 : 1; + + int speed_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : vibration_min; + int speed_small = profile->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : vibration_min; + + bool wireless = ds4_dev->cableState < 1; + bool lowBattery = ds4_dev->batteryLevel < 2; + bool isBlinking = ds4_dev->led_delay_on > 0 || ds4_dev->led_delay_off > 0; + bool newBlinkData = false; + + // we are now wired or have okay battery level -> stop blinking + if (isBlinking && !(wireless && lowBattery)) + { + ds4_dev->led_delay_on = 0; + ds4_dev->led_delay_off = 0; + newBlinkData = true; + } + // we are now wireless and low on battery -> blink + if (!isBlinking && wireless && lowBattery) + { + ds4_dev->led_delay_on = 100; + ds4_dev->led_delay_off = 100; + newBlinkData = true; + } + + ds4_dev->newVibrateData |= ds4_dev->largeVibrate != speed_large || ds4_dev->smallVibrate != speed_small || newBlinkData; + + ds4_dev->largeVibrate = speed_large; + ds4_dev->smallVibrate = speed_small; + + if (ds4_dev->newVibrateData && SendVibrateData(ds4_dev) >= 0) + { + ds4_dev->newVibrateData = false; + } +} diff --git a/rpcs3/ds4_pad_handler.h b/rpcs3/ds4_pad_handler.h index 958ed540d9..c4b81b8c1a 100644 --- a/rpcs3/ds4_pad_handler.h +++ b/rpcs3/ds4_pad_handler.h @@ -47,37 +47,6 @@ class ds4_pad_handler final : public PadHandlerBase KeyCodeCount }; - // Unique names for the config files and our pad settings dialog - const std::unordered_map button_list = - { - { DS4KeyCodes::Triangle, "Triangle" }, - { DS4KeyCodes::Circle, "Circle" }, - { DS4KeyCodes::Cross, "Cross" }, - { DS4KeyCodes::Square, "Square" }, - { DS4KeyCodes::Left, "Left" }, - { DS4KeyCodes::Right, "Right" }, - { DS4KeyCodes::Up, "Up" }, - { DS4KeyCodes::Down, "Down" }, - { DS4KeyCodes::R1, "R1" }, - { DS4KeyCodes::R2, "R2" }, - { DS4KeyCodes::R3, "R3" }, - { DS4KeyCodes::Options, "Options" }, - { DS4KeyCodes::Share, "Share" }, - { DS4KeyCodes::PSButton, "PS Button" }, - { DS4KeyCodes::TouchPad, "Touch Pad" }, - { DS4KeyCodes::L1, "L1" }, - { DS4KeyCodes::L2, "L2" }, - { DS4KeyCodes::L3, "L3" }, - { DS4KeyCodes::LSXNeg, "LS X-" }, - { DS4KeyCodes::LSXPos, "LS X+" }, - { DS4KeyCodes::LSYPos, "LS Y+" }, - { DS4KeyCodes::LSYNeg, "LS Y-" }, - { DS4KeyCodes::RSXNeg, "RS X-" }, - { DS4KeyCodes::RSXPos, "RS X+" }, - { DS4KeyCodes::RSYPos, "RS Y+" }, - { DS4KeyCodes::RSYNeg, "RS Y-" } - }; - enum DS4CalibIndex { // gyro @@ -106,18 +75,17 @@ class ds4_pad_handler final : public PadHandlerBase ReadError, }; - struct DS4Device + struct DS4Device : public PadDevice { hid_device* hidDevice{ nullptr }; - pad_config* config{ nullptr }; std::string path{ "" }; bool btCon{ false }; bool hasCalibData{ false }; - std::array calibData; + std::array calibData{}; bool newVibrateData{ true }; u8 largeVibrate{ 0 }; u8 smallVibrate{ 0 }; - std::array padData; + std::array padData{}; u8 batteryLevel{ 0 }; u8 cableState{ 0 }; u8 led_delay_on{ 0 }; @@ -140,28 +108,19 @@ public: bool Init() override; std::vector ListDevices() override; - bool bindPadToDevice(std::shared_ptr pad, const std::string& device) override; - void ThreadProc() override; - void GetNextButtonPress(const std::string& padId, const std::function& buttonCallback, const std::function& fail_callback, bool get_blacklist = false, const std::vector& buttons = {}) override; void SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b) override; void init_config(pad_config* cfg, const std::string& name) override; private: bool is_init = false; - - std::vector blacklist; - std::vector, std::shared_ptr>> bindings; - std::shared_ptr m_dev; + DS4DataStatus status; private: - std::shared_ptr GetDevice(const std::string& padId, bool try_reconnect = false); - void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) override; - void ProcessDataToPad(const std::shared_ptr& ds4Device, const std::shared_ptr& pad); + std::shared_ptr GetDS4Device(const std::string& padId, bool try_reconnect = false); // Copies data into padData if status is NewData, otherwise buffer is untouched DS4DataStatus GetRawData(const std::shared_ptr& ds4Device); // This function gets us usuable buffer from the rawbuffer of padData // Todo: this currently only handles 'buttons' and not axis or sensors for the time being - std::array GetButtonValues(const std::shared_ptr& ds4Device); bool GetCalibrationData(const std::shared_ptr& ds4Device); void CheckAddDevice(hid_device* hidDevice, hid_device_info* hidDevInfo); int SendVibrateData(const std::shared_ptr& device); @@ -178,4 +137,15 @@ private: return std::numeric_limits::min(); else return static_cast(output); } + + std::shared_ptr get_device(const std::string& device) override; + bool get_is_left_trigger(u64 keyCode) override; + bool get_is_right_trigger(u64 keyCode) override; + bool get_is_left_stick(u64 keyCode) override; + bool get_is_right_stick(u64 keyCode) override; + PadHandlerBase::connection update_connection(const std::shared_ptr& device) override; + void get_extended_info(const std::shared_ptr& device, const std::shared_ptr& pad) override; + void apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) override; + std::unordered_map get_button_values(const std::shared_ptr& device) override; + std::array get_preview_values(std::unordered_map data) override; }; diff --git a/rpcs3/evdev_joystick_handler.cpp b/rpcs3/evdev_joystick_handler.cpp index 32906eedc4..a37862e6d8 100644 --- a/rpcs3/evdev_joystick_handler.cpp +++ b/rpcs3/evdev_joystick_handler.cpp @@ -36,6 +36,8 @@ evdev_joystick_handler::evdev_joystick_handler() : PadHandlerBase(pad_handler::e m_trigger_threshold = trigger_max / 2; m_thumb_threshold = thumb_max / 2; + + m_dev = std::make_shared(); } evdev_joystick_handler::~evdev_joystick_handler() @@ -127,11 +129,14 @@ std::string evdev_joystick_handler::get_device_name(const libevdev* dev) return name; } -bool evdev_joystick_handler::update_device(EvdevDevice& device) +bool evdev_joystick_handler::update_device(const std::shared_ptr& device) { - std::shared_ptr pad = device.pad; - const auto& path = device.path; - libevdev*& dev = device.device; + auto evdev_device = std::static_pointer_cast(device); + if (!evdev_device) + return false; + + const auto& path = evdev_device->path; + libevdev*& dev = evdev_device->device; bool was_connected = dev != nullptr; @@ -173,32 +178,39 @@ bool evdev_joystick_handler::update_device(EvdevDevice& device) void evdev_joystick_handler::update_devs() { - for (auto& device : devices) + for (auto& binding : bindings) { - update_device(device); + update_device(binding.first); } } void evdev_joystick_handler::Close() { - for (auto& device : devices) + for (auto& binding : bindings) { - auto& dev = device.device; - if (dev != nullptr) + auto evdev_device = std::static_pointer_cast(binding.first); + if (evdev_device) { - int fd = libevdev_get_fd(dev); - if (device.effect_id != -1) - ioctl(fd, EVIOCRMFF, device.effect_id); - libevdev_free(dev); - close(fd); + auto& dev = evdev_device->device; + if (dev != nullptr) + { + int fd = libevdev_get_fd(dev); + if (evdev_device->effect_id != -1) + ioctl(fd, EVIOCRMFF, evdev_device->effect_id); + libevdev_free(dev); + close(fd); + } } } } -std::unordered_map> evdev_joystick_handler::GetButtonValues(const EvdevDevice& device) +std::unordered_map> evdev_joystick_handler::GetButtonValues(const std::shared_ptr& device) { std::unordered_map> button_values; - auto& dev = device.device; + if (!device) + return button_values; + + auto& dev = device->device; if (!Init()) return button_values; @@ -241,30 +253,30 @@ std::unordered_map> evdev_joystick_handler::GetButtonV return button_values; } -evdev_joystick_handler::EvdevDevice* evdev_joystick_handler::get_device(const std::string& device) +std::shared_ptr evdev_joystick_handler::get_evdev_device(const std::string& device) { // Add device if not yet present - m_pad_index = add_device(device, true); + m_pad_index = add_device(device, nullptr, true); if (m_pad_index < 0) return nullptr; - EvdevDevice& dev = devices[m_pad_index]; + auto dev = bindings[m_pad_index]; // Check if our device is connected - if (!update_device(dev)) + if (!update_device(dev.first)) return nullptr; - return &dev; + return std::static_pointer_cast(dev.first); } -void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const std::function& callback, const std::function& fail_callback, bool get_blacklist, const std::vector& buttons) +void evdev_joystick_handler::get_next_button_press(const std::string& padId, const std::function)>& callback, const std::function& fail_callback, bool get_blacklist, const std::vector& buttons) { if (get_blacklist) blacklist.clear(); // Get our evdev device - EvdevDevice* device = get_device(padId); - if (device == nullptr || device->device == nullptr) + auto device = get_evdev_device(padId); + if (!device || device->device == nullptr) return fail_callback(padId); libevdev* dev = device->device; @@ -276,7 +288,7 @@ void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const if (ret == LIBEVDEV_READ_STATUS_SYNC) ret = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_SYNC, &evt); - auto data = GetButtonValues(*device); + auto data = GetButtonValues(device); auto find_value = [=](const std::string& name) { @@ -290,7 +302,7 @@ void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const return it != data.end() && dir == it->second.second ? it->second.first : 0; }; - int preview_values[6] = {0, 0, 0, 0, 0, 0}; + std::array preview_values = {0, 0, 0, 0, 0, 0}; if (buttons.size() == 10) { @@ -403,9 +415,9 @@ void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const // https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp // https://github.com/reicast/reicast-emulator/blob/master/core/linux-dist/evdev.cpp // http://www.infradead.org/~mchehab/kernel_docs_pdf/linux-input.pdf -void evdev_joystick_handler::SetRumble(EvdevDevice* device, u16 large, u16 small) +void evdev_joystick_handler::SetRumble(std::shared_ptrdevice, u16 large, u16 small) { - if (device == nullptr || !device->has_rumble || device->effect_id == -2) + if (!device || !device->has_rumble || device->effect_id == -2) return; int fd = libevdev_get_fd(device->device); @@ -483,8 +495,8 @@ void evdev_joystick_handler::SetRumble(EvdevDevice* device, u16 large, u16 small void evdev_joystick_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32/* r*/, s32/* g*/, s32/* b*/) { // Get our evdev device - EvdevDevice* dev = get_device(padId); - if (dev == nullptr) + auto dev = get_evdev_device(padId); + if (!dev) { LOG_ERROR(HLE, "evdev TestVibration: Device [%s] not found! [largeMotor = %d] [smallMotor = %d]", padId, largeMotor, smallMotor); return; @@ -499,49 +511,7 @@ void evdev_joystick_handler::SetPadData(const std::string& padId, u32 largeMotor SetRumble(dev, largeMotor, smallMotor); } -void evdev_joystick_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u16& value, bool ignore_threshold) -{ - // Update the pad button values based on their type and thresholds. - // With this you can use axis or triggers as buttons or vice versa - auto profile = m_dev.config; - u32 code = static_cast(keyCode); - auto checkButton = [&](const EvdevButton& b) - { - return b.code == code && b.type == m_dev.cur_type && b.dir == m_dev.cur_dir; - }; - auto checkButtons = [&](const std::vector& b) - { - return std::find_if(b.begin(), b.end(), checkButton) != b.end(); - }; - - if (checkButton(m_dev.trigger_left)) - { - pressed = value > profile->ltriggerthreshold; - value = pressed ? NormalizeTriggerInput(value, profile->ltriggerthreshold) : 0; - } - else if (checkButton(m_dev.trigger_right)) - { - pressed = value > profile->rtriggerthreshold; - value = pressed ? NormalizeTriggerInput(value, profile->rtriggerthreshold) : 0; - } - else if (checkButtons(m_dev.axis_left)) - { - pressed = value > (ignore_threshold ? 0 : profile->lstickdeadzone); - value = pressed ? NormalizeStickInput(value, profile->lstickdeadzone, profile->lstickmultiplier, ignore_threshold) : 0; - } - else if (checkButtons(m_dev.axis_right)) - { - pressed = value > (ignore_threshold ? 0 : profile->rstickdeadzone); - value = pressed ? NormalizeStickInput(value, profile->rstickdeadzone, profile->rstickmultiplier, ignore_threshold) : 0; - } - else // normal button (should in theory also support sensitive buttons) - { - pressed = value > 0; - value = pressed ? value : 0; - } -} - -int evdev_joystick_handler::GetButtonInfo(const input_event& evt, const EvdevDevice& device, int& value) +int evdev_joystick_handler::GetButtonInfo(const input_event& evt, const std::shared_ptr& device, int& value) { int code = evt.code; int val = evt.value; @@ -565,7 +535,11 @@ int evdev_joystick_handler::GetButtonInfo(const input_event& evt, const EvdevDev } case EV_ABS: { - auto& dev = device.device; + if (!device || !device->device) + { + return -1; + } + auto& dev = device->device; int min = libevdev_get_abs_minimum(dev, code); int max = libevdev_get_abs_maximum(dev, code); @@ -635,7 +609,7 @@ std::vector evdev_joystick_handler::ListDevices() return evdev_joystick_list; } -int evdev_joystick_handler::add_device(const std::string& device, bool in_settings) +int evdev_joystick_handler::add_device(const std::string& device, const std::shared_ptr& pad, bool in_settings) { if (in_settings && m_pad_index >= 0) return m_pad_index; @@ -676,8 +650,12 @@ int evdev_joystick_handler::add_device(const std::string& device, bool in_settin 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](const EvdevDevice &device) { return path == device.path; }); - if (it != devices.end()) + auto it = std::find_if(bindings.begin(), bindings.end(), [&path](std::pair, std::shared_ptr> binding) + { + auto device = std::static_pointer_cast(binding.first); + return device && path == device->path; + }); + if (it != bindings.end()) { libevdev_free(dev); close(fd); @@ -685,11 +663,11 @@ int evdev_joystick_handler::add_device(const std::string& device, bool in_settin } // Alright, now that we've confirmed we haven't added this joystick yet, les do dis. - m_dev.device = dev; - m_dev.path = path; - m_dev.has_rumble = libevdev_has_event_type(dev, EV_FF); - devices.push_back(m_dev); - return devices.size() - 1; + m_dev->device = dev; + m_dev->path = path; + m_dev->has_rumble = libevdev_has_event_type(dev, EV_FF); + bindings.emplace_back(m_dev, pad); + return bindings.size() - 1; } libevdev_free(dev); close(fd); @@ -698,187 +676,188 @@ int evdev_joystick_handler::add_device(const std::string& device, bool in_settin return -1; } -void evdev_joystick_handler::ThreadProc() +PadHandlerBase::connection evdev_joystick_handler::update_connection(const std::shared_ptr& device) { - update_devs(); + bool result = update_device(device); + if (!update_device(device)) + return connection::disconnected; - int padnum = 0; - for (auto& device : devices) + auto evdev_device = std::static_pointer_cast(device); + if (!evdev_device || !evdev_device->device) + return connection::disconnected; + + return connection::connected; +} + +void evdev_joystick_handler::get_mapping(const std::shared_ptr& device, const std::shared_ptr& pad) +{ + std::unordered_map values; + m_dev = std::static_pointer_cast(device); + if (!m_dev || !pad) + return; + + auto& dev = m_dev->device; + if (dev == nullptr) + return; + + // Try to query the latest event from the joystick. + input_event evt; + int ret = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &evt); + + // Grab any pending sync event. + if (ret == LIBEVDEV_READ_STATUS_SYNC) { - m_dev = device; - auto profile = device.config; - auto pad = device.pad; - auto axis_orientations = device.axis_orientations; - auto& dev = device.device; - if (dev == nullptr) - { - if (last_connection_status[padnum] == true) - { - // It was disconnected. - LOG_ERROR(HLE, "evdev device %d disconnected", padnum); - pad->m_port_status &= ~CELL_PAD_STATUS_CONNECTED; - pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; - last_connection_status[padnum] = false; - connected--; - } - padnum++; - continue; - } - - if (last_connection_status[padnum] == false) - { - // Connection status changed from disconnected to connected. - LOG_ERROR(HLE, "evdev device %d reconnected", padnum); - pad->m_port_status |= CELL_PAD_STATUS_CONNECTED; - pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; - last_connection_status[padnum] = true; - connected++; - } - padnum++; - - // Handle vibration - int idx_l = profile->switch_vibration_motors ? 1 : 0; - int idx_s = profile->switch_vibration_motors ? 0 : 1; - u16 force_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : vibration_min; - u16 force_small = profile->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min; - SetRumble(&device, force_large, force_small); - - // Try to query the latest event from the joystick. - input_event evt; - int ret = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &evt); - - // Grab any pending sync event. - if (ret == LIBEVDEV_READ_STATUS_SYNC) - { - LOG_NOTICE(GENERAL, "Captured sync event"); - 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: %s [errno %d]", strerror(-ret), -ret); - continue; - } - - m_dev.cur_type = evt.type; - - int value; - int button_code = GetButtonInfo(evt, device, value); - if (button_code < 0 || value < 0) - continue; - - // Translate any corresponding keycodes to our normal DS3 buttons and triggers - for (int i = 0; i < static_cast(pad->m_buttons.size() - 1); i++) // skip reserved button - { - if (pad->m_buttons[i].m_keyCode != button_code) - continue; - - // Be careful to handle mapped axis specially - if (evt.type == EV_ABS) - { - // get axis direction and skip on error or set to 0 if the stick/hat is actually pointing to the other direction. - // maybe mimic on error, needs investigation. FindAxisDirection should ideally never return -1 anyway - int direction = FindAxisDirection(axis_orientations, i); - m_dev.cur_dir = direction; - - if (direction < 0) - { - LOG_ERROR(HLE, "FindAxisDirection = %d, Button Nr.%d, value = %d", direction, i, value); - continue; - } - else if (direction != (m_is_negative ? 1 : 0)) - { - pad->m_buttons[i].m_value = 0; - pad->m_buttons[i].m_pressed = 0; - continue; - } - } - - pad->m_buttons[i].m_value = static_cast(value); - TranslateButtonPress(button_code, pad->m_buttons[i].m_pressed, pad->m_buttons[i].m_value); - } - - // Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now) - for (int idx = 0; idx < static_cast(pad->m_sticks.size()); idx++) - { - bool pressed_min = false, pressed_max = false; - - // m_keyCodeMin is the mapped key for left or down - if (pad->m_sticks[idx].m_keyCodeMin == button_code) - { - bool is_direction_min = false; - - if (!m_is_button_or_trigger && evt.type == EV_ABS) - { - int index = BUTTON_COUNT + (idx * 2) + 1; - int min_direction = FindAxisDirection(axis_orientations, index); - m_dev.cur_dir = min_direction; - - if (min_direction < 0) - LOG_ERROR(HLE, "keyCodeMin FindAxisDirection = %d, Axis Nr.%d, Button Nr.%d, value = %d", min_direction, idx, index, value); - else - is_direction_min = m_is_negative == (min_direction == 1); - } - - if (m_is_button_or_trigger || is_direction_min) - { - device.val_min[idx] = value; - TranslateButtonPress(button_code, pressed_min, device.val_min[idx], true); - } - else // set to 0 to avoid remnant counter axis values - device.val_min[idx] = 0; - } - - // m_keyCodeMax is the mapped key for right or up - if (pad->m_sticks[idx].m_keyCodeMax == button_code) - { - bool is_direction_max = false; - - if (!m_is_button_or_trigger && evt.type == EV_ABS) - { - int index = BUTTON_COUNT + (idx * 2); - int max_direction = FindAxisDirection(axis_orientations, index); - m_dev.cur_dir = max_direction; - - if (max_direction < 0) - LOG_ERROR(HLE, "keyCodeMax FindAxisDirection = %d, Axis Nr.%d, Button Nr.%d, value = %d", max_direction, idx, index, value); - else - is_direction_max = m_is_negative == (max_direction == 1); - } - - if (m_is_button_or_trigger || is_direction_max) - { - device.val_max[idx] = value; - TranslateButtonPress(button_code, pressed_max, device.val_max[idx], true); - } - else // set to 0 to avoid remnant counter axis values - device.val_max[idx] = 0; - } - - // cancel out opposing values and get the resulting difference. if there was no change, use the old value. - device.stick_val[idx] = device.val_max[idx] - device.val_min[idx]; - } - - // Normalize our two stick's axis based on the thresholds - u16 lx, ly, rx, ry; - - // Normalize our two stick's axis based on the thresholds - std::tie(lx, ly) = NormalizeStickDeadzone(device.stick_val[0], device.stick_val[1], profile->lstickdeadzone); - std::tie(rx, ry) = NormalizeStickDeadzone(device.stick_val[2], device.stick_val[3], profile->rstickdeadzone); - - if (profile->padsquircling != 0) - { - std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling); - std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling); - } - - pad->m_sticks[0].m_value = lx; - pad->m_sticks[1].m_value = 255 - ly; - pad->m_sticks[2].m_value = rx; - pad->m_sticks[3].m_value = 255 - ry; + LOG_NOTICE(GENERAL, "Captured sync event"); + 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: %s [errno %d]", strerror(-ret), -ret); + return; + } + + m_dev->cur_type = evt.type; + + int value; + int button_code = GetButtonInfo(evt, m_dev, value); + if (button_code < 0 || value < 0) + return; + + auto axis_orientations = m_dev->axis_orientations; + + // Translate any corresponding keycodes to our normal DS3 buttons and triggers + for (int i = 0; i < static_cast(pad->m_buttons.size()); i++) + { + if (pad->m_buttons[i].m_keyCode != button_code) + continue; + + // Be careful to handle mapped axis specially + if (evt.type == EV_ABS) + { + // get axis direction and skip on error or set to 0 if the stick/hat is actually pointing to the other direction. + // maybe mimic on error, needs investigation. FindAxisDirection should ideally never return -1 anyway + int direction = FindAxisDirection(axis_orientations, i); + m_dev->cur_dir = direction; + + if (direction < 0) + { + LOG_ERROR(HLE, "FindAxisDirection = %d, Button Nr.%d, value = %d", direction, i, value); + continue; + } + else if (direction != (m_is_negative ? 1 : 0)) + { + pad->m_buttons[i].m_value = 0; + pad->m_buttons[i].m_pressed = 0; + continue; + } + } + + pad->m_buttons[i].m_value = static_cast(value); + TranslateButtonPress(m_dev, button_code, pad->m_buttons[i].m_pressed, pad->m_buttons[i].m_value); + } + + // Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now) + for (int idx = 0; idx < static_cast(pad->m_sticks.size()); idx++) + { + bool pressed_min = false; + bool pressed_max = false; + + // m_keyCodeMin is the mapped key for left or down + if (pad->m_sticks[idx].m_keyCodeMin == button_code) + { + bool is_direction_min = false; + + if (!m_is_button_or_trigger && evt.type == EV_ABS) + { + int index = BUTTON_COUNT + (idx * 2) + 1; + int min_direction = FindAxisDirection(axis_orientations, index); + m_dev->cur_dir = min_direction; + + if (min_direction < 0) + LOG_ERROR(HLE, "keyCodeMin FindAxisDirection = %d, Axis Nr.%d, Button Nr.%d, value = %d", min_direction, idx, index, value); + else + is_direction_min = m_is_negative == (min_direction == 1); + } + + if (m_is_button_or_trigger || is_direction_min) + { + m_dev->val_min[idx] = value; + TranslateButtonPress(m_dev, button_code, pressed_min, m_dev->val_min[idx], true); + } + else // set to 0 to avoid remnant counter axis values + m_dev->val_min[idx] = 0; + } + + // m_keyCodeMax is the mapped key for right or up + if (pad->m_sticks[idx].m_keyCodeMax == button_code) + { + bool is_direction_max = false; + + if (!m_is_button_or_trigger && evt.type == EV_ABS) + { + int index = BUTTON_COUNT + (idx * 2); + int max_direction = FindAxisDirection(axis_orientations, index); + m_dev->cur_dir = max_direction; + + if (max_direction < 0) + LOG_ERROR(HLE, "keyCodeMax FindAxisDirection = %d, Axis Nr.%d, Button Nr.%d, value = %d", max_direction, idx, index, value); + else + is_direction_max = m_is_negative == (max_direction == 1); + } + + if (m_is_button_or_trigger || is_direction_max) + { + m_dev->val_max[idx] = value; + TranslateButtonPress(m_dev, button_code, pressed_max, m_dev->val_max[idx], true); + } + else // set to 0 to avoid remnant counter axis values + m_dev->val_max[idx] = 0; + } + + // cancel out opposing values and get the resulting difference. if there was no change, use the old value. + m_dev->stick_val[idx] = m_dev->val_max[idx] - m_dev->val_min[idx]; + } + + const auto profile = m_dev->config; + + // Normalize our two stick's axis based on the thresholds + u16 lx, ly, rx, ry; + + // Normalize our two stick's axis based on the thresholds + std::tie(lx, ly) = NormalizeStickDeadzone(m_dev->stick_val[0], m_dev->stick_val[1], profile->lstickdeadzone); + std::tie(rx, ry) = NormalizeStickDeadzone(m_dev->stick_val[2], m_dev->stick_val[3], profile->rstickdeadzone); + + if (profile->padsquircling != 0) + { + std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling); + std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling); + } + + pad->m_sticks[0].m_value = lx; + pad->m_sticks[1].m_value = 255 - ly; + pad->m_sticks[2].m_value = rx; + pad->m_sticks[3].m_value = 255 - ry; + + return; +} + +void evdev_joystick_handler::apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) +{ + auto evdev_device = std::static_pointer_cast(device); + if (!evdev_device) + return; + + auto profile = device->config; + + // Handle vibration + int idx_l = profile->switch_vibration_motors ? 1 : 0; + int idx_s = profile->switch_vibration_motors ? 0 : 1; + u16 force_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : vibration_min; + u16 force_small = profile->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min; + SetRumble(evdev_device, force_large, force_small); } // Search axis_orientations map for the direction by index, returns -1 if not found, 0 for positive and 1 for negative @@ -893,16 +872,19 @@ int evdev_joystick_handler::FindAxisDirection(const std::unordered_map pad, const std::string& device) { + if (!pad) + return false; + Init(); std::unordered_map axis_orientations; int i = 0; // increment to know the axis location (17-24). Be careful if you ever add more find_key() calls in here (BUTTON_COUNT = 17) int last_type = EV_ABS; - int index = static_cast(devices.size()); + int index = static_cast(bindings.size()); m_pad_configs[index].load(); - m_dev.config = &m_pad_configs[index]; - pad_config* p_profile = m_dev.config; + m_dev->config = &m_pad_configs[index]; + pad_config* p_profile = m_dev->config; if (p_profile == nullptr) return false; @@ -954,11 +936,11 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->cross), CELL_PAD_CTRL_CROSS); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->square), CELL_PAD_CTRL_SQUARE); - m_dev.trigger_left = evdevbutton(p_profile->l2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev.trigger_left.code, CELL_PAD_CTRL_L2); + m_dev->trigger_left = evdevbutton(p_profile->l2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev->trigger_left.code, CELL_PAD_CTRL_L2); - m_dev.trigger_right = evdevbutton(p_profile->r2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev.trigger_right.code, CELL_PAD_CTRL_R2); + m_dev->trigger_right = evdevbutton(p_profile->r2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev->trigger_right.code, CELL_PAD_CTRL_R2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->l1), CELL_PAD_CTRL_L1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->r1), CELL_PAD_CTRL_R1); @@ -973,19 +955,19 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->right), CELL_PAD_CTRL_RIGHT); //pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved (and currently not in use by rpcs3 at all) - m_dev.axis_left[0] = evdevbutton(p_profile->ls_right); - m_dev.axis_left[1] = evdevbutton(p_profile->ls_left); - m_dev.axis_left[2] = evdevbutton(p_profile->ls_up); - m_dev.axis_left[3] = evdevbutton(p_profile->ls_down); - m_dev.axis_right[0] = evdevbutton(p_profile->rs_right); - m_dev.axis_right[1] = evdevbutton(p_profile->rs_left); - m_dev.axis_right[2] = evdevbutton(p_profile->rs_up); - m_dev.axis_right[3] = evdevbutton(p_profile->rs_down); + m_dev->axis_left[0] = evdevbutton(p_profile->ls_right); + m_dev->axis_left[1] = evdevbutton(p_profile->ls_left); + m_dev->axis_left[2] = evdevbutton(p_profile->ls_up); + m_dev->axis_left[3] = evdevbutton(p_profile->ls_down); + m_dev->axis_right[0] = evdevbutton(p_profile->rs_right); + m_dev->axis_right[1] = evdevbutton(p_profile->rs_left); + m_dev->axis_right[2] = evdevbutton(p_profile->rs_up); + m_dev->axis_right[3] = evdevbutton(p_profile->rs_down); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, m_dev.axis_left[1].code, m_dev.axis_left[0].code); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, m_dev.axis_left[3].code, m_dev.axis_left[2].code); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, m_dev.axis_right[1].code, m_dev.axis_right[0].code); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, m_dev.axis_right[3].code, m_dev.axis_right[2].code); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, m_dev->axis_left[1].code, m_dev->axis_left[0].code); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, m_dev->axis_left[3].code, m_dev->axis_left[2].code); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, m_dev->axis_right[1].code, m_dev->axis_right[0].code); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, m_dev->axis_right[3].code, m_dev->axis_right[2].code); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); @@ -995,14 +977,43 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std pad->m_vibrateMotors.emplace_back(true, 0); pad->m_vibrateMotors.emplace_back(false, 0); - m_dev.pad = pad; - m_dev.axis_orientations = axis_orientations; + m_dev->axis_orientations = axis_orientations; - if (!add_device(device, false)) + if (add_device(device, pad, false) < 0) LOG_WARNING(HLE, "evdev add_device in bindPadToDevice failed for device %s", device); update_devs(); return true; } +bool evdev_joystick_handler::check_button(const EvdevButton& b, const u32 code) +{ + return m_dev && b.code == code && b.type == m_dev->cur_type && b.dir == m_dev->cur_dir; +} + +bool evdev_joystick_handler::check_buttons(const std::vector& b, const u32 code) +{ + return std::find_if(b.begin(), b.end(), [this, code](const EvdevButton& b) { return check_button(b, code); }) != b.end(); +}; + +bool evdev_joystick_handler::get_is_left_trigger(u64 keyCode) +{ + return keyCode == check_button(m_dev->trigger_left, static_cast(keyCode)); +} + +bool evdev_joystick_handler::get_is_right_trigger(u64 keyCode) +{ + return keyCode == check_button(m_dev->trigger_right, static_cast(keyCode)); +} + +bool evdev_joystick_handler::get_is_left_stick(u64 keyCode) +{ + return keyCode == check_buttons(m_dev->axis_left, static_cast(keyCode)); +} + +bool evdev_joystick_handler::get_is_right_stick(u64 keyCode) +{ + return keyCode == check_buttons(m_dev->axis_right, static_cast(keyCode)); +} + #endif diff --git a/rpcs3/evdev_joystick_handler.h b/rpcs3/evdev_joystick_handler.h index dc842b2345..02b604fc71 100644 --- a/rpcs3/evdev_joystick_handler.h +++ b/rpcs3/evdev_joystick_handler.h @@ -1,4 +1,5 @@ #pragma once +#ifdef HAVE_LIBEVDEV #include "Utilities/types.h" #include "Utilities/Config.h" @@ -303,12 +304,10 @@ class evdev_joystick_handler final : public PadHandlerBase int type; }; - struct EvdevDevice + struct EvdevDevice : public PadDevice { libevdev* device{ nullptr }; - pad_config* config{ nullptr }; std::string path; - std::shared_ptr pad; std::unordered_map axis_orientations; // value is true if key was found in rev_axis_list s32 stick_val[4] = { 0, 0, 0, 0 }; u16 val_min[4] = { 0, 0, 0, 0 }; @@ -336,21 +335,19 @@ public: bool Init() override; std::vector ListDevices() override; bool bindPadToDevice(std::shared_ptr pad, const std::string& device) override; - void ThreadProc() override; void Close(); - void GetNextButtonPress(const std::string& padId, const std::function& callback, const std::function& fail_callback, bool get_blacklist = false, const std::vector& buttons = {}) override; + void get_next_button_press(const std::string& padId, const std::function)>& callback, const std::function& fail_callback, bool get_blacklist = false, const std::vector& buttons = {}) override; void SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b) override; private: - void TranslateButtonPress(u64 keyCode, bool& pressed, u16& value, bool ignore_threshold = false) override; - EvdevDevice* get_device(const std::string& device); + std::shared_ptr get_evdev_device(const std::string& device); std::string get_device_name(const libevdev* dev); - bool update_device(EvdevDevice& device); + bool update_device(const std::shared_ptr& device); void update_devs(); - int add_device(const std::string& device, bool in_settings = false); - int GetButtonInfo(const input_event& evt, const EvdevDevice& device, int& button_code); - std::unordered_map> GetButtonValues(const EvdevDevice& device); - void SetRumble(EvdevDevice* device, u16 large, u16 small); + int add_device(const std::string& device, const std::shared_ptr& pad, bool in_settings = false); + int GetButtonInfo(const input_event& evt, const std::shared_ptr& device, int& button_code); + std::unordered_map> GetButtonValues(const std::shared_ptr& device); + void SetRumble(std::shared_ptr device, u16 large, u16 small); // Search axis_orientations map for the direction by index, returns -1 if not found, 0 for positive and 1 for negative int FindAxisDirection(const std::unordered_map& map, int index); @@ -358,10 +355,23 @@ private: positive_axis m_pos_axis_config; std::vector m_positive_axis; std::vector blacklist; - std::vector devices; int m_pad_index = -1; - EvdevDevice m_dev; + std::shared_ptr m_dev; bool m_is_button_or_trigger; bool m_is_negative; bool m_is_init = false; + + bool check_button(const EvdevButton& b, const u32 code); + bool check_buttons(const std::vector& b, const u32 code); + +protected: + PadHandlerBase::connection update_connection(const std::shared_ptr& device) override; + void get_mapping(const std::shared_ptr& device, const std::shared_ptr& pad) override; + void apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad); + bool get_is_left_trigger(u64 keyCode) override; + bool get_is_right_trigger(u64 keyCode) override; + bool get_is_left_stick(u64 keyCode) override; + bool get_is_right_stick(u64 keyCode) override; }; + +#endif diff --git a/rpcs3/keyboard_pad_handler.cpp b/rpcs3/keyboard_pad_handler.cpp index 915d411f63..d2a1296d61 100644 --- a/rpcs3/keyboard_pad_handler.cpp +++ b/rpcs3/keyboard_pad_handler.cpp @@ -595,7 +595,7 @@ void keyboard_pad_handler::ThreadProc() bindings[i]->m_port_status |= CELL_PAD_STATUS_CONNECTED; bindings[i]->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; last_connection_status[i] = true; - connected++; + connected_devices++; } else { diff --git a/rpcs3/keyboard_pad_handler.h b/rpcs3/keyboard_pad_handler.h index bef354253d..9317a7db41 100644 --- a/rpcs3/keyboard_pad_handler.h +++ b/rpcs3/keyboard_pad_handler.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Utilities/Config.h" #include "Emu/Io/PadHandler.h" diff --git a/rpcs3/main_application.cpp b/rpcs3/main_application.cpp index 4af3b61178..7f48e41634 100644 --- a/rpcs3/main_application.cpp +++ b/rpcs3/main_application.cpp @@ -62,7 +62,7 @@ EmuCallbacks main_application::CreateCallbacks() { EmuCallbacks callbacks; - callbacks.reset_pads = [this](const std::string& title_id = "") + callbacks.reset_pads = [this](const std::string& title_id) { pad::get_current_handler()->Reset(title_id); }; diff --git a/rpcs3/mm_joystick_handler.cpp b/rpcs3/mm_joystick_handler.cpp index df92cfb87f..66ec3b158d 100644 --- a/rpcs3/mm_joystick_handler.cpp +++ b/rpcs3/mm_joystick_handler.cpp @@ -77,17 +77,17 @@ bool mm_joystick_handler::Init() return true; m_devices.clear(); - m_supported_joysticks = joyGetNumDevs(); + u32 supported_joysticks = joyGetNumDevs(); - if (m_supported_joysticks <= 0) + if (supported_joysticks <= 0) { LOG_ERROR(GENERAL, "mmjoy: Driver doesn't support Joysticks"); return false; } - LOG_NOTICE(GENERAL, "mmjoy: Driver supports %u joysticks", m_supported_joysticks); + LOG_NOTICE(GENERAL, "mmjoy: Driver supports %u joysticks", supported_joysticks); - for (u32 i = 0; i < m_supported_joysticks; i++) + for (u32 i = 0; i < supported_joysticks; i++) { MMJOYDevice dev; @@ -116,23 +116,13 @@ std::vector mm_joystick_handler::ListDevices() return devices; } -bool mm_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std::string& device) +std::array mm_joystick_handler::get_mapped_key_codes(const std::shared_ptr& device, const pad_config* profile) { - if (!Init()) - return false; + std::array mapping{ 0 }; - int id = GetIDByName(device); - if (id < 0) - return false; - - std::shared_ptr joy_device = std::make_shared(m_devices.at(id)); - - int index = static_cast(bindings.size()); - m_pad_configs[index].load(); - joy_device->config = &m_pad_configs[index]; - pad_config* p_profile = joy_device->config; - if (p_profile == nullptr) - return false; + auto joy_device = std::static_pointer_cast(device); + if (!joy_device) + return mapping; auto find_key = [=](const cfg::string& name) { @@ -144,147 +134,47 @@ bool mm_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std::s return static_cast(key); }; - pad->Init - ( - CELL_PAD_STATUS_DISCONNECTED, - CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE, - CELL_PAD_DEV_TYPE_STANDARD, - p_profile->device_class_type - ); + joy_device->trigger_left = find_key(profile->l2); + joy_device->trigger_right = find_key(profile->r2); + joy_device->axis_left[0] = find_key(profile->ls_left); + joy_device->axis_left[1] = find_key(profile->ls_right); + joy_device->axis_left[2] = find_key(profile->ls_down); + joy_device->axis_left[3] = find_key(profile->ls_up); + joy_device->axis_right[0] = find_key(profile->rs_left); + joy_device->axis_right[1] = find_key(profile->rs_right); + joy_device->axis_right[2] = find_key(profile->rs_down); + joy_device->axis_right[3] = find_key(profile->rs_up); - joy_device->trigger_left = find_key(p_profile->l2); - joy_device->trigger_right = find_key(p_profile->r2); - joy_device->axis_left[0] = find_key(p_profile->ls_left); - joy_device->axis_left[1] = find_key(p_profile->ls_right); - joy_device->axis_left[2] = find_key(p_profile->ls_down); - joy_device->axis_left[3] = find_key(p_profile->ls_up); - joy_device->axis_right[0] = find_key(p_profile->rs_left); - joy_device->axis_right[1] = find_key(p_profile->rs_right); - joy_device->axis_right[2] = find_key(p_profile->rs_down); - joy_device->axis_right[3] = find_key(p_profile->rs_up); + mapping[button::up] = find_key(profile->up); + mapping[button::down] = find_key(profile->down); + mapping[button::left] = find_key(profile->left); + mapping[button::right] = find_key(profile->right); + mapping[button::cross] = find_key(profile->cross); + mapping[button::square] = find_key(profile->square); + mapping[button::circle] = find_key(profile->circle); + mapping[button::triangle] = find_key(profile->triangle); + mapping[button::l1] = find_key(profile->l1); + mapping[button::l2] = (u32)joy_device->trigger_left; + mapping[button::l3] = find_key(profile->l3); + mapping[button::r1] = find_key(profile->r1); + mapping[button::r2] = (u32)joy_device->trigger_right; + mapping[button::r3] = find_key(profile->r3); + mapping[button::start] = find_key(profile->start); + mapping[button::select] = find_key(profile->select); + mapping[button::ps] = find_key(profile->ps); + mapping[button::ls_left] = joy_device->axis_left[0]; + mapping[button::ls_right] = joy_device->axis_left[1]; + mapping[button::ls_down] = joy_device->axis_left[2]; + mapping[button::ls_up] = joy_device->axis_left[3]; + mapping[button::rs_left] = joy_device->axis_right[0]; + mapping[button::rs_right] = joy_device->axis_right[1]; + mapping[button::rs_down] = joy_device->axis_right[2]; + mapping[button::rs_up] = joy_device->axis_right[3]; - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->triangle), CELL_PAD_CTRL_TRIANGLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->circle), CELL_PAD_CTRL_CIRCLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->cross), CELL_PAD_CTRL_CROSS); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->square), CELL_PAD_CTRL_SQUARE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, (u32) joy_device->trigger_left, CELL_PAD_CTRL_L2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, (u32) joy_device->trigger_right, CELL_PAD_CTRL_R2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->l1), CELL_PAD_CTRL_L1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->r1), CELL_PAD_CTRL_R1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->start), CELL_PAD_CTRL_START); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->select), CELL_PAD_CTRL_SELECT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->l3), CELL_PAD_CTRL_L3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->r3), CELL_PAD_CTRL_R3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->up), CELL_PAD_CTRL_UP); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->down), CELL_PAD_CTRL_DOWN); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->left), CELL_PAD_CTRL_LEFT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->right), CELL_PAD_CTRL_RIGHT); - //pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved (and currently not in use by rpcs3 at all) - - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, joy_device->axis_left[0], joy_device->axis_left[1]); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, joy_device->axis_left[2], joy_device->axis_left[3]); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, joy_device->axis_right[0], joy_device->axis_right[1]); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, joy_device->axis_right[2], joy_device->axis_right[3]); - - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 512); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 512); - - pad->m_vibrateMotors.emplace_back(true, 0); - pad->m_vibrateMotors.emplace_back(false, 0); - - bindings.emplace_back(joy_device, pad); - - return true; + return mapping; } -void mm_joystick_handler::ThreadProc() -{ - MMRESULT status; - - for (u32 i = 0; i != bindings.size(); ++i) - { - m_dev = bindings[i].first; - auto pad = bindings[i].second; - auto profile = m_dev->config; - status = joyGetPosEx(m_dev->device_id, &m_dev->device_info); - - if (status != JOYERR_NOERROR) - { - if (last_connection_status[i] == true) - { - LOG_ERROR(HLE, "MMJOY Device %d disconnected.", m_dev->device_id); - pad->m_port_status &= ~CELL_PAD_STATUS_CONNECTED; - pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; - last_connection_status[i] = false; - connected--; - } - continue; - } - - if (last_connection_status[i] == false) - { - if (GetMMJOYDevice(m_dev->device_id, m_dev.get()) == false) - continue; - LOG_SUCCESS(HLE, "MMJOY Device %d reconnected.", m_dev->device_id); - pad->m_port_status |= CELL_PAD_STATUS_CONNECTED; - pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; - last_connection_status[i] = true; - connected++; - } - - auto button_values = GetButtonValues(m_dev->device_info, m_dev->device_caps); - - // Translate any corresponding keycodes to our normal DS3 buttons and triggers - for (auto& btn : pad->m_buttons) - { - btn.m_value = button_values[btn.m_keyCode]; - TranslateButtonPress(btn.m_keyCode, btn.m_pressed, btn.m_value); - } - - s32 stick_val[4]{0}; - - // Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now) - for (int i = 0; i < static_cast(pad->m_sticks.size()); i++) - { - bool pressed; - - // m_keyCodeMin is the mapped key for left or down - u32 key_min = pad->m_sticks[i].m_keyCodeMin; - u16 val_min = button_values[key_min]; - TranslateButtonPress(key_min, pressed, val_min, true); - - // m_keyCodeMax is the mapped key for right or up - u32 key_max = pad->m_sticks[i].m_keyCodeMax; - u16 val_max = button_values[key_max]; - TranslateButtonPress(key_max, pressed, val_max, true); - - // cancel out opposing values and get the resulting difference - stick_val[i] = val_max - val_min; - } - - u16 lx, ly, rx, ry; - - // Normalize our two stick's axis based on the thresholds - std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], profile->lstickdeadzone); - std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], profile->rstickdeadzone); - - if (profile->padsquircling != 0) - { - std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling); - std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling); - } - - pad->m_sticks[0].m_value = lx; - pad->m_sticks[1].m_value = 255 - ly; - pad->m_sticks[2].m_value = rx; - pad->m_sticks[3].m_value = 255 - ry; - } -} - -void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std::function& callback, const std::function& fail_callback, bool get_blacklist, const std::vector& buttons) +void mm_joystick_handler::get_next_button_press(const std::string& padId, const std::function)>& callback, const std::function& fail_callback, bool get_blacklist, const std::vector& buttons) { if (get_blacklist) blacklist.clear(); @@ -301,7 +191,7 @@ void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std id = GetIDByName(padId); if (id < 0) { - LOG_ERROR(GENERAL, "MMJOY GetNextButtonPress for device [%s] failed with id = %d", padId, id); + LOG_ERROR(GENERAL, "MMJOY get_next_button_press for device [%s] failed with id = %d", padId, id); return fail_callback(padId); } } @@ -406,7 +296,7 @@ void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std return static_cast(key); }; - int preview_values[6] = { 0, 0, 0, 0, 0, 0 }; + std::array preview_values = { 0, 0, 0, 0, 0, 0 }; if (buttons.size() == 10) { preview_values[0] = data[find_key(buttons[0])]; @@ -429,39 +319,6 @@ void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std } } -void mm_joystick_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold) -{ - // Update the pad button values based on their type and thresholds. - // With this you can use axis or triggers as buttons or vice versa - auto p_profile = m_dev->config; - - if (keyCode == m_dev->trigger_left) - { - pressed = val > (ignore_threshold ? 0 : p_profile->ltriggerthreshold); - val = pressed ? NormalizeTriggerInput(val, p_profile->ltriggerthreshold) : 0; - } - else if (keyCode == m_dev->trigger_right) - { - pressed = val > (ignore_threshold ? 0 : p_profile->rtriggerthreshold); - val = pressed ? NormalizeTriggerInput(val, p_profile->rtriggerthreshold) : 0; - } - else if (std::find(m_dev->axis_left.begin(), m_dev->axis_left.end(), keyCode) != m_dev->axis_left.end()) - { - pressed = val > (ignore_threshold ? 0 : p_profile->lstickdeadzone); - val = pressed ? NormalizeStickInput(val, p_profile->lstickdeadzone, p_profile->lstickmultiplier, ignore_threshold) : 0; - } - else if (std::find(m_dev->axis_right.begin(), m_dev->axis_right.end(), keyCode) != m_dev->axis_right.end()) - { - pressed = val > (ignore_threshold ? 0 : p_profile->rstickdeadzone); - val = pressed ? NormalizeStickInput(val, p_profile->rstickdeadzone, p_profile->rstickmultiplier, ignore_threshold) : 0; - } - else // normal button (should in theory also support sensitive buttons) - { - pressed = val > 0; - val = pressed ? val : 0; - } -} - std::unordered_map mm_joystick_handler::GetButtonValues(const JOYINFOEX& js_info, const JOYCAPS& js_caps) { std::unordered_map button_values; @@ -554,6 +411,14 @@ std::unordered_map mm_joystick_handler::GetButtonValues(const JOYINFOE return button_values; } +std::unordered_map mm_joystick_handler::get_button_values(const std::shared_ptr& device) +{ + auto dev = std::static_pointer_cast(device); + if (!dev) + return std::unordered_map(); + return GetButtonValues(dev->device_info, dev->device_caps); +} + int mm_joystick_handler::GetIDByName(const std::string& name) { for (auto dev : m_devices) @@ -567,9 +432,7 @@ int mm_joystick_handler::GetIDByName(const std::string& name) bool mm_joystick_handler::GetMMJOYDevice(int index, MMJOYDevice* dev) { if (!dev) - { return false; - } JOYINFOEX js_info; JOYCAPS js_caps; @@ -593,4 +456,51 @@ bool mm_joystick_handler::GetMMJOYDevice(int index, MMJOYDevice* dev) return true; } +std::shared_ptr mm_joystick_handler::get_device(const std::string& device) +{ + if (!Init()) + return false; + + int id = GetIDByName(device); + if (id < 0) + return false; + + std::shared_ptr joy_device = std::make_shared(m_devices.at(id)); + return joy_device; +} + +bool mm_joystick_handler::get_is_left_trigger(u64 keyCode) +{ + return m_dev && m_dev->trigger_left == keyCode; +} + +bool mm_joystick_handler::get_is_right_trigger(u64 keyCode) +{ + return m_dev && m_dev->trigger_right == keyCode; +} + +bool mm_joystick_handler::get_is_left_stick(u64 keyCode) +{ + return m_dev && std::find(m_dev->axis_left.begin(), m_dev->axis_left.end(), keyCode) != m_dev->axis_left.end(); +} + +bool mm_joystick_handler::get_is_right_stick(u64 keyCode) +{ + return m_dev && std::find(m_dev->axis_right.begin(), m_dev->axis_right.end(), keyCode) != m_dev->axis_right.end(); +} + +PadHandlerBase::connection mm_joystick_handler::update_connection(const std::shared_ptr& device) +{ + auto dev = std::static_pointer_cast(device); + if (!dev) + return connection::disconnected; + + MMRESULT status = joyGetPosEx(dev->device_id, &dev->device_info); + if (status == JOYERR_NOERROR && GetMMJOYDevice(dev->device_id, dev.get())) + { + return connection::connected; + } + return connection::disconnected; +} + #endif diff --git a/rpcs3/mm_joystick_handler.h b/rpcs3/mm_joystick_handler.h index 7b09989d3d..a44864d765 100644 --- a/rpcs3/mm_joystick_handler.h +++ b/rpcs3/mm_joystick_handler.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Emu/Io/PadHandler.h" #include @@ -86,13 +86,12 @@ class mm_joystick_handler final : public PadHandlerBase { joy_v_neg, "V-" }, }; - struct MMJOYDevice + struct MMJOYDevice : public PadDevice { u32 device_id{ 0 }; std::string device_name{ "" }; - pad_config* config{ nullptr }; - JOYINFOEX device_info; - JOYCAPS device_caps; + JOYINFOEX device_info{}; + JOYCAPS device_caps{}; u64 trigger_left = 0; u64 trigger_right = 0; std::vector axis_left = { 0,0,0,0 }; @@ -106,22 +105,26 @@ public: bool Init() override; std::vector ListDevices() override; - bool bindPadToDevice(std::shared_ptr pad, const std::string& device) override; - void ThreadProc() override; - void GetNextButtonPress(const std::string& padId, const std::function& callback, const std::function& fail_callback, bool get_blacklist = false, const std::vector& buttons = {}) override; + void get_next_button_press(const std::string& padId, const std::function)>& callback, const std::function& fail_callback, bool get_blacklist = false, const std::vector& buttons = {}) override; void init_config(pad_config* cfg, const std::string& name) override; private: - void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) override; std::unordered_map GetButtonValues(const JOYINFOEX& js_info, const JOYCAPS& js_caps); int GetIDByName(const std::string& name); bool GetMMJOYDevice(int index, MMJOYDevice* dev); bool is_init = false; - u32 m_supported_joysticks = 0; std::vector blacklist; - std::unordered_map m_devices; - std::vector, std::shared_ptr>> bindings; std::shared_ptr m_dev; + std::unordered_map m_devices; + + std::array get_mapped_key_codes(const std::shared_ptr& device, const pad_config* profile) override; + std::shared_ptr get_device(const std::string& device) override; + bool get_is_left_trigger(u64 keyCode) override; + bool get_is_right_trigger(u64 keyCode) override; + bool get_is_left_stick(u64 keyCode) override; + bool get_is_right_stick(u64 keyCode) override; + PadHandlerBase::connection update_connection(const std::shared_ptr& device) override; + std::unordered_map get_button_values(const std::shared_ptr& device) override; }; diff --git a/rpcs3/pad_thread.cpp b/rpcs3/pad_thread.cpp index 5e66319bfa..448bed77e5 100644 --- a/rpcs3/pad_thread.cpp +++ b/rpcs3/pad_thread.cpp @@ -185,15 +185,15 @@ void pad_thread::ThreadFunc() Init(); } - u32 connected = 0; + u32 connected_devices = 0; for (auto& cur_pad_handler : handlers) { cur_pad_handler.second->ThreadProc(); - connected += cur_pad_handler.second->connected; + connected_devices += cur_pad_handler.second->connected_devices; } - m_info.now_connect = connected + num_ldd_pad; + m_info.now_connect = connected_devices + num_ldd_pad; // The following section is only reached when a dialog was closed and the pads are still intercepted. // As long as any of the listed buttons is pressed, cellPadGetData will ignore all input (needed for Hotline Miami). diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index 36bc580938..20c4ca5022 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -94,7 +94,7 @@ pad_settings_dialog::pad_settings_dialog(QWidget *parent, const GameInfo *game) // Fill input type combobox std::vector str_inputs = g_cfg_input.player[0]->handler.to_list(); - for (int index = 0; index < str_inputs.size(); index++) + for (size_t index = 0; index < str_inputs.size(); index++) { ui->chooseHandler->addItem(qstr(str_inputs[index])); } @@ -355,7 +355,7 @@ void pad_settings_dialog::InitButtons() }); // Enable Button Remapping - const auto& callback = [=](u16 val, std::string name, std::string pad_name, int preview_values[6]) + const auto& callback = [=](u16 val, std::string name, std::string pad_name, std::array preview_values) { SwitchPadInfo(pad_name, true); @@ -385,7 +385,7 @@ void pad_settings_dialog::InitButtons() return; } - LOG_NOTICE(HLE, "GetNextButtonPress: %s device %s button %s pressed with value %d", m_handler->m_type, pad_name, name, val); + LOG_NOTICE(HLE, "get_next_button_press: %s device %s button %s pressed with value %d", m_handler->m_type, pad_name, name, val); if (m_button_id > button_ids::id_pad_begin && m_button_id < button_ids::id_pad_end) { m_cfg_entries[m_button_id].key = name; @@ -414,7 +414,7 @@ void pad_settings_dialog::InitButtons() m_cfg_entries[button_ids::id_pad_rstick_left].key, m_cfg_entries[button_ids::id_pad_rstick_right].key, m_cfg_entries[button_ids::id_pad_rstick_down].key, m_cfg_entries[button_ids::id_pad_rstick_up].key }; - m_handler->GetNextButtonPress(m_device_name, callback, fail_callback, false, buttons); + m_handler->get_next_button_press(m_device_name, callback, fail_callback, false, buttons); }); // Use timer to refresh pad connection status @@ -428,7 +428,7 @@ void pad_settings_dialog::InitButtons() continue; } const pad_info info = ui->chooseDevice->itemData(i).value(); - m_handler->GetNextButtonPress(info.name, [=](u16, std::string, std::string pad_name, int[6]) { SwitchPadInfo(pad_name, true); }, [=](std::string pad_name) { SwitchPadInfo(pad_name, false); }, false); + m_handler->get_next_button_press(info.name, [=](u16, std::string, std::string pad_name, std::array) { SwitchPadInfo(pad_name, true); }, [=](std::string pad_name) { SwitchPadInfo(pad_name, false); }, false); } }); } @@ -835,7 +835,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id) UpdateLabel(true); return; case button_ids::id_blacklist: - m_handler->GetNextButtonPress(m_device_name, nullptr, nullptr, true); + m_handler->get_next_button_press(m_device_name, nullptr, nullptr, true); return; default: break; @@ -987,7 +987,7 @@ void pad_settings_dialog::ChangeInputType() case pad_handler::ds4: { const QString name_string = qstr(m_handler->name_string()); - for (int i = 1; i <= m_handler->max_devices(); i++) // Controllers 1-n in GUI + for (size_t i = 1; i <= m_handler->max_devices(); i++) // Controllers 1-n in GUI { const QString device_name = name_string + QString::number(i); ui->chooseDevice->addItem(device_name, QVariant::fromValue(pad_info{ sstr(device_name), true })); @@ -997,7 +997,7 @@ void pad_settings_dialog::ChangeInputType() } default: { - for (int i = 0; i < device_list.size(); i++) + for (size_t i = 0; i < device_list.size(); i++) { ui->chooseDevice->addItem(qstr(device_list[i]), QVariant::fromValue(pad_info{ device_list[i], true })); } @@ -1020,7 +1020,7 @@ void pad_settings_dialog::ChangeInputType() continue; } const pad_info info = ui->chooseDevice->itemData(i).value(); - m_handler->GetNextButtonPress(info.name, [=](u16, std::string, std::string pad_name, int[6]) { SwitchPadInfo(pad_name, true); }, [=](std::string pad_name) { SwitchPadInfo(pad_name, false); }, false); + m_handler->get_next_button_press(info.name, [=](u16, std::string, std::string pad_name, std::array) { SwitchPadInfo(pad_name, true); }, [=](std::string pad_name) { SwitchPadInfo(pad_name, false); }, false); if (info.name == device) { ui->chooseDevice->setCurrentIndex(i); diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.h b/rpcs3/rpcs3qt/pad_settings_dialog.h index 2ba12231a8..e31faeb3f7 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/pad_settings_dialog.h @@ -79,7 +79,7 @@ class pad_settings_dialog : public QDialog struct pad_button { - cfg::string* cfg_name; + cfg::string* cfg_name = nullptr; std::string key; QString text; }; diff --git a/rpcs3/xinput_pad_handler.cpp b/rpcs3/xinput_pad_handler.cpp index 484dfb1ec5..6f66a8d7f8 100644 --- a/rpcs3/xinput_pad_handler.cpp +++ b/rpcs3/xinput_pad_handler.cpp @@ -12,41 +12,38 @@ namespace XINPUT_INFO }; } // namespace XINPUT_INFO -// ScpToolkit defined structure for pressure sensitive button query -struct SCP_EXTN -{ - float SCP_UP; - float SCP_RIGHT; - float SCP_DOWN; - float SCP_LEFT; - - float SCP_LX; - float SCP_LY; - - float SCP_L1; - float SCP_L2; - float SCP_L3; - - float SCP_RX; - float SCP_RY; - - float SCP_R1; - float SCP_R2; - float SCP_R3; - - float SCP_T; - float SCP_C; - float SCP_X; - float SCP_S; - - float SCP_SELECT; - float SCP_START; - - float SCP_PS; -}; - xinput_pad_handler::xinput_pad_handler() : PadHandlerBase(pad_handler::xinput) { + // Unique names for the config files and our pad settings dialog + button_list = + { + { XInputKeyCodes::A, "A" }, + { XInputKeyCodes::B, "B" }, + { XInputKeyCodes::X, "X" }, + { XInputKeyCodes::Y, "Y" }, + { XInputKeyCodes::Left, "Left" }, + { XInputKeyCodes::Right, "Right" }, + { XInputKeyCodes::Up, "Up" }, + { XInputKeyCodes::Down, "Down" }, + { XInputKeyCodes::LB, "LB" }, + { XInputKeyCodes::RB, "RB" }, + { XInputKeyCodes::Back, "Back" }, + { XInputKeyCodes::Start, "Start" }, + { XInputKeyCodes::LS, "LS" }, + { XInputKeyCodes::RS, "RS" }, + { XInputKeyCodes::Guide, "Guide" }, + { XInputKeyCodes::LT, "LT" }, + { XInputKeyCodes::RT, "RT" }, + { XInputKeyCodes::LSXNeg, "LS X-" }, + { XInputKeyCodes::LSXPos, "LS X+" }, + { XInputKeyCodes::LSYPos, "LS Y+" }, + { XInputKeyCodes::LSYNeg, "LS Y-" }, + { XInputKeyCodes::RSXNeg, "RS X-" }, + { XInputKeyCodes::RSXPos, "RS X+" }, + { XInputKeyCodes::RSYPos, "RS Y+" }, + { XInputKeyCodes::RSYNeg, "RS Y-" } + }; + init_configs(); // Define border values @@ -71,7 +68,15 @@ xinput_pad_handler::xinput_pad_handler() : PadHandlerBase(pad_handler::xinput) xinput_pad_handler::~xinput_pad_handler() { - Close(); + if (library) + { + FreeLibrary(library); + library = nullptr; + xinputGetExtended = nullptr; + xinputGetState = nullptr; + xinputSetState = nullptr; + xinputGetBatteryInformation = nullptr; + } } void xinput_pad_handler::init_config(pad_config* cfg, const std::string& name) @@ -117,65 +122,6 @@ void xinput_pad_handler::init_config(pad_config* cfg, const std::string& name) cfg->from_default(); } -void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std::function& callback, const std::function& fail_callback, bool get_blacklist, const std::vector& /*buttons*/) -{ - if (get_blacklist) - blacklist.clear(); - - int device_number = GetDeviceNumber(padId); - if (device_number < 0) - return fail_callback(padId); - - // Simply get the state of the controller from XInput. - const auto state = GetState(static_cast(device_number)); - if (std::get(state) != ERROR_SUCCESS) - return fail_callback(padId); - - // 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) - ASSERT(std::get>(state).has_value()); - std::pair pressed_button = {0, ""}; - const PadButtonValues& data = *std::get>(state); - for (const auto& button : button_list) - { - u32 keycode = button.first; - u16 value = data[keycode]; - - if (!get_blacklist && std::find(blacklist.begin(), blacklist.end(), keycode) != blacklist.end()) - continue; - - if (((keycode < XInputKeyCodes::LT) && (value > 0)) - || ((keycode == XInputKeyCodes::LT) && (value > m_trigger_threshold)) - || ((keycode == XInputKeyCodes::RT) && (value > m_trigger_threshold)) - || ((keycode >= XInputKeyCodes::LSXNeg && keycode <= XInputKeyCodes::LSYPos) && (value > m_thumb_threshold)) - || ((keycode >= XInputKeyCodes::RSXNeg && keycode <= XInputKeyCodes::RSYPos) && (value > m_thumb_threshold))) - { - if (get_blacklist) - { - blacklist.emplace_back(keycode); - LOG_ERROR(HLE, "XInput Calibration: Added key [ %d = %s ] to blacklist. Value = %d", keycode, button.second, value); - } - else if (value > pressed_button.first) - pressed_button = { value, button.second }; - } - } - - if (get_blacklist) - { - if (blacklist.empty()) - LOG_SUCCESS(HLE, "XInput Calibration: Blacklist is clear. No input spam detected"); - return; - } - - int preview_values[6] = { data[LT], data[RT], data[LSXPos] - data[LSXNeg], data[LSYPos] - data[LSYNeg], data[RSXPos] - data[RSXNeg], data[RSYPos] - data[RSYNeg] }; - - if (pressed_button.first > 0) - return callback(pressed_button.first, pressed_button.second, padId, preview_values); - else - return callback(0, "", padId, preview_values); -} - void xinput_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32/* r*/, s32/* g*/, s32/* b*/) { int device_number = GetDeviceNumber(padId); @@ -192,42 +138,6 @@ void xinput_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u3 (*xinputSetState)(static_cast(device_number), &vibrate); } -void xinput_pad_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold) -{ - // Update the pad button values based on their type and thresholds. - // With this you can use axis or triggers as buttons or vice versa - auto p_profile = m_dev->config; - switch (keyCode) - { - case XInputKeyCodes::LT: - pressed = val > p_profile->ltriggerthreshold; - val = pressed ? NormalizeTriggerInput(val, p_profile->ltriggerthreshold) : 0; - break; - case XInputKeyCodes::RT: - pressed = val > p_profile->rtriggerthreshold; - val = pressed ? NormalizeTriggerInput(val, p_profile->rtriggerthreshold) : 0; - break; - case XInputKeyCodes::LSXNeg: - case XInputKeyCodes::LSXPos: - case XInputKeyCodes::LSYPos: - case XInputKeyCodes::LSYNeg: - pressed = val > (ignore_threshold ? 0 : p_profile->lstickdeadzone); - val = pressed ? NormalizeStickInput(val, p_profile->lstickdeadzone, p_profile->lstickmultiplier, ignore_threshold) : 0; - break; - case XInputKeyCodes::RSXNeg: - case XInputKeyCodes::RSXPos: - case XInputKeyCodes::RSYPos: - case XInputKeyCodes::RSYNeg: - pressed = val > (ignore_threshold ? 0 : p_profile->rstickdeadzone); - val = pressed ? NormalizeStickInput(val, p_profile->rstickdeadzone, p_profile->rstickmultiplier, ignore_threshold) : 0; - break; - default: // normal button (should in theory also support sensitive buttons) - pressed = val > 0; - val = pressed ? val : 0; - break; - } -} - int xinput_pad_handler::GetDeviceNumber(const std::string& padId) { if (!Init()) @@ -244,9 +154,25 @@ int xinput_pad_handler::GetDeviceNumber(const std::string& padId) return device_number; } -std::array xinput_pad_handler::GetButtonValues_Base(const XINPUT_STATE& state) +std::unordered_map xinput_pad_handler::get_button_values(const std::shared_ptr& device) { - std::array values; + PadButtonValues values; + auto dev = std::static_pointer_cast(device); + if (!dev || dev->state != ERROR_SUCCESS) // the state has to be aquired with update_connection before calling this function + return values; + + // Try SCP first, if it fails for that pad then try normal XInput + if (dev->is_scp_device) + { + return get_button_values_scp(dev->state_scp); + } + + return get_button_values_base(dev->state_base); +} + +xinput_pad_handler::PadButtonValues xinput_pad_handler::get_button_values_base(const XINPUT_STATE& state) +{ + PadButtonValues values; // Triggers values[XInputKeyCodes::LT] = state.Gamepad.bLeftTrigger; @@ -303,9 +229,9 @@ std::array xinput_pad_han return values; } -std::array xinput_pad_handler::GetButtonValues_SCP(const SCP_EXTN& state) +xinput_pad_handler::PadButtonValues xinput_pad_handler::get_button_values_scp(const SCP_EXTN& state) { - std::array values; + PadButtonValues values; // Triggers values[xinput_pad_handler::XInputKeyCodes::LT] = static_cast(state.SCP_L2 * 255.0f); @@ -359,33 +285,9 @@ std::array xinput_pad_han return values; } -auto xinput_pad_handler::GetState(u32 device_number) -> std::tuple> +std::array xinput_pad_handler::get_preview_values(std::unordered_map data) { - std::tuple> result; - std::get(result) = ERROR_NOT_CONNECTED; - - // Try SCP first, if it fails for that pad then try normal XInput - if (xinputGetExtended) - { - SCP_EXTN stateExtn; - std::get(result) = xinputGetExtended(device_number, &stateExtn); - if (std::get(result) == ERROR_SUCCESS) - { - std::get>(result) = GetButtonValues_SCP(stateExtn); - } - } - - if (std::get(result) != ERROR_SUCCESS) - { - XINPUT_STATE stateBase; - std::get(result) = xinputGetState(device_number, &stateBase); - if (std::get(result) == ERROR_SUCCESS) - { - std::get>(result) = GetButtonValues_Base(stateBase); - } - } - - return result; + return { data[LT], data[RT], data[LSXPos] - data[LSXNeg], data[LSYPos] - data[LSYNeg], data[RSXPos] - data[RSXNeg], data[RSYPos] - data[RSYNeg] }; } bool xinput_pad_handler::Init() @@ -427,154 +329,6 @@ bool xinput_pad_handler::Init() return true; } -void xinput_pad_handler::Close() -{ - if (library) - { - FreeLibrary(library); - library = nullptr; - xinputGetExtended = nullptr; - xinputGetState = nullptr; - xinputSetState = nullptr; - xinputGetBatteryInformation = nullptr; - } -} - -void xinput_pad_handler::ThreadProc() -{ - for (int i = 0; i < static_cast(bindings.size()); ++i) - { - auto& bind = bindings[i]; - m_dev = bind.first; - auto padnum = m_dev->deviceNumber; - auto profile = m_dev->config; - auto pad = bind.second; - - const auto state = GetState(padnum); - - switch (std::get(state)) - { - case ERROR_DEVICE_NOT_CONNECTED: - { - if (last_connection_status[i] == true) - { - LOG_ERROR(HLE, "XInput device %d disconnected", padnum); - pad->m_port_status &= ~CELL_PAD_STATUS_CONNECTED; - pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; - last_connection_status[i] = false; - connected--; - } - continue; - } - case ERROR_SUCCESS: - { - if (last_connection_status[i] == false) - { - LOG_SUCCESS(HLE, "XInput device %d reconnected", padnum); - pad->m_port_status |= CELL_PAD_STATUS_CONNECTED; - pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; - last_connection_status[i] = true; - connected++; - } - - ASSERT(std::get>(state).has_value()); - const PadButtonValues& button_values = *std::get>(state); - - // Translate any corresponding keycodes to our normal DS3 buttons and triggers - for (auto& btn : pad->m_buttons) - { - btn.m_value = button_values[btn.m_keyCode]; - TranslateButtonPress(btn.m_keyCode, btn.m_pressed, btn.m_value); - } - - for (const auto& btn : pad->m_buttons) - { - if (btn.m_pressed) - { - SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); - break; - } - } - - // used to get the absolute value of an axis - s32 stick_val[4]{0}; - - // Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now) - for (int i = 0; i < static_cast(pad->m_sticks.size()); i++) - { - bool pressed; - - // m_keyCodeMin is the mapped key for left or down - u32 key_min = pad->m_sticks[i].m_keyCodeMin; - u16 val_min = button_values[key_min]; - TranslateButtonPress(key_min, pressed, val_min, true); - - // m_keyCodeMax is the mapped key for right or up - u32 key_max = pad->m_sticks[i].m_keyCodeMax; - u16 val_max = button_values[key_max]; - TranslateButtonPress(key_max, pressed, val_max, true); - - // cancel out opposing values and get the resulting difference - stick_val[i] = val_max - val_min; - } - - u16 lx, ly, rx, ry; - - // Normalize our two stick's axis based on the thresholds - std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], profile->lstickdeadzone); - std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], profile->rstickdeadzone); - - if (profile->padsquircling != 0) - { - std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling); - std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling); - } - - pad->m_sticks[0].m_value = lx; - pad->m_sticks[1].m_value = 255 - ly; - pad->m_sticks[2].m_value = rx; - pad->m_sticks[3].m_value = 255 - ry; - - // Receive Battery Info. If device is not on cable, get battery level, else assume full - XINPUT_BATTERY_INFORMATION battery_info; - (*xinputGetBatteryInformation)(padnum, BATTERY_DEVTYPE_GAMEPAD, &battery_info); - pad->m_cable_state = battery_info.BatteryType == BATTERY_TYPE_WIRED ? 1 : 0; - pad->m_battery_level = pad->m_cable_state ? BATTERY_LEVEL_FULL : battery_info.BatteryLevel; - - // The left motor is the low-frequency rumble motor. The right motor is the high-frequency rumble motor. - // The two motors are not the same, and they create different vibration effects. Values range between 0 to 65535. - size_t idx_l = profile->switch_vibration_motors ? 1 : 0; - size_t idx_s = profile->switch_vibration_motors ? 0 : 1; - - u16 speed_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : static_cast(vibration_min); - u16 speed_small = profile->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : static_cast(vibration_min); - - m_dev->newVibrateData |= m_dev->largeVibrate != speed_large || m_dev->smallVibrate != speed_small; - - m_dev->largeVibrate = speed_large; - m_dev->smallVibrate = speed_small; - - // XBox One Controller can't handle faster vibration updates than ~10ms. Elite is even worse. So I'll use 20ms to be on the safe side. No lag was noticable. - if (m_dev->newVibrateData && (std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_dev->last_vibration) > 20ms)) - { - XINPUT_VIBRATION vibrate; - vibrate.wLeftMotorSpeed = speed_large * 257; - vibrate.wRightMotorSpeed = speed_small * 257; - - if ((*xinputSetState)(padnum, &vibrate) == ERROR_SUCCESS) - { - m_dev->newVibrateData = false; - m_dev->last_vibration = std::chrono::high_resolution_clock::now(); - } - } - break; - } - default: - break; - } - } -} - std::vector xinput_pad_handler::ListDevices() { std::vector xinput_pads_list; @@ -584,74 +338,153 @@ std::vector xinput_pad_handler::ListDevices() for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) { - XINPUT_STATE state; - DWORD result = (*xinputGetState)(i, &state); + DWORD result = ERROR_NOT_CONNECTED; + + // Try SCP first, if it fails for that pad then try normal XInput + if (xinputGetExtended) + { + SCP_EXTN state; + result = xinputGetExtended(i, &state); + } + + if (result != ERROR_SUCCESS) + { + XINPUT_STATE state; + result = xinputGetState(i, &state); + } + if (result == ERROR_SUCCESS) xinput_pads_list.push_back(m_name_string + std::to_string(i + 1)); // Controllers 1-n in GUI } return xinput_pads_list; } -bool xinput_pad_handler::bindPadToDevice(std::shared_ptr pad, const std::string& device) +std::shared_ptr xinput_pad_handler::get_device(const std::string& device) { - //Convert device string to u32 representing xinput device number + // Convert device string to u32 representing xinput device number int device_number = GetDeviceNumber(device); if (device_number < 0) - return false; + return nullptr; std::shared_ptr x_device = std::make_shared(); x_device->deviceNumber = static_cast(device_number); - int index = static_cast(bindings.size()); - m_pad_configs[index].load(); - x_device->config = &m_pad_configs[index]; - pad_config* p_profile = x_device->config; - if (p_profile == nullptr) + return x_device; +} + +bool xinput_pad_handler::get_is_left_trigger(u64 keyCode) +{ + return keyCode == XInputKeyCodes::LT; +} + +bool xinput_pad_handler::get_is_right_trigger(u64 keyCode) +{ + return keyCode == XInputKeyCodes::RT; +} + +bool xinput_pad_handler::get_is_left_stick(u64 keyCode) +{ + switch (keyCode) + { + case XInputKeyCodes::LSXNeg: + case XInputKeyCodes::LSXPos: + case XInputKeyCodes::LSYPos: + case XInputKeyCodes::LSYNeg: + return true; + default: return false; + } +} - pad->Init - ( - CELL_PAD_STATUS_DISCONNECTED, - CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE, - CELL_PAD_DEV_TYPE_STANDARD, - p_profile->device_class_type - ); +bool xinput_pad_handler::get_is_right_stick(u64 keyCode) +{ + switch (keyCode) + { + case XInputKeyCodes::RSXNeg: + case XInputKeyCodes::RSXPos: + case XInputKeyCodes::RSYPos: + case XInputKeyCodes::RSYNeg: + return true; + default: + return false; + } +} - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->up), CELL_PAD_CTRL_UP); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->down), CELL_PAD_CTRL_DOWN); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->left), CELL_PAD_CTRL_LEFT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->right), CELL_PAD_CTRL_RIGHT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->start), CELL_PAD_CTRL_START); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->select), CELL_PAD_CTRL_SELECT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->l3), CELL_PAD_CTRL_L3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->r3), CELL_PAD_CTRL_R3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l1), CELL_PAD_CTRL_L1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r1), CELL_PAD_CTRL_R1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->cross), CELL_PAD_CTRL_CROSS); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->circle), CELL_PAD_CTRL_CIRCLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->square), CELL_PAD_CTRL_SQUARE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->triangle), CELL_PAD_CTRL_TRIANGLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l2), CELL_PAD_CTRL_L2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r2), CELL_PAD_CTRL_R2); - //pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved (and currently not in use by rpcs3 at all) +PadHandlerBase::connection xinput_pad_handler::update_connection(const std::shared_ptr& device) +{ + auto dev = std::static_pointer_cast(device); + if (!dev) + return connection::disconnected; - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, FindKeyCode(button_list, p_profile->ls_left), FindKeyCode(button_list, p_profile->ls_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, FindKeyCode(button_list, p_profile->ls_down), FindKeyCode(button_list, p_profile->ls_up)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, FindKeyCode(button_list, p_profile->rs_left), FindKeyCode(button_list, p_profile->rs_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, FindKeyCode(button_list, p_profile->rs_down), FindKeyCode(button_list, p_profile->rs_up)); + dev->state = ERROR_NOT_CONNECTED; + dev->state_scp = {}; + dev->state_base = {}; - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 512); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 512); + // Try SCP first, if it fails for that pad then try normal XInput + if (xinputGetExtended) + dev->state = xinputGetExtended(dev->deviceNumber, &dev->state_scp); - pad->m_vibrateMotors.emplace_back(true, 0); - pad->m_vibrateMotors.emplace_back(false, 0); + dev->is_scp_device = dev->state == ERROR_SUCCESS; - bindings.emplace_back(x_device, pad); + if (!dev->is_scp_device) + dev->state = xinputGetState(dev->deviceNumber, &dev->state_base); - return true; + if (dev->state == ERROR_SUCCESS) + return connection::connected; + + return connection::disconnected; +} + +void xinput_pad_handler::get_extended_info(const std::shared_ptr& device, const std::shared_ptr& pad) +{ + auto dev = std::static_pointer_cast(device); + if (!dev || !pad) + return; + + auto padnum = dev->deviceNumber; + + // Receive Battery Info. If device is not on cable, get battery level, else assume full + XINPUT_BATTERY_INFORMATION battery_info; + (*xinputGetBatteryInformation)(padnum, BATTERY_DEVTYPE_GAMEPAD, &battery_info); + pad->m_cable_state = battery_info.BatteryType == BATTERY_TYPE_WIRED ? 1 : 0; + pad->m_battery_level = pad->m_cable_state ? BATTERY_LEVEL_FULL : battery_info.BatteryLevel; +} + +void xinput_pad_handler::apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) +{ + auto dev = std::static_pointer_cast(device); + if (!dev || !pad) + return; + + auto padnum = dev->deviceNumber; + auto profile = dev->config; + + // The left motor is the low-frequency rumble motor. The right motor is the high-frequency rumble motor. + // The two motors are not the same, and they create different vibration effects. Values range between 0 to 65535. + size_t idx_l = profile->switch_vibration_motors ? 1 : 0; + size_t idx_s = profile->switch_vibration_motors ? 0 : 1; + + u16 speed_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : static_cast(vibration_min); + u16 speed_small = profile->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : static_cast(vibration_min); + + dev->newVibrateData |= dev->largeVibrate != speed_large || dev->smallVibrate != speed_small; + + dev->largeVibrate = speed_large; + dev->smallVibrate = speed_small; + + // XBox One Controller can't handle faster vibration updates than ~10ms. Elite is even worse. So I'll use 20ms to be on the safe side. No lag was noticable. + if (dev->newVibrateData && (std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - dev->last_vibration) > 20ms)) + { + XINPUT_VIBRATION vibrate; + vibrate.wLeftMotorSpeed = speed_large * 257; + vibrate.wRightMotorSpeed = speed_small * 257; + + if ((*xinputSetState)(padnum, &vibrate) == ERROR_SUCCESS) + { + dev->newVibrateData = false; + dev->last_vibration = std::chrono::high_resolution_clock::now(); + } + } } #endif diff --git a/rpcs3/xinput_pad_handler.h b/rpcs3/xinput_pad_handler.h index 3c3d334698..55ecee32e1 100644 --- a/rpcs3/xinput_pad_handler.h +++ b/rpcs3/xinput_pad_handler.h @@ -8,7 +8,38 @@ #include #include -struct SCP_EXTN; +// ScpToolkit defined structure for pressure sensitive button query +struct SCP_EXTN +{ + float SCP_UP; + float SCP_RIGHT; + float SCP_DOWN; + float SCP_LEFT; + + float SCP_LX; + float SCP_LY; + + float SCP_L1; + float SCP_L2; + float SCP_L3; + + float SCP_RX; + float SCP_RY; + + float SCP_R1; + float SCP_R2; + float SCP_R3; + + float SCP_T; + float SCP_C; + float SCP_X; + float SCP_S; + + float SCP_SELECT; + float SCP_START; + + float SCP_PS; +}; class xinput_pad_handler final : public PadHandlerBase { @@ -46,44 +77,19 @@ class xinput_pad_handler final : public PadHandlerBase KeyCodeCount }; - // Unique names for the config files and our pad settings dialog - const std::unordered_map button_list = - { - { XInputKeyCodes::A, "A" }, - { XInputKeyCodes::B, "B" }, - { XInputKeyCodes::X, "X" }, - { XInputKeyCodes::Y, "Y" }, - { XInputKeyCodes::Left, "Left" }, - { XInputKeyCodes::Right, "Right" }, - { XInputKeyCodes::Up, "Up" }, - { XInputKeyCodes::Down, "Down" }, - { XInputKeyCodes::LB, "LB" }, - { XInputKeyCodes::RB, "RB" }, - { XInputKeyCodes::Back, "Back" }, - { XInputKeyCodes::Start, "Start" }, - { XInputKeyCodes::LS, "LS" }, - { XInputKeyCodes::RS, "RS" }, - { XInputKeyCodes::Guide, "Guide" }, - { XInputKeyCodes::LT, "LT" }, - { XInputKeyCodes::RT, "RT" }, - { XInputKeyCodes::LSXNeg, "LS X-" }, - { XInputKeyCodes::LSXPos, "LS X+" }, - { XInputKeyCodes::LSYPos, "LS Y+" }, - { XInputKeyCodes::LSYNeg, "LS Y-" }, - { XInputKeyCodes::RSXNeg, "RS X-" }, - { XInputKeyCodes::RSXPos, "RS X+" }, - { XInputKeyCodes::RSYPos, "RS Y+" }, - { XInputKeyCodes::RSYNeg, "RS Y-" } - }; + using PadButtonValues = std::unordered_map; - struct XInputDevice + struct XInputDevice : public PadDevice { u32 deviceNumber{ 0 }; bool newVibrateData{ true }; u16 largeVibrate{ 0 }; u16 smallVibrate{ 0 }; std::chrono::high_resolution_clock::time_point last_vibration; - pad_config* config{ nullptr }; + bool is_scp_device{ false }; + DWORD state{ ERROR_NOT_CONNECTED }; // holds internal controller state change + SCP_EXTN state_scp{ 0 }; + XINPUT_STATE state_base{ 0 }; }; public: @@ -91,12 +97,8 @@ public: ~xinput_pad_handler(); bool Init() override; - void Close(); std::vector ListDevices() override; - bool bindPadToDevice(std::shared_ptr pad, const std::string& device) override; - void ThreadProc() override; - void GetNextButtonPress(const std::string& padId, const std::function& callback, const std::function& fail_callback, bool get_blacklist = false, const std::vector& buttons = {}) override; void SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b) override; void init_config(pad_config* cfg, const std::string& name) override; @@ -106,14 +108,10 @@ private: typedef DWORD (WINAPI * PFN_XINPUTSETSTATE)(DWORD, XINPUT_VIBRATION *); typedef DWORD (WINAPI * PFN_XINPUTGETBATTERYINFORMATION)(DWORD, BYTE, XINPUT_BATTERY_INFORMATION *); - using PadButtonValues = std::array; - private: int GetDeviceNumber(const std::string& padId); - std::tuple> GetState(u32 device_number); - PadButtonValues GetButtonValues_Base(const XINPUT_STATE& state); - PadButtonValues GetButtonValues_SCP(const SCP_EXTN& state); - void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) override; + PadButtonValues get_button_values_base(const XINPUT_STATE& state); + PadButtonValues get_button_values_scp(const SCP_EXTN& state); bool is_init{ false }; HMODULE library{ nullptr }; @@ -122,7 +120,14 @@ private: PFN_XINPUTSETSTATE xinputSetState{ nullptr }; PFN_XINPUTGETBATTERYINFORMATION xinputGetBatteryInformation{ nullptr }; - std::vector blacklist; - std::vector, std::shared_ptr>> bindings; - std::shared_ptr m_dev; + std::shared_ptr get_device(const std::string& device) override; + bool get_is_left_trigger(u64 keyCode) override; + bool get_is_right_trigger(u64 keyCode) override; + bool get_is_left_stick(u64 keyCode) override; + bool get_is_right_stick(u64 keyCode) override; + PadHandlerBase::connection update_connection(const std::shared_ptr& device) override; + void get_extended_info(const std::shared_ptr& device, const std::shared_ptr& pad) override; + void apply_pad_data(const std::shared_ptr& device, const std::shared_ptr& pad) override; + std::unordered_map get_button_values(const std::shared_ptr& device) override; + std::array get_preview_values(std::unordered_map data) override; };