2020-08-25 19:23:38 +00:00
|
|
|
/*
|
2021-01-26 03:03:26 +00:00
|
|
|
* Copyright (c) 2020-2021 ndeadly
|
2020-08-25 19:23:38 +00:00
|
|
|
*
|
2020-08-26 22:50:34 +00:00
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms and conditions of the GNU General Public License,
|
|
|
|
* version 2, as published by the Free Software Foundation.
|
2020-08-25 19:23:38 +00:00
|
|
|
*
|
2020-08-26 22:50:34 +00:00
|
|
|
* This program is distributed in the hope 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.
|
2020-08-25 19:23:38 +00:00
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2020-08-26 18:52:47 +00:00
|
|
|
#include "controller_management.hpp"
|
|
|
|
#include <stratosphere.hpp>
|
2020-06-25 21:50:43 +00:00
|
|
|
#include <memory>
|
|
|
|
#include <mutex>
|
2020-06-11 18:34:14 +00:00
|
|
|
#include <vector>
|
2020-06-22 21:14:54 +00:00
|
|
|
#include <cstring>
|
2020-06-11 18:34:14 +00:00
|
|
|
|
2020-07-11 19:10:38 +00:00
|
|
|
namespace ams::controller {
|
2020-06-11 18:34:14 +00:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2020-12-06 14:54:55 +00:00
|
|
|
const std::string official_npad_names[] = {
|
|
|
|
"Joy-Con",
|
|
|
|
"Pro Controller",
|
|
|
|
"Lic Pro Controller",
|
|
|
|
"NES Controller",
|
|
|
|
"HVC Controller",
|
|
|
|
"SNES Controller",
|
|
|
|
"NintendoGamepad",
|
|
|
|
};
|
|
|
|
|
2020-08-26 18:52:47 +00:00
|
|
|
constexpr auto cod_major_peripheral = 0x05;
|
|
|
|
constexpr auto cod_minor_gamepad = 0x08;
|
|
|
|
constexpr auto cod_minor_joystick = 0x04;
|
2020-09-20 17:55:42 +00:00
|
|
|
constexpr auto cod_minor_keyboard = 0x40;
|
2020-06-13 00:11:05 +00:00
|
|
|
|
2020-08-26 18:52:47 +00:00
|
|
|
os::Mutex g_controller_lock(false);
|
|
|
|
std::vector<std::unique_ptr<SwitchController>> g_controllers;
|
2020-06-11 18:34:14 +00:00
|
|
|
|
2020-08-26 18:52:47 +00:00
|
|
|
inline bool bdcmp(const bluetooth::Address *addr1, const bluetooth::Address *addr2) {
|
|
|
|
return std::memcmp(addr1, addr2, sizeof(bluetooth::Address)) == 0;
|
2020-06-11 18:34:14 +00:00
|
|
|
}
|
|
|
|
|
2020-08-26 18:52:47 +00:00
|
|
|
}
|
2020-06-11 18:34:14 +00:00
|
|
|
|
2020-12-02 20:59:05 +00:00
|
|
|
ControllerType Identify(const bluetooth::DevicesSettings *device) {
|
2020-09-07 23:24:52 +00:00
|
|
|
|
2021-03-17 01:44:49 +00:00
|
|
|
if (IsOfficialSwitchControllerName(device->name.name))
|
2020-09-08 08:54:57 +00:00
|
|
|
return ControllerType_Switch;
|
2020-06-11 18:34:14 +00:00
|
|
|
|
2020-08-26 18:52:47 +00:00
|
|
|
for (auto hwId : WiiController::hardware_ids) {
|
2020-08-11 23:16:32 +00:00
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
2020-08-26 18:52:47 +00:00
|
|
|
return ControllerType_Wii;
|
2020-06-11 18:34:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-26 18:52:47 +00:00
|
|
|
for (auto hwId : Dualshock4Controller::hardware_ids) {
|
2020-08-11 23:16:32 +00:00
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
2020-07-11 19:10:38 +00:00
|
|
|
return ControllerType_Dualshock4;
|
2020-06-11 18:34:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-13 22:26:40 +00:00
|
|
|
for (auto hwId : DualsenseController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_Dualsense;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-26 18:52:47 +00:00
|
|
|
for (auto hwId : XboxOneController::hardware_ids) {
|
2020-08-11 23:16:32 +00:00
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
2020-07-11 19:10:38 +00:00
|
|
|
return ControllerType_XboxOne;
|
2020-06-11 18:34:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-28 18:53:08 +00:00
|
|
|
for (auto hwId : OuyaController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_Ouya;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-02 18:46:14 +00:00
|
|
|
for (auto hwId : GamestickController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_Gamestick;
|
2020-09-07 08:52:53 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-02 18:46:14 +00:00
|
|
|
|
2020-09-06 11:45:50 +00:00
|
|
|
for (auto hwId : GemboxController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_Gembox;
|
|
|
|
}
|
2020-08-11 23:16:32 +00:00
|
|
|
}
|
2020-09-07 08:52:53 +00:00
|
|
|
|
2020-09-02 23:03:37 +00:00
|
|
|
for (auto hwId : IpegaController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_Ipega;
|
|
|
|
}
|
2020-09-07 08:52:53 +00:00
|
|
|
}
|
2020-08-11 23:16:32 +00:00
|
|
|
|
2020-09-02 19:20:25 +00:00
|
|
|
for (auto hwId : XiaomiController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_Xiaomi;
|
|
|
|
}
|
|
|
|
}
|
2020-09-12 12:20:02 +00:00
|
|
|
|
|
|
|
for (auto hwId : GamesirController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_Gamesir;
|
|
|
|
}
|
|
|
|
}
|
2020-09-12 22:30:30 +00:00
|
|
|
|
2020-09-12 13:09:33 +00:00
|
|
|
for (auto hwId : SteelseriesController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_Steelseries;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-17 18:52:44 +00:00
|
|
|
for (auto hwId : NvidiaShieldController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_NvidiaShield;
|
2020-09-20 16:27:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-13 23:59:55 +00:00
|
|
|
for (auto hwId : EightBitDoController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_8BitDo;
|
2020-09-17 18:52:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-26 17:01:28 +00:00
|
|
|
for (auto hwId : PowerAController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_PowerA;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-06 22:31:13 +00:00
|
|
|
for (auto hwId : MadCatzController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_MadCatz;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-18 22:04:40 +00:00
|
|
|
for (auto hwId : MocuteController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_Mocute;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-15 19:41:11 +00:00
|
|
|
for (auto hwId : RazerController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_Razer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-14 13:24:34 +00:00
|
|
|
for (auto hwId : ICadeController::hardware_ids) {
|
|
|
|
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
|
|
|
|
return ControllerType_ICade;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-11 19:10:38 +00:00
|
|
|
return ControllerType_Unknown;
|
2020-06-11 18:34:14 +00:00
|
|
|
}
|
|
|
|
|
2020-12-11 23:07:41 +00:00
|
|
|
bool IsAllowedDeviceClass(const bluetooth::DeviceClass *cod) {
|
2021-03-17 01:44:49 +00:00
|
|
|
return ((cod->class_of_device[1] & 0x0f) == cod_major_peripheral) &&
|
|
|
|
(((cod->class_of_device[2] & 0x0f) == cod_minor_gamepad) || ((cod->class_of_device[2] & 0x0f) == cod_minor_joystick) || ((cod->class_of_device[2] & 0x40) == cod_minor_keyboard));
|
2020-08-26 18:52:47 +00:00
|
|
|
}
|
2020-07-11 21:53:30 +00:00
|
|
|
|
2020-12-06 14:54:55 +00:00
|
|
|
bool IsOfficialSwitchControllerName(const std::string& name) {
|
|
|
|
for (auto n : official_npad_names) {
|
|
|
|
if (name.rfind(n, 0) == 0)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2020-06-11 18:34:14 +00:00
|
|
|
}
|
|
|
|
|
2020-08-26 18:52:47 +00:00
|
|
|
void AttachHandler(const bluetooth::Address *address) {
|
|
|
|
std::scoped_lock lk(g_controller_lock);
|
2020-06-25 21:50:43 +00:00
|
|
|
|
2020-12-02 20:59:05 +00:00
|
|
|
bluetooth::DevicesSettings device;
|
|
|
|
R_ABORT_UNLESS(btdrvGetPairedDeviceInfo(*address, &device));
|
2020-06-11 18:34:14 +00:00
|
|
|
|
2020-08-26 18:52:47 +00:00
|
|
|
switch (Identify(&device)) {
|
|
|
|
case ControllerType_Switch:
|
|
|
|
g_controllers.push_back(std::make_unique<SwitchController>(address));
|
2020-06-11 18:34:14 +00:00
|
|
|
break;
|
2020-08-26 18:52:47 +00:00
|
|
|
case ControllerType_Wii:
|
|
|
|
g_controllers.push_back(std::make_unique<WiiController>(address));
|
2020-06-11 18:34:14 +00:00
|
|
|
break;
|
2020-07-11 19:10:38 +00:00
|
|
|
case ControllerType_Dualshock4:
|
|
|
|
g_controllers.push_back(std::make_unique<Dualshock4Controller>(address));
|
2020-06-11 18:34:14 +00:00
|
|
|
break;
|
2020-11-13 22:26:40 +00:00
|
|
|
case ControllerType_Dualsense:
|
|
|
|
g_controllers.push_back(std::make_unique<DualsenseController>(address));
|
|
|
|
break;
|
2020-07-11 19:10:38 +00:00
|
|
|
case ControllerType_XboxOne:
|
|
|
|
g_controllers.push_back(std::make_unique<XboxOneController>(address));
|
2020-06-11 18:34:14 +00:00
|
|
|
break;
|
2020-08-28 18:53:08 +00:00
|
|
|
case ControllerType_Ouya:
|
|
|
|
g_controllers.push_back(std::make_unique<OuyaController>(address));
|
|
|
|
break;
|
2020-09-02 18:46:14 +00:00
|
|
|
case ControllerType_Gamestick:
|
|
|
|
g_controllers.push_back(std::make_unique<GamestickController>(address));
|
2020-09-07 08:42:22 +00:00
|
|
|
break;
|
2020-09-06 21:39:31 +00:00
|
|
|
case ControllerType_Gembox:
|
|
|
|
g_controllers.push_back(std::make_unique<GemboxController>(address));
|
|
|
|
break;
|
2020-09-06 21:38:13 +00:00
|
|
|
case ControllerType_Ipega:
|
|
|
|
g_controllers.push_back(std::make_unique<IpegaController>(address));
|
2020-09-07 08:52:53 +00:00
|
|
|
break;
|
2020-09-06 21:35:29 +00:00
|
|
|
case ControllerType_Xiaomi:
|
|
|
|
g_controllers.push_back(std::make_unique<XiaomiController>(address));
|
2020-09-02 18:46:14 +00:00
|
|
|
break;
|
2020-09-12 12:20:02 +00:00
|
|
|
case ControllerType_Gamesir:
|
|
|
|
g_controllers.push_back(std::make_unique<GamesirController>(address));
|
2020-09-12 22:30:30 +00:00
|
|
|
break;
|
2020-09-12 13:09:33 +00:00
|
|
|
case ControllerType_Steelseries:
|
|
|
|
g_controllers.push_back(std::make_unique<SteelseriesController>(address));
|
2020-09-12 12:20:02 +00:00
|
|
|
break;
|
2020-09-17 18:52:44 +00:00
|
|
|
case ControllerType_NvidiaShield:
|
|
|
|
g_controllers.push_back(std::make_unique<NvidiaShieldController>(address));
|
2020-09-20 16:27:23 +00:00
|
|
|
break;
|
2020-09-13 23:59:55 +00:00
|
|
|
case ControllerType_8BitDo:
|
|
|
|
g_controllers.push_back(std::make_unique<EightBitDoController>(address));
|
2020-09-17 18:52:44 +00:00
|
|
|
break;
|
2020-09-26 17:01:28 +00:00
|
|
|
case ControllerType_PowerA:
|
|
|
|
g_controllers.push_back(std::make_unique<PowerAController>(address));
|
|
|
|
break;
|
2020-10-06 22:31:13 +00:00
|
|
|
case ControllerType_MadCatz:
|
|
|
|
g_controllers.push_back(std::make_unique<MadCatzController>(address));
|
|
|
|
break;
|
2020-10-18 22:04:40 +00:00
|
|
|
case ControllerType_Mocute:
|
|
|
|
g_controllers.push_back(std::make_unique<MocuteController>(address));
|
|
|
|
break;
|
2020-11-15 19:41:11 +00:00
|
|
|
case ControllerType_Razer:
|
|
|
|
g_controllers.push_back(std::make_unique<RazerController>(address));
|
|
|
|
break;
|
2021-03-14 13:24:34 +00:00
|
|
|
case ControllerType_ICade:
|
|
|
|
g_controllers.push_back(std::make_unique<ICadeController>(address));
|
|
|
|
break;
|
2020-06-11 18:34:14 +00:00
|
|
|
default:
|
2020-10-04 15:16:07 +00:00
|
|
|
g_controllers.push_back(std::make_unique<UnknownController>(address));
|
2020-09-07 21:18:31 +00:00
|
|
|
break;
|
2020-06-11 18:34:14 +00:00
|
|
|
}
|
|
|
|
|
2020-08-26 18:52:47 +00:00
|
|
|
g_controllers.back()->Initialize();
|
2020-06-11 18:34:14 +00:00
|
|
|
}
|
|
|
|
|
2020-08-26 18:52:47 +00:00
|
|
|
void RemoveHandler(const bluetooth::Address *address) {
|
|
|
|
std::scoped_lock lk(g_controller_lock);
|
2020-06-13 00:11:05 +00:00
|
|
|
|
2020-06-11 18:34:14 +00:00
|
|
|
for (auto it = g_controllers.begin(); it < g_controllers.end(); ++it) {
|
2020-08-26 18:52:47 +00:00
|
|
|
if (bdcmp(&(*it)->Address(), address)) {
|
2020-06-11 18:34:14 +00:00
|
|
|
g_controllers.erase(it);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-26 18:52:47 +00:00
|
|
|
SwitchController *LocateHandler(const bluetooth::Address *address) {
|
|
|
|
std::scoped_lock lk(g_controller_lock);
|
|
|
|
|
|
|
|
for (auto it = g_controllers.begin(); it < g_controllers.end(); ++it) {
|
|
|
|
if (bdcmp(&(*it)->Address(), address)) {
|
|
|
|
return (*it).get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-06-11 18:34:14 +00:00
|
|
|
}
|