joycon.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <fmt/format.h>
  4. #include "common/param_package.h"
  5. #include "common/polyfill_ranges.h"
  6. #include "common/polyfill_thread.h"
  7. #include "common/settings.h"
  8. #include "common/thread.h"
  9. #include "input_common/drivers/joycon.h"
  10. #include "input_common/helpers/joycon_driver.h"
  11. #include "input_common/helpers/joycon_protocol/joycon_types.h"
  12. namespace InputCommon {
  13. Joycons::Joycons(const std::string& input_engine_) : InputEngine(input_engine_) {
  14. // Avoid conflicting with SDL driver
  15. if (!Settings::values.enable_joycon_driver && !Settings::values.enable_procon_driver) {
  16. return;
  17. }
  18. LOG_INFO(Input, "Joycon driver Initialization started");
  19. const int init_res = SDL_hid_init();
  20. if (init_res == 0) {
  21. Setup();
  22. } else {
  23. LOG_ERROR(Input, "Hidapi could not be initialized. failed with error = {}", init_res);
  24. }
  25. }
  26. Joycons::~Joycons() {
  27. Reset();
  28. }
  29. void Joycons::Reset() {
  30. scan_thread = {};
  31. for (const auto& device : left_joycons) {
  32. if (!device) {
  33. continue;
  34. }
  35. device->Stop();
  36. }
  37. for (const auto& device : right_joycons) {
  38. if (!device) {
  39. continue;
  40. }
  41. device->Stop();
  42. }
  43. for (const auto& device : pro_controller) {
  44. if (!device) {
  45. continue;
  46. }
  47. device->Stop();
  48. }
  49. SDL_hid_exit();
  50. }
  51. void Joycons::Setup() {
  52. u32 port = 0;
  53. PreSetController(GetIdentifier(0, Joycon::ControllerType::None));
  54. for (auto& device : left_joycons) {
  55. PreSetController(GetIdentifier(port, Joycon::ControllerType::Left));
  56. device = std::make_shared<Joycon::JoyconDriver>(port++);
  57. }
  58. port = 0;
  59. for (auto& device : right_joycons) {
  60. PreSetController(GetIdentifier(port, Joycon::ControllerType::Right));
  61. device = std::make_shared<Joycon::JoyconDriver>(port++);
  62. }
  63. port = 0;
  64. for (auto& device : pro_controller) {
  65. PreSetController(GetIdentifier(port, Joycon::ControllerType::Pro));
  66. device = std::make_shared<Joycon::JoyconDriver>(port++);
  67. }
  68. scan_thread = std::jthread([this](std::stop_token stop_token) { ScanThread(stop_token); });
  69. }
  70. void Joycons::ScanThread(std::stop_token stop_token) {
  71. constexpr u16 nintendo_vendor_id = 0x057e;
  72. Common::SetCurrentThreadName("JoyconScanThread");
  73. do {
  74. SDL_hid_device_info* devs = SDL_hid_enumerate(nintendo_vendor_id, 0x0);
  75. SDL_hid_device_info* cur_dev = devs;
  76. while (cur_dev) {
  77. if (IsDeviceNew(cur_dev)) {
  78. LOG_DEBUG(Input, "Device Found,type : {:04X} {:04X}", cur_dev->vendor_id,
  79. cur_dev->product_id);
  80. RegisterNewDevice(cur_dev);
  81. }
  82. cur_dev = cur_dev->next;
  83. }
  84. SDL_hid_free_enumeration(devs);
  85. } while (Common::StoppableTimedWait(stop_token, std::chrono::seconds{5}));
  86. }
  87. bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const {
  88. Joycon::ControllerType type{};
  89. Joycon::SerialNumber serial_number{};
  90. const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type);
  91. if (result != Joycon::DriverResult::Success) {
  92. return false;
  93. }
  94. const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number);
  95. if (result2 != Joycon::DriverResult::Success) {
  96. return false;
  97. }
  98. auto is_handle_identical = [serial_number](std::shared_ptr<Joycon::JoyconDriver> device) {
  99. if (!device) {
  100. return false;
  101. }
  102. if (!device->IsConnected()) {
  103. return false;
  104. }
  105. if (device->GetHandleSerialNumber() != serial_number) {
  106. return false;
  107. }
  108. return true;
  109. };
  110. // Check if device already exist
  111. switch (type) {
  112. case Joycon::ControllerType::Left:
  113. if (!Settings::values.enable_joycon_driver) {
  114. return false;
  115. }
  116. for (const auto& device : left_joycons) {
  117. if (is_handle_identical(device)) {
  118. return false;
  119. }
  120. }
  121. break;
  122. case Joycon::ControllerType::Right:
  123. if (!Settings::values.enable_joycon_driver) {
  124. return false;
  125. }
  126. for (const auto& device : right_joycons) {
  127. if (is_handle_identical(device)) {
  128. return false;
  129. }
  130. }
  131. break;
  132. case Joycon::ControllerType::Pro:
  133. if (!Settings::values.enable_procon_driver) {
  134. return false;
  135. }
  136. for (const auto& device : pro_controller) {
  137. if (is_handle_identical(device)) {
  138. return false;
  139. }
  140. }
  141. break;
  142. default:
  143. return false;
  144. }
  145. return true;
  146. }
  147. void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) {
  148. Joycon::ControllerType type{};
  149. auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type);
  150. auto handle = GetNextFreeHandle(type);
  151. if (handle == nullptr) {
  152. LOG_WARNING(Input, "No free handles available");
  153. return;
  154. }
  155. if (result == Joycon::DriverResult::Success) {
  156. result = handle->RequestDeviceAccess(device_info);
  157. }
  158. if (result == Joycon::DriverResult::Success) {
  159. LOG_WARNING(Input, "Initialize device");
  160. const std::size_t port = handle->GetDevicePort();
  161. const Joycon::JoyconCallbacks callbacks{
  162. .on_battery_data = {[this, port, type](Joycon::Battery value) {
  163. OnBatteryUpdate(port, type, value);
  164. }},
  165. .on_color_data = {[this, port, type](Joycon::Color value) {
  166. OnColorUpdate(port, type, value);
  167. }},
  168. .on_button_data = {[this, port, type](int id, bool value) {
  169. OnButtonUpdate(port, type, id, value);
  170. }},
  171. .on_stick_data = {[this, port, type](int id, f32 value) {
  172. OnStickUpdate(port, type, id, value);
  173. }},
  174. .on_motion_data = {[this, port, type](int id, const Joycon::MotionData& value) {
  175. OnMotionUpdate(port, type, id, value);
  176. }},
  177. .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }},
  178. .on_amiibo_data = {[this, port, type](const std::vector<u8>& amiibo_data) {
  179. OnAmiiboUpdate(port, type, amiibo_data);
  180. }},
  181. .on_camera_data = {[this, port](const std::vector<u8>& camera_data,
  182. Joycon::IrsResolution format) {
  183. OnCameraUpdate(port, camera_data, format);
  184. }},
  185. };
  186. handle->InitializeDevice();
  187. handle->SetCallbacks(callbacks);
  188. }
  189. }
  190. std::shared_ptr<Joycon::JoyconDriver> Joycons::GetNextFreeHandle(
  191. Joycon::ControllerType type) const {
  192. if (type == Joycon::ControllerType::Left) {
  193. const auto unconnected_device =
  194. std::ranges::find_if(left_joycons, [](auto& device) { return !device->IsConnected(); });
  195. if (unconnected_device != left_joycons.end()) {
  196. return *unconnected_device;
  197. }
  198. }
  199. if (type == Joycon::ControllerType::Right) {
  200. const auto unconnected_device = std::ranges::find_if(
  201. right_joycons, [](auto& device) { return !device->IsConnected(); });
  202. if (unconnected_device != right_joycons.end()) {
  203. return *unconnected_device;
  204. }
  205. }
  206. if (type == Joycon::ControllerType::Pro) {
  207. const auto unconnected_device = std::ranges::find_if(
  208. pro_controller, [](auto& device) { return !device->IsConnected(); });
  209. if (unconnected_device != pro_controller.end()) {
  210. return *unconnected_device;
  211. }
  212. }
  213. return nullptr;
  214. }
  215. bool Joycons::IsVibrationEnabled(const PadIdentifier& identifier) {
  216. const auto handle = GetHandle(identifier);
  217. if (handle == nullptr) {
  218. return false;
  219. }
  220. return handle->IsVibrationEnabled();
  221. }
  222. Common::Input::DriverResult Joycons::SetVibration(const PadIdentifier& identifier,
  223. const Common::Input::VibrationStatus& vibration) {
  224. const Joycon::VibrationValue native_vibration{
  225. .low_amplitude = vibration.low_amplitude,
  226. .low_frequency = vibration.low_frequency,
  227. .high_amplitude = vibration.high_amplitude,
  228. .high_frequency = vibration.high_frequency,
  229. };
  230. auto handle = GetHandle(identifier);
  231. if (handle == nullptr) {
  232. return Common::Input::DriverResult::InvalidHandle;
  233. }
  234. handle->SetVibration(native_vibration);
  235. return Common::Input::DriverResult::Success;
  236. }
  237. Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier,
  238. const Common::Input::LedStatus& led_status) {
  239. auto handle = GetHandle(identifier);
  240. if (handle == nullptr) {
  241. return Common::Input::DriverResult::InvalidHandle;
  242. }
  243. int led_config = led_status.led_1 ? 1 : 0;
  244. led_config += led_status.led_2 ? 2 : 0;
  245. led_config += led_status.led_3 ? 4 : 0;
  246. led_config += led_status.led_4 ? 8 : 0;
  247. return static_cast<Common::Input::DriverResult>(
  248. handle->SetLedConfig(static_cast<u8>(led_config)));
  249. }
  250. Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier,
  251. Common::Input::CameraFormat camera_format) {
  252. auto handle = GetHandle(identifier);
  253. if (handle == nullptr) {
  254. return Common::Input::DriverResult::InvalidHandle;
  255. }
  256. return static_cast<Common::Input::DriverResult>(handle->SetIrsConfig(
  257. Joycon::IrsMode::ImageTransfer, static_cast<Joycon::IrsResolution>(camera_format)));
  258. };
  259. Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const {
  260. return Common::Input::NfcState::Success;
  261. };
  262. Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier,
  263. const std::vector<u8>& data) {
  264. auto handle = GetHandle(identifier);
  265. if (handle->WriteNfcData(data) != Joycon::DriverResult::Success) {
  266. return Common::Input::NfcState::WriteFailed;
  267. }
  268. return Common::Input::NfcState::Success;
  269. };
  270. Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier,
  271. const Common::Input::PollingMode polling_mode) {
  272. auto handle = GetHandle(identifier);
  273. if (handle == nullptr) {
  274. LOG_ERROR(Input, "Invalid handle {}", identifier.port);
  275. return Common::Input::DriverResult::InvalidHandle;
  276. }
  277. switch (polling_mode) {
  278. case Common::Input::PollingMode::Active:
  279. return static_cast<Common::Input::DriverResult>(handle->SetActiveMode());
  280. case Common::Input::PollingMode::Passive:
  281. return static_cast<Common::Input::DriverResult>(handle->SetPassiveMode());
  282. case Common::Input::PollingMode::IR:
  283. return static_cast<Common::Input::DriverResult>(handle->SetIrMode());
  284. case Common::Input::PollingMode::NFC:
  285. return static_cast<Common::Input::DriverResult>(handle->SetNfcMode());
  286. case Common::Input::PollingMode::Ring:
  287. return static_cast<Common::Input::DriverResult>(handle->SetRingConMode());
  288. default:
  289. return Common::Input::DriverResult::NotSupported;
  290. }
  291. }
  292. void Joycons::OnBatteryUpdate(std::size_t port, Joycon::ControllerType type,
  293. Joycon::Battery value) {
  294. const auto identifier = GetIdentifier(port, type);
  295. if (value.charging != 0) {
  296. SetBattery(identifier, Common::Input::BatteryLevel::Charging);
  297. return;
  298. }
  299. Common::Input::BatteryLevel battery{};
  300. switch (value.status) {
  301. case 0:
  302. battery = Common::Input::BatteryLevel::Empty;
  303. break;
  304. case 1:
  305. battery = Common::Input::BatteryLevel::Critical;
  306. break;
  307. case 2:
  308. battery = Common::Input::BatteryLevel::Low;
  309. break;
  310. case 3:
  311. battery = Common::Input::BatteryLevel::Medium;
  312. break;
  313. case 4:
  314. default:
  315. battery = Common::Input::BatteryLevel::Full;
  316. break;
  317. }
  318. SetBattery(identifier, battery);
  319. }
  320. void Joycons::OnColorUpdate(std::size_t port, Joycon::ControllerType type,
  321. const Joycon::Color& value) {
  322. const auto identifier = GetIdentifier(port, type);
  323. Common::Input::BodyColorStatus color{
  324. .body = value.body,
  325. .buttons = value.buttons,
  326. .left_grip = value.left_grip,
  327. .right_grip = value.right_grip,
  328. };
  329. SetColor(identifier, color);
  330. }
  331. void Joycons::OnButtonUpdate(std::size_t port, Joycon::ControllerType type, int id, bool value) {
  332. const auto identifier = GetIdentifier(port, type);
  333. SetButton(identifier, id, value);
  334. }
  335. void Joycons::OnStickUpdate(std::size_t port, Joycon::ControllerType type, int id, f32 value) {
  336. const auto identifier = GetIdentifier(port, type);
  337. SetAxis(identifier, id, value);
  338. }
  339. void Joycons::OnMotionUpdate(std::size_t port, Joycon::ControllerType type, int id,
  340. const Joycon::MotionData& value) {
  341. const auto identifier = GetIdentifier(port, type);
  342. BasicMotion motion_data{
  343. .gyro_x = value.gyro_x,
  344. .gyro_y = value.gyro_y,
  345. .gyro_z = value.gyro_z,
  346. .accel_x = value.accel_x,
  347. .accel_y = value.accel_y,
  348. .accel_z = value.accel_z,
  349. .delta_timestamp = 15000,
  350. };
  351. SetMotion(identifier, id, motion_data);
  352. }
  353. void Joycons::OnRingConUpdate(f32 ring_data) {
  354. // To simplify ring detection it will always be mapped to an empty identifier for all
  355. // controllers
  356. static constexpr PadIdentifier identifier = {
  357. .guid = Common::UUID{},
  358. .port = 0,
  359. .pad = 0,
  360. };
  361. SetAxis(identifier, 100, ring_data);
  362. }
  363. void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type,
  364. const std::vector<u8>& amiibo_data) {
  365. const auto identifier = GetIdentifier(port, type);
  366. const auto nfc_state = amiibo_data.empty() ? Common::Input::NfcState::AmiiboRemoved
  367. : Common::Input::NfcState::NewAmiibo;
  368. SetNfc(identifier, {nfc_state, amiibo_data});
  369. }
  370. void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data,
  371. Joycon::IrsResolution format) {
  372. const auto identifier = GetIdentifier(port, Joycon::ControllerType::Right);
  373. SetCamera(identifier, {static_cast<Common::Input::CameraFormat>(format), camera_data});
  374. }
  375. std::shared_ptr<Joycon::JoyconDriver> Joycons::GetHandle(PadIdentifier identifier) const {
  376. auto is_handle_active = [&](std::shared_ptr<Joycon::JoyconDriver> device) {
  377. if (!device) {
  378. return false;
  379. }
  380. if (!device->IsConnected()) {
  381. return false;
  382. }
  383. if (device->GetDevicePort() == identifier.port) {
  384. return true;
  385. }
  386. return false;
  387. };
  388. const auto type = static_cast<Joycon::ControllerType>(identifier.pad);
  389. if (type == Joycon::ControllerType::Left) {
  390. const auto matching_device = std::ranges::find_if(
  391. left_joycons, [is_handle_active](auto& device) { return is_handle_active(device); });
  392. if (matching_device != left_joycons.end()) {
  393. return *matching_device;
  394. }
  395. }
  396. if (type == Joycon::ControllerType::Right) {
  397. const auto matching_device = std::ranges::find_if(
  398. right_joycons, [is_handle_active](auto& device) { return is_handle_active(device); });
  399. if (matching_device != right_joycons.end()) {
  400. return *matching_device;
  401. }
  402. }
  403. if (type == Joycon::ControllerType::Pro) {
  404. const auto matching_device = std::ranges::find_if(
  405. pro_controller, [is_handle_active](auto& device) { return is_handle_active(device); });
  406. if (matching_device != pro_controller.end()) {
  407. return *matching_device;
  408. }
  409. }
  410. return nullptr;
  411. }
  412. PadIdentifier Joycons::GetIdentifier(std::size_t port, Joycon::ControllerType type) const {
  413. const std::array<u8, 16> guid{0, 0, 0, 0, 0, 0, 0, 0,
  414. 0, 0, 0, 0, 0, 0, 0, static_cast<u8>(type)};
  415. return {
  416. .guid = Common::UUID{guid},
  417. .port = port,
  418. .pad = static_cast<std::size_t>(type),
  419. };
  420. }
  421. Common::ParamPackage Joycons::GetParamPackage(std::size_t port, Joycon::ControllerType type) const {
  422. const auto identifier = GetIdentifier(port, type);
  423. return {
  424. {"engine", GetEngineName()},
  425. {"guid", identifier.guid.RawString()},
  426. {"port", std::to_string(identifier.port)},
  427. {"pad", std::to_string(identifier.pad)},
  428. };
  429. }
  430. std::vector<Common::ParamPackage> Joycons::GetInputDevices() const {
  431. std::vector<Common::ParamPackage> devices{};
  432. auto add_entry = [&](std::shared_ptr<Joycon::JoyconDriver> device) {
  433. if (!device) {
  434. return;
  435. }
  436. if (!device->IsConnected()) {
  437. return;
  438. }
  439. auto param = GetParamPackage(device->GetDevicePort(), device->GetHandleDeviceType());
  440. std::string name = fmt::format("{} {}", JoyconName(device->GetHandleDeviceType()),
  441. device->GetDevicePort() + 1);
  442. param.Set("display", std::move(name));
  443. devices.emplace_back(param);
  444. };
  445. for (const auto& controller : left_joycons) {
  446. add_entry(controller);
  447. }
  448. for (const auto& controller : right_joycons) {
  449. add_entry(controller);
  450. }
  451. for (const auto& controller : pro_controller) {
  452. add_entry(controller);
  453. }
  454. // List dual joycon pairs
  455. for (std::size_t i = 0; i < MaxSupportedControllers; i++) {
  456. if (!left_joycons[i] || !right_joycons[i]) {
  457. continue;
  458. }
  459. if (!left_joycons[i]->IsConnected() || !right_joycons[i]->IsConnected()) {
  460. continue;
  461. }
  462. auto main_param = GetParamPackage(i, left_joycons[i]->GetHandleDeviceType());
  463. const auto second_param = GetParamPackage(i, right_joycons[i]->GetHandleDeviceType());
  464. const auto type = Joycon::ControllerType::Dual;
  465. std::string name = fmt::format("{} {}", JoyconName(type), i + 1);
  466. main_param.Set("display", std::move(name));
  467. main_param.Set("guid2", second_param.Get("guid", ""));
  468. main_param.Set("pad", std::to_string(static_cast<size_t>(type)));
  469. devices.emplace_back(main_param);
  470. }
  471. return devices;
  472. }
  473. ButtonMapping Joycons::GetButtonMappingForDevice(const Common::ParamPackage& params) {
  474. static constexpr std::array<std::tuple<Settings::NativeButton::Values, Joycon::PadButton, bool>,
  475. 18>
  476. switch_to_joycon_button = {
  477. std::tuple{Settings::NativeButton::A, Joycon::PadButton::A, true},
  478. {Settings::NativeButton::B, Joycon::PadButton::B, true},
  479. {Settings::NativeButton::X, Joycon::PadButton::X, true},
  480. {Settings::NativeButton::Y, Joycon::PadButton::Y, true},
  481. {Settings::NativeButton::DLeft, Joycon::PadButton::Left, false},
  482. {Settings::NativeButton::DUp, Joycon::PadButton::Up, false},
  483. {Settings::NativeButton::DRight, Joycon::PadButton::Right, false},
  484. {Settings::NativeButton::DDown, Joycon::PadButton::Down, false},
  485. {Settings::NativeButton::L, Joycon::PadButton::L, false},
  486. {Settings::NativeButton::R, Joycon::PadButton::R, true},
  487. {Settings::NativeButton::ZL, Joycon::PadButton::ZL, false},
  488. {Settings::NativeButton::ZR, Joycon::PadButton::ZR, true},
  489. {Settings::NativeButton::Plus, Joycon::PadButton::Plus, true},
  490. {Settings::NativeButton::Minus, Joycon::PadButton::Minus, false},
  491. {Settings::NativeButton::Home, Joycon::PadButton::Home, true},
  492. {Settings::NativeButton::Screenshot, Joycon::PadButton::Capture, false},
  493. {Settings::NativeButton::LStick, Joycon::PadButton::StickL, false},
  494. {Settings::NativeButton::RStick, Joycon::PadButton::StickR, true},
  495. };
  496. if (!params.Has("port")) {
  497. return {};
  498. }
  499. ButtonMapping mapping{};
  500. for (const auto& [switch_button, joycon_button, side] : switch_to_joycon_button) {
  501. const std::size_t port = static_cast<std::size_t>(params.Get("port", 0));
  502. auto pad = static_cast<Joycon::ControllerType>(params.Get("pad", 0));
  503. if (pad == Joycon::ControllerType::Dual) {
  504. pad = side ? Joycon::ControllerType::Right : Joycon::ControllerType::Left;
  505. }
  506. Common::ParamPackage button_params = GetParamPackage(port, pad);
  507. button_params.Set("button", static_cast<int>(joycon_button));
  508. mapping.insert_or_assign(switch_button, std::move(button_params));
  509. }
  510. // Map SL and SR buttons for left joycons
  511. if (params.Get("pad", 0) == static_cast<int>(Joycon::ControllerType::Left)) {
  512. const std::size_t port = static_cast<std::size_t>(params.Get("port", 0));
  513. Common::ParamPackage button_params = GetParamPackage(port, Joycon::ControllerType::Left);
  514. Common::ParamPackage sl_button_params = button_params;
  515. Common::ParamPackage sr_button_params = button_params;
  516. sl_button_params.Set("button", static_cast<int>(Joycon::PadButton::LeftSL));
  517. sr_button_params.Set("button", static_cast<int>(Joycon::PadButton::LeftSR));
  518. mapping.insert_or_assign(Settings::NativeButton::SL, std::move(sl_button_params));
  519. mapping.insert_or_assign(Settings::NativeButton::SR, std::move(sr_button_params));
  520. }
  521. // Map SL and SR buttons for right joycons
  522. if (params.Get("pad", 0) == static_cast<int>(Joycon::ControllerType::Right)) {
  523. const std::size_t port = static_cast<std::size_t>(params.Get("port", 0));
  524. Common::ParamPackage button_params = GetParamPackage(port, Joycon::ControllerType::Right);
  525. Common::ParamPackage sl_button_params = button_params;
  526. Common::ParamPackage sr_button_params = button_params;
  527. sl_button_params.Set("button", static_cast<int>(Joycon::PadButton::RightSL));
  528. sr_button_params.Set("button", static_cast<int>(Joycon::PadButton::RightSR));
  529. mapping.insert_or_assign(Settings::NativeButton::SL, std::move(sl_button_params));
  530. mapping.insert_or_assign(Settings::NativeButton::SR, std::move(sr_button_params));
  531. }
  532. return mapping;
  533. }
  534. AnalogMapping Joycons::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
  535. if (!params.Has("port")) {
  536. return {};
  537. }
  538. const std::size_t port = static_cast<std::size_t>(params.Get("port", 0));
  539. auto pad_left = static_cast<Joycon::ControllerType>(params.Get("pad", 0));
  540. auto pad_right = pad_left;
  541. if (pad_left == Joycon::ControllerType::Dual) {
  542. pad_left = Joycon::ControllerType::Left;
  543. pad_right = Joycon::ControllerType::Right;
  544. }
  545. AnalogMapping mapping = {};
  546. Common::ParamPackage left_analog_params = GetParamPackage(port, pad_left);
  547. left_analog_params.Set("axis_x", static_cast<int>(Joycon::PadAxes::LeftStickX));
  548. left_analog_params.Set("axis_y", static_cast<int>(Joycon::PadAxes::LeftStickY));
  549. mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params));
  550. Common::ParamPackage right_analog_params = GetParamPackage(port, pad_right);
  551. right_analog_params.Set("axis_x", static_cast<int>(Joycon::PadAxes::RightStickX));
  552. right_analog_params.Set("axis_y", static_cast<int>(Joycon::PadAxes::RightStickY));
  553. mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params));
  554. return mapping;
  555. }
  556. MotionMapping Joycons::GetMotionMappingForDevice(const Common::ParamPackage& params) {
  557. if (!params.Has("port")) {
  558. return {};
  559. }
  560. const std::size_t port = static_cast<std::size_t>(params.Get("port", 0));
  561. auto pad_left = static_cast<Joycon::ControllerType>(params.Get("pad", 0));
  562. auto pad_right = pad_left;
  563. if (pad_left == Joycon::ControllerType::Dual) {
  564. pad_left = Joycon::ControllerType::Left;
  565. pad_right = Joycon::ControllerType::Right;
  566. }
  567. MotionMapping mapping = {};
  568. Common::ParamPackage left_motion_params = GetParamPackage(port, pad_left);
  569. left_motion_params.Set("motion", 0);
  570. mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, std::move(left_motion_params));
  571. Common::ParamPackage right_Motion_params = GetParamPackage(port, pad_right);
  572. right_Motion_params.Set("motion", 1);
  573. mapping.insert_or_assign(Settings::NativeMotion::MotionRight, std::move(right_Motion_params));
  574. return mapping;
  575. }
  576. Common::Input::ButtonNames Joycons::GetUIButtonName(const Common::ParamPackage& params) const {
  577. const auto button = static_cast<Joycon::PadButton>(params.Get("button", 0));
  578. switch (button) {
  579. case Joycon::PadButton::Left:
  580. return Common::Input::ButtonNames::ButtonLeft;
  581. case Joycon::PadButton::Right:
  582. return Common::Input::ButtonNames::ButtonRight;
  583. case Joycon::PadButton::Down:
  584. return Common::Input::ButtonNames::ButtonDown;
  585. case Joycon::PadButton::Up:
  586. return Common::Input::ButtonNames::ButtonUp;
  587. case Joycon::PadButton::LeftSL:
  588. case Joycon::PadButton::RightSL:
  589. return Common::Input::ButtonNames::TriggerSL;
  590. case Joycon::PadButton::LeftSR:
  591. case Joycon::PadButton::RightSR:
  592. return Common::Input::ButtonNames::TriggerSR;
  593. case Joycon::PadButton::L:
  594. return Common::Input::ButtonNames::TriggerL;
  595. case Joycon::PadButton::R:
  596. return Common::Input::ButtonNames::TriggerR;
  597. case Joycon::PadButton::ZL:
  598. return Common::Input::ButtonNames::TriggerZL;
  599. case Joycon::PadButton::ZR:
  600. return Common::Input::ButtonNames::TriggerZR;
  601. case Joycon::PadButton::A:
  602. return Common::Input::ButtonNames::ButtonA;
  603. case Joycon::PadButton::B:
  604. return Common::Input::ButtonNames::ButtonB;
  605. case Joycon::PadButton::X:
  606. return Common::Input::ButtonNames::ButtonX;
  607. case Joycon::PadButton::Y:
  608. return Common::Input::ButtonNames::ButtonY;
  609. case Joycon::PadButton::Plus:
  610. return Common::Input::ButtonNames::ButtonPlus;
  611. case Joycon::PadButton::Minus:
  612. return Common::Input::ButtonNames::ButtonMinus;
  613. case Joycon::PadButton::Home:
  614. return Common::Input::ButtonNames::ButtonHome;
  615. case Joycon::PadButton::Capture:
  616. return Common::Input::ButtonNames::ButtonCapture;
  617. case Joycon::PadButton::StickL:
  618. return Common::Input::ButtonNames::ButtonStickL;
  619. case Joycon::PadButton::StickR:
  620. return Common::Input::ButtonNames::ButtonStickR;
  621. default:
  622. return Common::Input::ButtonNames::Undefined;
  623. }
  624. }
  625. Common::Input::ButtonNames Joycons::GetUIName(const Common::ParamPackage& params) const {
  626. if (params.Has("button")) {
  627. return GetUIButtonName(params);
  628. }
  629. if (params.Has("axis")) {
  630. return Common::Input::ButtonNames::Value;
  631. }
  632. if (params.Has("motion")) {
  633. return Common::Input::ButtonNames::Engine;
  634. }
  635. return Common::Input::ButtonNames::Invalid;
  636. }
  637. std::string Joycons::JoyconName(Joycon::ControllerType type) const {
  638. switch (type) {
  639. case Joycon::ControllerType::Left:
  640. return "Left Joycon";
  641. case Joycon::ControllerType::Right:
  642. return "Right Joycon";
  643. case Joycon::ControllerType::Pro:
  644. return "Pro Controller";
  645. case Joycon::ControllerType::Dual:
  646. return "Dual Joycon";
  647. default:
  648. return "Unknown Switch Controller";
  649. }
  650. }
  651. } // namespace InputCommon