Skip to content

Commit 4ba0a00

Browse files
committed
Add PID and GetDeviceInfo's response type spoofing for all controllers except Joycons.
Prevent SPI flash writes when emulating a Pro Controller and report default colors.
1 parent b076bc2 commit 4ba0a00

File tree

8 files changed

+167
-5
lines changed

8 files changed

+167
-5
lines changed

mc_mitm/config.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@
1919
;enable_dualsense_player_leds=false
2020
; Set Dualsense vibration intensity, 12.5% per increment. Valid range [1-8] where 1=12.5%, 8=100% [default 4(50%)]
2121
;dualsense_vibration_intensity=4
22+
; Change the controller type/PID reported by every official controller but Joycons to be a Pro Controller, allowing full button remapping [default false]
23+
;force_pro_controller=false

mc_mitm/source/btm_mitm/btm_mitm_service.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "btm_mitm_service.hpp"
1717
#include "btm_shim.h"
1818
#include "../controllers/controller_management.hpp"
19+
#include "../mcmitm_config.hpp"
1920

2021
namespace ams::mitm::btm {
2122

@@ -83,6 +84,10 @@ namespace ams::mitm::btm {
8384
if (!controller::IsOfficialSwitchControllerName(device->name.name)) {
8485
std::strncpy(device->name.name, controller::pro_controller_name, sizeof(device->name) - 1);
8586
}
87+
else if (mitm::GetGlobalConfig()->misc.force_pro_controller && controller::IsNotJoyconOrProController(device->name.name)) {
88+
device->profile_info.hid_device_info.vid = 0x057e; //This may not have any effect, it's just to fix problems with a Licensed Pro Controller
89+
device->profile_info.hid_device_info.pid = 0x2009; //Change Pid to a Pro controller one
90+
}
8691
}
8792

8893
return ams::ResultSuccess();
@@ -97,6 +102,10 @@ namespace ams::mitm::btm {
97102
if (!controller::IsOfficialSwitchControllerName(device->name)) {
98103
std::strncpy(device->name, controller::pro_controller_name, sizeof(device->name) - 1);
99104
}
105+
else if (mitm::GetGlobalConfig()->misc.force_pro_controller && controller::IsNotJoyconOrProController(device->name)) {
106+
device->profile_info.hid_device_info.vid = 0x057e; //This may not have any effect, it's just to fix problems with a Licensed Pro Controller
107+
device->profile_info.hid_device_info.pid = 0x2009; //Change Pid to a Pro controller one
108+
}
100109
}
101110

102111
return ams::ResultSuccess();

mc_mitm/source/controllers/controller_management.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "controller_management.hpp"
1717
#include <stratosphere.hpp>
1818
#include "../utils.hpp"
19+
#include "../mcmitm_config.hpp"
1920

2021
namespace ams::controller {
2122

@@ -48,6 +49,7 @@ namespace ams::controller {
4849
if (IsOfficialSwitchControllerName(hos::GetVersion() < hos::Version_13_0_0 ? device->name.name : device->name2))
4950
return ControllerType_Switch;
5051

52+
5153
for (auto hwId : WiiController::hardware_ids) {
5254
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
5355
return ControllerType_Wii;
@@ -191,6 +193,16 @@ namespace ams::controller {
191193
return false;
192194
}
193195

196+
bool IsNotJoyconOrProController(const std::string& name) {
197+
std::string JoyconName = "Joy-Con";
198+
std::string ProControllerName = "Pro Controller";
199+
if (name.rfind(JoyconName) == 0 || name.rfind(ProControllerName) == 0) {
200+
return false;
201+
}
202+
203+
return true;
204+
}
205+
194206
void AttachHandler(const bluetooth::Address *address) {
195207
bluetooth::DevicesSettings device_settings;
196208
R_ABORT_UNLESS(btdrvGetPairedDeviceInfo(*address, &device_settings));
@@ -201,7 +213,9 @@ namespace ams::controller {
201213

202214
switch (Identify(&device_settings)) {
203215
case ControllerType_Switch:
204-
controller = std::make_shared<SwitchController>(address, id);
216+
if (mitm::GetGlobalConfig()->misc.force_pro_controller && IsNotJoyconOrProController(hos::GetVersion() < hos::Version_13_0_0 ? device_settings.name.name : device_settings.name2))
217+
controller = std::make_shared<ForcedProController>(address, id);
218+
else controller = std::make_shared<SwitchController>(address, id);
205219
break;
206220
case ControllerType_Wii:
207221
controller = std::make_shared<WiiController>(address, id);

mc_mitm/source/controllers/controller_management.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <string>
1919

2020
#include "switch_controller.hpp"
21+
#include "forced_pro_controller.hpp"
2122
#include "wii_controller.hpp"
2223
#include "dualshock4_controller.hpp"
2324
#include "dualsense_controller.hpp"
@@ -80,6 +81,7 @@ namespace ams::controller {
8081
ControllerType Identify(const bluetooth::DevicesSettings *device);
8182
bool IsAllowedDeviceClass(const bluetooth::DeviceClass *cod);
8283
bool IsOfficialSwitchControllerName(const std::string& name);
84+
bool IsNotJoyconOrProController(const std::string& name);
8385

8486
void AttachHandler(const bluetooth::Address *address);
8587
void RemoveHandler(const bluetooth::Address *address);
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright (c) 2020-2022 ndeadly
3+
*
4+
* This program is free software; you can redistribute it and/or modify it
5+
* under the terms and conditions of the GNU General Public License,
6+
* version 2, as published by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope it will be useful, but WITHOUT
9+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11+
* more details.
12+
*
13+
* You should have received a copy of the GNU General Public License
14+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*/
16+
#include "forced_pro_controller.hpp"
17+
#include "../mcmitm_config.hpp"
18+
19+
namespace ams::controller {
20+
21+
ForcedProController::ForcedProController(const bluetooth::Address *address, HardwareID id)
22+
: SwitchController(address, id) {}
23+
24+
25+
Result ForcedProController::HandleDataReportEvent(const bluetooth::HidReportEventInfo *event_info) {
26+
const bluetooth::HidReport *report;
27+
if (hos::GetVersion() >= hos::Version_9_0_0) {
28+
report = &event_info->data_report.v9.report;
29+
} else if (hos::GetVersion() >= hos::Version_7_0_0) {
30+
report = reinterpret_cast<const bluetooth::HidReport *>(&event_info->data_report.v7.report);
31+
} else {
32+
report = reinterpret_cast<const bluetooth::HidReport *>(&event_info->data_report.v1.report);
33+
}
34+
35+
if (!m_future_responses.empty()) {
36+
if ((m_future_responses.back()->GetType() == BtdrvHidEventType_Data) && (m_future_responses.back()->GetUserData() == report->data[0])) {
37+
m_future_responses.back()->SetData(*event_info);
38+
}
39+
}
40+
41+
std::scoped_lock lk(m_input_mutex);
42+
43+
this->UpdateControllerState(report);
44+
45+
auto input_report = reinterpret_cast<SwitchInputReport *>(m_input_report.data);
46+
if (input_report->id == 0x21) {
47+
auto response = &input_report->type0x21.hid_command_response;
48+
switch (response->id) {
49+
case HidCommand_SerialFlashRead:
50+
if (response->data.serial_flash_read.address == 0x6050) {
51+
if (ams::mitm::GetSystemLanguage() == 10) {
52+
uint8_t data[] = {0xff, 0xd7, 0x00, 0x00, 0x57, 0xb7, 0x00, 0x57, 0xb7, 0x00, 0x57, 0xb7};
53+
std::memcpy(response->data.serial_flash_read.data, data, sizeof(data));
54+
}
55+
else {
56+
uint8_t data[] = {0x32, 0x32, 0x32, 0xe6, 0xe6, 0xe6, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46};
57+
std::memcpy(response->data.serial_flash_read.data, data, sizeof(data));
58+
}
59+
}
60+
break;
61+
case HidCommand_GetDeviceInfo:
62+
response->data.get_device_info.type = 0x03;
63+
response->data.get_device_info._unk2 = 0x02;
64+
break;
65+
}
66+
}
67+
68+
this->ApplyButtonCombos(&input_report->buttons);
69+
70+
return bluetooth::hid::report::WriteHidDataReport(m_address, &m_input_report);
71+
}
72+
73+
Result ForcedProController::HandleOutputDataReport(const bluetooth::HidReport *report) {
74+
auto output_report = reinterpret_cast<const SwitchOutputReport *>(&report->data);
75+
if (output_report->id == 0x01 && (output_report->type0x01.hid_command.id == HidCommand_SerialFlashWrite || output_report->type0x01.hid_command.id == HidCommand_SerialFlashSectorErase)) {
76+
SwitchInputReport input_report = {
77+
.id = 0x21,
78+
.timer = 1,
79+
.conn_info = 1,
80+
.battery = BATTERY_MAX,
81+
.vibrator = 0,
82+
};
83+
84+
input_report.type0x21.hid_command_response = {
85+
.ack = 0x80,
86+
.id = output_report->type0x01.hid_command.id,
87+
.data = {
88+
.serial_flash_write = {
89+
.status = 0x1 //Force write protected response just to be safe
90+
}
91+
}
92+
};
93+
94+
return bluetooth::hid::report::WriteHidDataReport(m_address, &m_input_report);
95+
}
96+
return this->WriteDataReport(report);
97+
}
98+
99+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (c) 2020-2022 ndeadly
3+
*
4+
* This program is free software; you can redistribute it and/or modify it
5+
* under the terms and conditions of the GNU General Public License,
6+
* version 2, as published by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope it will be useful, but WITHOUT
9+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11+
* more details.
12+
*
13+
* You should have received a copy of the GNU General Public License
14+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*/
16+
#pragma once
17+
#include "switch_controller.hpp"
18+
19+
namespace ams::controller {
20+
21+
class ForcedProController : public SwitchController {
22+
23+
public:
24+
ForcedProController(const bluetooth::Address *address, HardwareID id);
25+
virtual ~ForcedProController() {};
26+
27+
Result HandleDataReportEvent(const bluetooth::HidReportEventInfo *event_info);
28+
Result HandleOutputDataReport(const bluetooth::HidReport *report);
29+
30+
};
31+
32+
}

mc_mitm/source/mcmitm_config.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,16 @@ namespace ams::mitm {
3333
.enable_dualshock4_lightbar = true,
3434
.enable_dualsense_lightbar = true,
3535
.enable_dualsense_player_leds = true,
36-
.dualsense_vibration_intensity = 4
36+
.dualsense_vibration_intensity = 4,
37+
.force_pro_controller = false
3738
}
3839
};
3940

4041
void ParseBoolean(const char *value, bool *out) {
4142
if (strcasecmp(value, "true") == 0)
4243
*out = true;
4344
else if (strcasecmp(value, "false") == 0)
44-
*out = false;
45+
*out = false;
4546
}
4647

4748
void ParseInt(const char *value, int *out, int min=INT_MIN, int max=INT_MAX) {
@@ -75,9 +76,9 @@ namespace ams::mitm {
7576

7677
if (strcasecmp(section, "general") == 0) {
7778
if (strcasecmp(name, "enable_rumble") == 0)
78-
ParseBoolean(value, &config->general.enable_rumble);
79+
ParseBoolean(value, &config->general.enable_rumble);
7980
else if (strcasecmp(name, "enable_motion") == 0)
80-
ParseBoolean(value, &config->general.enable_motion);
81+
ParseBoolean(value, &config->general.enable_motion);
8182
}
8283
else if (strcasecmp(section, "bluetooth") == 0) {
8384
if (strcasecmp(name, "host_name") == 0)
@@ -94,6 +95,8 @@ namespace ams::mitm {
9495
ParseBoolean(value, &config->misc.enable_dualsense_player_leds);
9596
else if (strcasecmp(name, "dualsense_vibration_intensity") == 0)
9697
ParseInt(value, &config->misc.dualsense_vibration_intensity, 1, 8);
98+
else if (strcasecmp(name, "force_pro_controller") == 0)
99+
ParseBoolean(value, &config->misc.force_pro_controller);
97100
}
98101
else {
99102
return 0;

mc_mitm/source/mcmitm_config.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ namespace ams::mitm {
3333
bool enable_dualsense_lightbar;
3434
bool enable_dualsense_player_leds;
3535
int dualsense_vibration_intensity;
36+
bool force_pro_controller;
3637
} misc;
3738
};
3839

0 commit comments

Comments
 (0)