diff --git a/bluetooth-mitm/source/controllers/controller_management.cpp b/bluetooth-mitm/source/controllers/controller_management.cpp index 35e9aea0..5b30bb8f 100644 --- a/bluetooth-mitm/source/controllers/controller_management.cpp +++ b/bluetooth-mitm/source/controllers/controller_management.cpp @@ -96,7 +96,13 @@ namespace ams::controller { return ControllerType_Gamesir; } } - + + for (auto hwId : SteelseriesController::hardware_ids) { + if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) { + return ControllerType_Steelseries; + } + } + return ControllerType_Unknown; } @@ -152,6 +158,9 @@ namespace ams::controller { break; case ControllerType_Gamesir: g_controllers.push_back(std::make_unique(address)); + break; + case ControllerType_Steelseries: + g_controllers.push_back(std::make_unique(address)); break; default: g_controllers.push_back(std::make_unique(address)); diff --git a/bluetooth-mitm/source/controllers/controller_management.hpp b/bluetooth-mitm/source/controllers/controller_management.hpp index e177bd6c..88ceafbd 100644 --- a/bluetooth-mitm/source/controllers/controller_management.hpp +++ b/bluetooth-mitm/source/controllers/controller_management.hpp @@ -27,6 +27,7 @@ #include "ipega_controller.hpp" #include "xiaomi_controller.hpp" #include "gamesir_controller.hpp" +#include "steelseries_controller.hpp" namespace ams::controller { @@ -44,6 +45,7 @@ namespace ams::controller { ControllerType_Ipega, ControllerType_Xiaomi, ControllerType_Gamesir, + ControllerType_Steelseries, ControllerType_Unknown, }; diff --git a/bluetooth-mitm/source/controllers/steelseries_controller.cpp b/bluetooth-mitm/source/controllers/steelseries_controller.cpp new file mode 100644 index 00000000..0a8abe31 --- /dev/null +++ b/bluetooth-mitm/source/controllers/steelseries_controller.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2020 ndeadly + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "steelseries_controller.hpp" +#include + +namespace ams::controller { + + namespace { + + const constexpr float stick_scale_factor = float(UINT12_MAX) / UINT8_MAX; + + } + + void SteelseriesController::ConvertReportFormat(const bluetooth::HidReport *in_report, bluetooth::HidReport *out_report) { + auto steelseries_report = reinterpret_cast(&in_report->data); + auto switch_report = reinterpret_cast(&out_report->data); + + switch(steelseries_report->id) { + case 0x01: + this->HandleInputReport0x01(steelseries_report, switch_report); + break; + default: + break; + } + + out_report->size = sizeof(SwitchInputReport0x30) + 1; + switch_report->id = 0x30; + switch_report->input0x30.conn_info = 0x0; + switch_report->input0x30.battery = m_battery | m_charging; + std::memset(switch_report->input0x30.motion, 0, sizeof(switch_report->input0x30.motion)); + switch_report->input0x30.timer = os::ConvertToTimeSpan(os::GetSystemTick()).GetMilliSeconds() & 0xff; + } + + void SteelseriesController::HandleInputReport0x01(const SteelseriesReportData *src, SwitchReportData *dst) { + this->PackStickData(&dst->input0x30.left_stick, + static_cast(stick_scale_factor * -static_cast(~src->input0x01.left_stick.x + 1) + 0x7ff) & 0xfff, + static_cast(stick_scale_factor * (UINT8_MAX + static_cast(~src->input0x01.left_stick.y + 1)) + 0x7ff) & 0xfff + ); + this->PackStickData(&dst->input0x30.right_stick, + static_cast(stick_scale_factor * -static_cast(~src->input0x01.right_stick.x + 1) + 0x7ff) & 0xfff, + static_cast(stick_scale_factor * (UINT8_MAX + static_cast(~src->input0x01.right_stick.y + 1)) + 0x7ff) & 0xfff + ); + + dst->input0x30.buttons.dpad_down = (src->input0x01.dpad == SteelseriesDPad_S) || + (src->input0x01.dpad == SteelseriesDPad_SE) || + (src->input0x01.dpad == SteelseriesDPad_SW); + dst->input0x30.buttons.dpad_up = (src->input0x01.dpad == SteelseriesDPad_N) || + (src->input0x01.dpad == SteelseriesDPad_NE) || + (src->input0x01.dpad == SteelseriesDPad_NW); + dst->input0x30.buttons.dpad_right = (src->input0x01.dpad == SteelseriesDPad_E) || + (src->input0x01.dpad == SteelseriesDPad_NE) || + (src->input0x01.dpad == SteelseriesDPad_SE); + dst->input0x30.buttons.dpad_left = (src->input0x01.dpad == SteelseriesDPad_W) || + (src->input0x01.dpad == SteelseriesDPad_NW) || + (src->input0x01.dpad == SteelseriesDPad_SW); + + dst->input0x30.buttons.A = src->input0x01.buttons.B; + dst->input0x30.buttons.B = src->input0x01.buttons.A; + dst->input0x30.buttons.X = src->input0x01.buttons.Y; + dst->input0x30.buttons.Y = src->input0x01.buttons.X; + + dst->input0x30.buttons.R = src->input0x01.buttons.R; + dst->input0x30.buttons.L = src->input0x01.buttons.L; + + dst->input0x30.buttons.minus = src->input0x01.buttons.select; + dst->input0x30.buttons.plus = src->input0x01.buttons.start; + + dst->input0x30.buttons.capture = 0; + + // Home button combo + dst->input0x30.buttons.home = dst->input0x30.buttons.dpad_down & dst->input0x30.buttons.minus; + if (dst->input0x30.buttons.home){ + dst->input0x30.buttons.dpad_down = 0; + dst->input0x30.buttons.minus = 0; + } + + } + +} diff --git a/bluetooth-mitm/source/controllers/steelseries_controller.hpp b/bluetooth-mitm/source/controllers/steelseries_controller.hpp new file mode 100644 index 00000000..77b7c16f --- /dev/null +++ b/bluetooth-mitm/source/controllers/steelseries_controller.hpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 ndeadly + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "emulated_switch_controller.hpp" + +namespace ams::controller { + + enum SteelseriesDPadDirection { + SteelseriesDPad_N, + SteelseriesDPad_NE, + SteelseriesDPad_E, + SteelseriesDPad_SE, + SteelseriesDPad_S, + SteelseriesDPad_SW, + SteelseriesDPad_W, + SteelseriesDPad_NW, + SteelseriesDPad_Released = 0x0f + }; + + struct SteelseriesStickData { + uint8_t x; + uint8_t y; + } __attribute__ ((__packed__)); + + struct SteelseriesButtonData { + uint8_t A : 1; + uint8_t B : 1; + uint8_t : 1; + uint8_t X : 1; + uint8_t Y : 1; + uint8_t : 1; + uint8_t L : 1; + uint8_t R : 1; + + uint8_t : 3; + uint8_t start : 1; + uint8_t select : 1; + uint8_t : 0; + } __attribute__ ((__packed__)); + + struct SteelseriesInputReport0x01 { + uint8_t dpad; + SteelseriesStickData left_stick; + SteelseriesStickData right_stick; + SteelseriesButtonData buttons; + } __attribute__((packed)); + + struct SteelseriesReportData { + uint8_t id; + union { + SteelseriesInputReport0x01 input0x01; + }; + } __attribute__((packed)); + + class SteelseriesController : public EmulatedSwitchController { + + public: + static constexpr const HardwareID hardware_ids[] = { + {0x1038, 0x1412} + }; + + SteelseriesController(const bluetooth::Address *address) + : EmulatedSwitchController(address) { }; + + void ConvertReportFormat(const bluetooth::HidReport *in_report, bluetooth::HidReport *out_report); + + private: + void HandleInputReport0x01(const SteelseriesReportData *src, SwitchReportData *dst); + + }; + +}