diff --git a/sysmodule/include/gamepad/controllers.hpp b/sysmodule/include/gamepad/controllers.hpp index f0a7a9b..3fa68e8 100644 --- a/sysmodule/include/gamepad/controllers.hpp +++ b/sysmodule/include/gamepad/controllers.hpp @@ -1,7 +1,8 @@ #pragma once -#include "gamepad/controllers/dualshock4.hpp" +#include "gamepad/controllers/joycon.hpp" #include "gamepad/controllers/switchpro.hpp" #include "gamepad/controllers/wiimote.hpp" #include "gamepad/controllers/wiiupro.hpp" +#include "gamepad/controllers/dualshock4.hpp" #include "gamepad/controllers/xboxone.hpp" diff --git a/sysmodule/include/gamepad/controllers/joycon.hpp b/sysmodule/include/gamepad/controllers/joycon.hpp new file mode 100644 index 0000000..036a704 --- /dev/null +++ b/sysmodule/include/gamepad/controllers/joycon.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include +#include "gamepad/hidgamepad.hpp" + +namespace mc::controller { + + union JoyconStickData { + struct __attribute__ ((__packed__)) { + uint16_t x : 12; + uint16_t : 0; + uint8_t : 8; + }; + + struct __attribute__ ((__packed__)) { + uint8_t : 8; + uint16_t : 4; + uint16_t y : 12; + }; + }; + + struct JoyconButtonData { + uint8_t Y : 1; + uint8_t X : 1; + uint8_t B : 1; + uint8_t A : 1; + uint8_t : 2; // SR, SL (Right Joy) + uint8_t R : 1; + uint8_t ZR : 1; + + uint8_t minus : 1; + uint8_t plus : 1; + uint8_t rstick_press : 1; + uint8_t lstick_press : 1; + uint8_t home : 1; + uint8_t capture : 1; + uint8_t : 0; + + uint8_t dpad_down : 1; + uint8_t dpad_up : 1; + uint8_t dpad_right : 1; + uint8_t dpad_left : 1; + uint8_t : 2; // SR, SL (Left Joy) + uint8_t L : 1; + uint8_t ZL : 1; + }; + + union JoyconReportData { + struct { + uint8_t conn_info : 4; + uint8_t battery : 4; + uint8_t timer; + JoyconButtonData buttons; + JoyconStickData left_stick; + JoyconStickData right_stick; + } report0x30; + }; + + class JoyconController : public HidGamepad { + + public: + static constexpr const HardwareID hardwareIds[] = { + {0x057e, 2006}, // Official Joycon(L) Controller + {0x057e, 2007}, // Official Joycon(R) Controller + }; + + JoyconController(HidInterfaceType iface) : HidGamepad(iface) {}; + + Result receiveReport(const HidReport *report); + + private: + void mapStickValues(JoystickPosition *dst, const JoyconStickData *src); + void handleInputReport0x30(const JoyconReportData *data); + + }; + +} diff --git a/sysmodule/include/gamepad/hidgamepad.hpp b/sysmodule/include/gamepad/hidgamepad.hpp index 762c2df..ba5d959 100644 --- a/sysmodule/include/gamepad/hidgamepad.hpp +++ b/sysmodule/include/gamepad/hidgamepad.hpp @@ -11,7 +11,7 @@ namespace mc::controller { enum ControllerType { - //ControllerType_Joycon, + ControllerType_Joycon, ControllerType_SwitchPro, ControllerType_WiiUPro, ControllerType_Wiimote, diff --git a/sysmodule/source/gamepad/controllermanager.cpp b/sysmodule/source/gamepad/controllermanager.cpp index 1ffbe14..503da83 100644 --- a/sysmodule/source/gamepad/controllermanager.cpp +++ b/sysmodule/source/gamepad/controllermanager.cpp @@ -28,6 +28,12 @@ namespace mc::controller { } ControllerType ControllerManager::identify(uint16_t vid, uint16_t pid) { + for (HardwareID hwId : JoyconController::hardwareIds) { + if ( (vid == hwId.vid) && (pid == hwId.pid) ) { + return ControllerType_Joycon; + } + } + for (HardwareID hwId : SwitchProController::hardwareIds) { if ( (vid == hwId.vid) && (pid == hwId.pid) ) { return ControllerType_SwitchPro; diff --git a/sysmodule/source/gamepad/controllers/joycon.cpp b/sysmodule/source/gamepad/controllers/joycon.cpp new file mode 100644 index 0000000..0ff3730 --- /dev/null +++ b/sysmodule/source/gamepad/controllers/joycon.cpp @@ -0,0 +1,78 @@ +#include +#include +#include "gamepad/controllers/joycon.hpp" + +namespace mc::controller { + + namespace { + + const constexpr uint8_t joycon_joystick_nbits = 12; + + } + + void JoyconController::mapStickValues(JoystickPosition *dst, const JoyconStickData *src) { + dst->dx = unsigned_to_signed(src->x, joycon_joystick_nbits); + dst->dy = -unsigned_to_signed(src->y, joycon_joystick_nbits); + + float angle = atan2(dst->dy, dst->dx); + float magnitude = hypot(dst->dx, dst->dy); + + if (magnitude < m_innerDeadzone) { + dst->dx = 0; + dst->dy = 0; + } + else if (magnitude > m_outerDeadzone) { + dst->dx = JOYSTICK_MAX * cos(angle); + dst->dy = JOYSTICK_MAX * sin(angle); + } + } + + Result JoyconController::receiveReport(const HidReport *report) { + + const JoyconReportData *reportData = reinterpret_cast(&report->data); + + switch(report->id) { + case 0x30: + handleInputReport0x30(reportData); + break; + + default: + return -1; + } + + return 0; + } + + void JoyconController::handleInputReport0x30(const JoyconReportData *data) { + std::memset(&m_state, 0, sizeof(m_state)); + + this->mapStickValues(&m_state.left_stick, &data->report0x30.left_stick); + this->mapStickValues(&m_state.right_stick, &data->report0x30.right_stick); + + m_state.dpad_left = data->report0x30.buttons.dpad_left; + m_state.dpad_up = data->report0x30.buttons.dpad_up; + m_state.dpad_right = data->report0x30.buttons.dpad_right; + m_state.dpad_down = data->report0x30.buttons.dpad_down; + + m_state.A = data->report0x30.buttons.A; + m_state.B = data->report0x30.buttons.B; + m_state.X = data->report0x30.buttons.X; + m_state.Y = data->report0x30.buttons.Y; + + m_state.L = data->report0x30.buttons.L; + m_state.ZL = data->report0x30.buttons.ZL; + m_state.lstick_press = data->report0x30.buttons.lstick_press; + + m_state.R = data->report0x30.buttons.R; + m_state.ZR = data->report0x30.buttons.ZR; + m_state.rstick_press = data->report0x30.buttons.rstick_press; + + m_state.minus = data->report0x30.buttons.minus; + m_state.plus = data->report0x30.buttons.plus; + m_state.capture = data->report0x30.buttons.capture; + m_state.home = data->report0x30.buttons.home; + + m_virtual->setState(&m_state); + } + +}