diff --git a/rpcs3/Input/ds3_pad_handler.cpp b/rpcs3/Input/ds3_pad_handler.cpp index 8013b6f14b..d36af783ff 100644 --- a/rpcs3/Input/ds3_pad_handler.cpp +++ b/rpcs3/Input/ds3_pad_handler.cpp @@ -4,7 +4,11 @@ LOG_CHANNEL(ds3_log, "DS3"); -ds3_pad_handler::ds3_pad_handler() : PadHandlerBase(pad_handler::ds3) +constexpr u16 DS3_VID = 0x054C; +constexpr u16 DS3_PID = 0x0268; + +ds3_pad_handler::ds3_pad_handler() + : hid_pad_handler(pad_handler::ds3, DS3_VID, {DS3_PID}) { button_list = { @@ -51,125 +55,22 @@ ds3_pad_handler::ds3_pad_handler() : PadHandlerBase(pad_handler::ds3) ds3_pad_handler::~ds3_pad_handler() { - for (auto& controller : controllers) + for (auto& controller : m_controllers) { - if (controller->handle) + if (controller.second && controller.second->hidDevice) { // Disable blinking and vibration - controller->large_motor = 0; - controller->small_motor = 0; - send_output_report(controller); - hid_close(controller->handle); + controller.second->large_motor = 0; + controller.second->small_motor = 0; + send_output_report(controller.second.get()); } } - hid_exit(); -} - -bool ds3_pad_handler::init_usb() -{ - if (hid_init() != 0) - { - ds3_log.fatal("Failed to init hidapi for the DS3 pad handler"); - return false; - } - return true; -} - -bool ds3_pad_handler::Init() -{ - if (is_init) - return true; - - if (!init_usb()) - return false; - - bool warn_about_drivers = false; - - // Uses libusb for windows as hidapi will never work with UsbHid driver for the ds3 and it won't work with WinUsb either(windows hid api needs the UsbHid in the driver stack as far as I can tell) - // For other os use hidapi and hope for the best! - hid_device_info* hid_info = hid_enumerate(DS3_VID, DS3_PID); - hid_device_info* head = hid_info; - while (hid_info) - { - hid_device *handle = hid_open_path(hid_info->path); - -#ifdef _WIN32 - u8 buf[0xFF]; - buf[0] = 0xF2; - bool got_report = false; - if (handle) - { - got_report = hid_get_feature_report(handle, buf, 0xFF) >= 0; - if (!got_report) - { - buf[0] = 0; - got_report = hid_get_feature_report(handle, buf, 0xFF) >= 0; - } - } - if (got_report) -#else - if(handle) -#endif - { - std::shared_ptr ds3dev = std::make_shared(); - ds3dev->device = hid_info->path; - ds3dev->handle = handle; -#ifdef _WIN32 - ds3dev->report_id = buf[0]; -#endif - controllers.emplace_back(ds3dev); - } - else - { - if (handle) - hid_close(handle); - - warn_about_drivers = true; - } - hid_info = hid_info->next; - } - - hid_free_enumeration(head); - - if (warn_about_drivers) - { - ds3_log.error("One or more DS3 pads were detected but couldn't be interacted with directly"); -#if defined(_WIN32) || defined(__linux__) - ds3_log.error("Check https://wiki.rpcs3.net/index.php?title=Help:Controller_Configuration for intructions on how to solve this issue"); -#endif - } - else if (controllers.empty()) - { - ds3_log.warning("No controllers found!"); - } - else - { - ds3_log.success("Controllers found: %d", controllers.size()); - } - - is_init = true; - return true; -} - -std::vector ds3_pad_handler::ListDevices() -{ - std::vector ds3_pads_list; - - if (!Init()) - return ds3_pads_list; - - for (usz i = 1; i <= controllers.size(); ++i) // Controllers 1-n in GUI - { - ds3_pads_list.emplace_back(m_name_string + std::to_string(i)); - } - - return ds3_pads_list; } void ds3_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32/* r*/, s32/* g*/, s32 /* b*/, bool /*battery_led*/, u32 /*battery_led_brightness*/) { - std::shared_ptr device = get_ds3_device(padId); - if (device == nullptr || device->handle == nullptr) + std::shared_ptr device = get_hid_device(padId); + if (device == nullptr || device->hidDevice == nullptr) return; // Set the device's motor speeds to our requested values 0-255 @@ -192,13 +93,13 @@ void ds3_pad_handler::SetPadData(const std::string& padId, u32 largeMotor, u32 s } // Start/Stop the engines :) - send_output_report(device); + send_output_report(device.get()); } -void ds3_pad_handler::send_output_report(const std::shared_ptr& ds3dev) +int ds3_pad_handler::send_output_report(ds3_device* ds3dev) { - if (!ds3dev) - return; + if (!ds3dev || !ds3dev->hidDevice) + return -2; #ifdef _WIN32 u8 report_buf[] = { @@ -223,23 +124,7 @@ void ds3_pad_handler::send_output_report(const std::shared_ptr& ds3d report_buf[5] = ds3dev->small_motor; #endif - hid_write(ds3dev->handle, report_buf, sizeof(report_buf)); -} - -std::shared_ptr ds3_pad_handler::get_ds3_device(const std::string& padId) -{ - if (!Init()) - return nullptr; - - const usz pos = padId.find(m_name_string); - if (pos == umax) - return nullptr; - - const int pad_number = std::stoi(padId.substr(pos + 9)); - if (pad_number > 0 && pad_number + 0u <= controllers.size()) - return controllers[static_cast(pad_number) - 1]; - - return nullptr; + return hid_write(ds3dev->hidDevice, report_buf, sizeof(report_buf)); } void ds3_pad_handler::init_config(pad_config* cfg, const std::string& name) @@ -293,18 +178,83 @@ void ds3_pad_handler::init_config(pad_config* cfg, const std::string& name) cfg->from_default(); } -ds3_pad_handler::DS3Status ds3_pad_handler::get_data(const std::shared_ptr& ds3dev) +void ds3_pad_handler::check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view wide_serial) +{ + if (!hidDevice) + { + return; + } + + ds3_device* device = nullptr; + + for (auto& controller : m_controllers) + { + ensure(controller.second); + + if (!controller.second->hidDevice) + { + device = controller.second.get(); + break; + } + } + + if (!device) + { + return; + } + + std::string serial; + + // Uses libusb for windows as hidapi will never work with UsbHid driver for the ds3 and it won't work with WinUsb either(windows hid api needs the UsbHid in the driver stack as far as I can tell) + // For other os use hidapi and hope for the best! +#ifdef _WIN32 + u8 buf[0xFF]; + buf[0] = 0xF2; + + bool got_report = hid_get_feature_report(hidDevice, buf, 0xFF) >= 0; + if (!got_report) + { + buf[0] = 0; + got_report = hid_get_feature_report(hidDevice, buf, 0xFF) >= 0; + } + if (!got_report) + { + hid_close(hidDevice); + return; + } +#endif + + { + for (wchar_t ch : wide_serial) + serial += static_cast(ch); + } + + if (hid_set_nonblocking(hidDevice, 1) == -1) + { + ds3_log.error("check_add_device: hid_set_nonblocking failed! Reason: %s", hid_error(hidDevice)); + hid_close(hidDevice); + return; + } + + device->report_id = buf[0]; + device->path = path; + device->hidDevice = hidDevice; + + send_output_report(device); +} + +ds3_pad_handler::DataStatus ds3_pad_handler::get_data(ds3_device* ds3dev) { if (!ds3dev) - return DS3Status::Disconnected; + return DataStatus::ReadError; auto& dbuf = ds3dev->buf; #ifdef _WIN32 dbuf[0] = ds3dev->report_id; - const int result = hid_get_feature_report(ds3dev->handle, dbuf, sizeof(dbuf)); + const int result = hid_get_feature_report(ds3dev->hidDevice, dbuf, sizeof(dbuf)); #else - const int result = hid_read(ds3dev->handle, dbuf, sizeof(dbuf)); + const int result = hid_read(ds3dev->hidDevice, dbuf, sizeof(dbuf)); #endif if (result > 0) @@ -315,27 +265,27 @@ ds3_pad_handler::DS3Status ds3_pad_handler::get_data(const std::shared_ptr ds3_pad_handler::get_button_values(const std::shared_ptr& device) { std::unordered_map key_buf; - auto dev = std::static_pointer_cast(device); + ds3_device* dev = static_cast(device.get()); if (!dev) return key_buf; @@ -400,7 +350,7 @@ pad_preview_values ds3_pad_handler::get_preview_values(const std::unordered_map< void ds3_pad_handler::get_extended_info(const std::shared_ptr& device, const std::shared_ptr& pad) { - auto ds3dev = std::static_pointer_cast(device); + ds3_device* ds3dev = static_cast(device.get()); if (!ds3dev || !pad) return; @@ -438,15 +388,6 @@ void ds3_pad_handler::get_extended_info(const std::shared_ptr& device //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; @@ -487,56 +428,43 @@ bool ds3_pad_handler::get_is_right_stick(u64 keyCode) PadHandlerBase::connection ds3_pad_handler::update_connection(const std::shared_ptr& device) { - auto dev = std::static_pointer_cast(device); - if (!dev) + ds3_device* dev = static_cast(device.get()); + if (!dev || dev->path.empty()) return connection::disconnected; - if (dev->handle == nullptr) + if (dev->hidDevice == nullptr) { - hid_device* devhandle = hid_open_path(dev->device.c_str()); - if (!devhandle) + hid_device* devhandle = hid_open_path(dev->path.c_str()); + if (devhandle) + { + if (hid_set_nonblocking(devhandle, 1) == -1) + { + ds3_log.error("Reconnecting Device %s: hid_set_nonblocking failed with error %s", dev->path, hid_error(devhandle)); + } + dev->hidDevice = devhandle; + } + else { return connection::disconnected; } - - dev->handle = devhandle; } - switch (get_data(dev)) + if (get_data(dev) == DataStatus::ReadError) { - 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; - } + // this also can mean disconnected, either way deal with it on next loop and reconnect + hid_close(dev->hidDevice); + dev->hidDevice = nullptr; + return connection::no_data; } - case DS3Status::NewData: - { - return connection::connected; - } - default: - break; - } - return connection::disconnected; + return connection::connected; } 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) + ds3_device* dev = static_cast(device.get()); + if (!dev || !dev->hidDevice || !pad) return; if (dev->large_motor != pad->m_vibrateMotors[0].m_value || dev->small_motor != pad->m_vibrateMotors[1].m_value) diff --git a/rpcs3/Input/ds3_pad_handler.h b/rpcs3/Input/ds3_pad_handler.h index a727fe661c..2430516e54 100644 --- a/rpcs3/Input/ds3_pad_handler.h +++ b/rpcs3/Input/ds3_pad_handler.h @@ -1,12 +1,19 @@ #pragma once -#include "Emu/Io/PadHandler.h" - -#include "hidapi.h" +#include "hid_pad_handler.h" #include -class ds3_pad_handler final : public PadHandlerBase +class ds3_device : public HidDevice +{ +public: + u8 buf[64]{0}; +#ifdef _WIN32 + u8 report_id = 0; +#endif +}; + +class ds3_pad_handler final : public hid_pad_handler { enum DS3KeyCodes { @@ -64,60 +71,24 @@ class ds3_pad_handler final : public PadHandlerBase DS3_ENDPOINT_IN = 0x81 }; - enum DS3Status : u8 - { - Disconnected, - Connected, - NewData - }; - - struct ds3_device : public PadDevice - { - std::string device = {}; - hid_device *handle = nullptr; - u8 buf[64]{ 0 }; - u8 large_motor = 0; - u8 small_motor = 0; - u8 status = DS3Status::Disconnected; -#ifdef _WIN32 - u8 report_id = 0; -#endif - }; - - const u16 DS3_VID = 0x054C; - const u16 DS3_PID = 0x0268; - #ifdef _WIN32 const u8 DS3_HID_OFFSET = 0x01; #else const u8 DS3_HID_OFFSET = 0x00; #endif - // pseudo 'controller id' to keep track of unique controllers - std::vector> controllers; - public: ds3_pad_handler(); ~ds3_pad_handler(); - bool Init() override; - - std::vector ListDevices() override; void SetPadData(const std::string& padId, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override; void init_config(pad_config* cfg, const std::string& name) override; private: - std::shared_ptr get_ds3_device(const std::string& padId); - ds3_pad_handler::DS3Status get_data(const std::shared_ptr& ds3dev); - void send_output_report(const std::shared_ptr& ds3dev); + ds3_pad_handler::DataStatus get_data(ds3_device* ds3dev); + int send_output_report(ds3_device* ds3dev); + void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view serial); -private: - bool init_usb(); - -private: - bool is_init = false; - - 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; diff --git a/rpcs3/Input/hid_pad_handler.cpp b/rpcs3/Input/hid_pad_handler.cpp index 5d6153883e..3b32d4677f 100644 --- a/rpcs3/Input/hid_pad_handler.cpp +++ b/rpcs3/Input/hid_pad_handler.cpp @@ -1,4 +1,5 @@ #include "hid_pad_handler.h" +#include "ds3_pad_handler.h" #include "ds4_pad_handler.h" #include "dualsense_pad_handler.h" #include "util/logs.hpp" @@ -198,5 +199,6 @@ std::shared_ptr hid_pad_handler::get_device(const std::string return get_hid_device(device); } +template class hid_pad_handler; template class hid_pad_handler; template class hid_pad_handler;