#pragma once #include "Emu/Io/PadHandler.h" #include "Utilities/Thread.h" #include "Utilities/CRC.h" #include "hidapi.h" #include const u32 MAX_GAMEPADS = 7; class ds4_thread final : public named_thread { private: enum DS4CalibIndex { // gyro PITCH = 0, YAW, ROLL, // accel X, Y, Z, COUNT }; struct DS4CalibData { s16 bias; s32 sensNumer; s32 sensDenom; }; struct DS4Device { hid_device* hidDevice{ nullptr }; std::string path{ "" }; bool btCon{ false }; std::array calibData; bool newVibrateData{true}; u8 largeVibrate{0}; u8 smallVibrate{0}; }; const u16 DS4_VID = 0x054C; // pid's of connected ds4 const std::array ds4Pids = {{0xBA0, 0x5C4, 0x09CC }}; // pseudo 'controller id' to keep track of unique controllers std::unordered_map controllers; std::array, MAX_GAMEPADS> padData{}; void on_task() override; std::string get_name() const override { return "DS4 Thread"; } semaphore<> mutex; CRCPP::CRC::Table crcTable{ CRCPP::CRC::CRC_32() }; public: void on_init(const std::shared_ptr&) override; std::array GetConnectedControllers(); std::array, MAX_GAMEPADS> GetControllerData(); void SetRumbleData(u32 port, u8 largeVibrate, u8 smallVibrate); ds4_thread() = default; ~ds4_thread(); private: bool GetCalibrationData(DS4Device* ds4Device); void CheckAddDevice(hid_device* hidDevice, hid_device_info* hidDevInfo); void SendVibrateData(const DS4Device& device); inline s16 ApplyCalibration(s32 rawValue, const DS4CalibData& calibData) { const s32 biased = rawValue - calibData.bias; const s32 quot = calibData.sensNumer / calibData.sensDenom; const s32 rem = calibData.sensNumer % calibData.sensDenom; const s32 output = (quot * biased) + ((rem * biased) / calibData.sensDenom); if (output > std::numeric_limits::max()) return std::numeric_limits::max(); else if (output < std::numeric_limits::min()) return std::numeric_limits::min(); else return static_cast(output); } }; class ds4_pad_handler final : public PadHandlerBase { public: ds4_pad_handler() {} ~ds4_pad_handler(); void Init(const u32 max_connect) override; void Close(); PadInfo& GetInfo() override; std::vector& GetPads() override; void SetRumble(const u32 pad, u8 largeMotor, bool smallMotor) override; private: void ProcessData(); // holds internal controller state change std::array last_connection_status = {}; std::shared_ptr ds4Thread; };