Skip to content

Commit 8f28dec

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 38c9879 commit 8f28dec

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
@@ -26,3 +26,5 @@
2626
;dualsense_enable_player_leds=false
2727
; Set Dualsense vibration intensity, 12.5% per increment. Valid range [1-8] where 1=12.5%, 8=100% [default 4(50%)]
2828
;dualsense_vibration_intensity=4
29+
; Change the controller type/PID reported by every official controller but Joycons to be a Pro Controller, allowing full button remapping [default false]
30+
;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

@@ -55,6 +56,10 @@ namespace ams::mitm::btm {
5556
if (!controller::IsOfficialSwitchControllerName(device->name)) {
5657
std::strncpy(device->name, controller::pro_controller_name, sizeof(device->name) - 1);
5758
}
59+
else if (mitm::GetGlobalConfig()->misc.force_pro_controller && controller::IsNotJoyconOrProController(device->name)) {
60+
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
61+
device->profile_info.hid_device_info.pid = 0x2009; //Change Pid to a Pro controller one
62+
}
5863
}
5964

6065
R_SUCCEED();
@@ -108,6 +113,10 @@ namespace ams::mitm::btm {
108113
if (!controller::IsOfficialSwitchControllerName(device->name.name)) {
109114
std::strncpy(device->name.name, controller::pro_controller_name, sizeof(device->name) - 1);
110115
}
116+
else if (mitm::GetGlobalConfig()->misc.force_pro_controller && controller::IsNotJoyconOrProController(device->name.name)) {
117+
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
118+
device->profile_info.hid_device_info.pid = 0x2009; //Change Pid to a Pro controller one
119+
}
111120
}
112121

113122
R_SUCCEED();

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

@@ -57,6 +58,7 @@ namespace ams::controller {
5758
if (IsOfficialSwitchControllerName(hos::GetVersion() < hos::Version_13_0_0 ? device->name.name : device->name2))
5859
return ControllerType_Switch;
5960

61+
6062
for (auto hwId : WiiController::hardware_ids) {
6163
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
6264
return ControllerType_Wii;
@@ -218,6 +220,16 @@ namespace ams::controller {
218220
return false;
219221
}
220222

223+
bool IsNotJoyconOrProController(const std::string& name) {
224+
std::string JoyconName = "Joy-Con";
225+
std::string ProControllerName = "Pro Controller";
226+
if (name.rfind(JoyconName) == 0 || name.rfind(ProControllerName) == 0) {
227+
return false;
228+
}
229+
230+
return true;
231+
}
232+
221233
void AttachHandler(const bluetooth::Address *address) {
222234
bluetooth::DevicesSettings device_settings;
223235
R_ABORT_UNLESS(btdrvGetPairedDeviceInfo(*address, &device_settings));
@@ -228,7 +240,9 @@ namespace ams::controller {
228240

229241
switch (Identify(&device_settings)) {
230242
case ControllerType_Switch:
231-
controller = std::make_shared<SwitchController>(address, id);
243+
if (mitm::GetGlobalConfig()->misc.force_pro_controller && IsNotJoyconOrProController(hos::GetVersion() < hos::Version_13_0_0 ? device_settings.name.name : device_settings.name2))
244+
controller = std::make_shared<ForcedProController>(address, id);
245+
else controller = std::make_shared<SwitchController>(address, id);
232246
break;
233247
case ControllerType_Wii:
234248
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 "dualshock3_controller.hpp"
2324
#include "dualshock4_controller.hpp"
@@ -86,6 +87,7 @@ namespace ams::controller {
8687
ControllerType Identify(const bluetooth::DevicesSettings *device);
8788
bool IsAllowedDeviceClass(const bluetooth::DeviceClass *cod);
8889
bool IsOfficialSwitchControllerName(const std::string& name);
90+
bool IsNotJoyconOrProController(const std::string& name);
8991

9092
void AttachHandler(const bluetooth::Address *address);
9193
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
@@ -36,15 +36,16 @@ namespace ams::mitm {
3636
.dualshock4_lightbar_brightness = 5,
3737
.dualsense_lightbar_brightness = 5,
3838
.dualsense_enable_player_leds = true,
39-
.dualsense_vibration_intensity = 4
39+
.dualsense_vibration_intensity = 4,
40+
.force_pro_controller = false
4041
}
4142
};
4243

4344
void ParseBoolean(const char *value, bool *out) {
4445
if (strcasecmp(value, "true") == 0)
4546
*out = true;
4647
else if (strcasecmp(value, "false") == 0)
47-
*out = false;
48+
*out = false;
4849
}
4950

5051
void ParseInt(const char *value, int *out, int min=INT_MIN, int max=INT_MAX) {
@@ -107,8 +108,10 @@ namespace ams::mitm {
107108
ParseBoolean(value, &config->misc.dualsense_enable_player_leds);
108109
} else if (strcasecmp(name, "dualsense_vibration_intensity") == 0) {
109110
ParseInt(value, &config->misc.dualsense_vibration_intensity, 1, 8);
110-
}
111-
} else {
111+
} else if (strcasecmp(name, "force_pro_controller") == 0)
112+
ParseBoolean(value, &config->misc.force_pro_controller);
113+
}
114+
else {
112115
return 0;
113116
}
114117

mc_mitm/source/mcmitm_config.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ namespace ams::mitm {
3636
int dualsense_lightbar_brightness;
3737
bool dualsense_enable_player_leds;
3838
int dualsense_vibration_intensity;
39+
bool force_pro_controller;
3940
} misc;
4041
};
4142

0 commit comments

Comments
 (0)