npad.cpp 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <array>
  6. #include <cstring>
  7. #include "common/assert.h"
  8. #include "common/bit_field.h"
  9. #include "common/common_types.h"
  10. #include "common/logging/log.h"
  11. #include "core/core.h"
  12. #include "core/core_timing.h"
  13. #include "core/frontend/input.h"
  14. #include "core/hle/kernel/kernel.h"
  15. #include "core/hle/kernel/readable_event.h"
  16. #include "core/hle/kernel/writable_event.h"
  17. #include "core/hle/service/hid/controllers/npad.h"
  18. #include "core/settings.h"
  19. namespace Service::HID {
  20. constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
  21. [[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
  22. constexpr std::size_t NPAD_OFFSET = 0x9A00;
  23. constexpr u32 BATTERY_FULL = 2;
  24. constexpr u32 MAX_NPAD_ID = 7;
  25. constexpr std::size_t HANDHELD_INDEX = 8;
  26. constexpr std::array<u32, 10> npad_id_list{
  27. 0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN,
  28. };
  29. enum class JoystickId : std::size_t {
  30. Joystick_Left,
  31. Joystick_Right,
  32. };
  33. Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad(
  34. Settings::ControllerType type) {
  35. switch (type) {
  36. case Settings::ControllerType::ProController:
  37. return NPadControllerType::ProController;
  38. case Settings::ControllerType::DualJoyconDetached:
  39. return NPadControllerType::JoyDual;
  40. case Settings::ControllerType::LeftJoycon:
  41. return NPadControllerType::JoyLeft;
  42. case Settings::ControllerType::RightJoycon:
  43. return NPadControllerType::JoyRight;
  44. case Settings::ControllerType::Handheld:
  45. return NPadControllerType::Handheld;
  46. default:
  47. UNREACHABLE();
  48. return NPadControllerType::ProController;
  49. }
  50. }
  51. Settings::ControllerType Controller_NPad::MapNPadToSettingsType(
  52. Controller_NPad::NPadControllerType type) {
  53. switch (type) {
  54. case NPadControllerType::ProController:
  55. return Settings::ControllerType::ProController;
  56. case NPadControllerType::JoyDual:
  57. return Settings::ControllerType::DualJoyconDetached;
  58. case NPadControllerType::JoyLeft:
  59. return Settings::ControllerType::LeftJoycon;
  60. case NPadControllerType::JoyRight:
  61. return Settings::ControllerType::RightJoycon;
  62. case NPadControllerType::Handheld:
  63. return Settings::ControllerType::Handheld;
  64. default:
  65. UNREACHABLE();
  66. return Settings::ControllerType::ProController;
  67. }
  68. }
  69. std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) {
  70. switch (npad_id) {
  71. case 0:
  72. case 1:
  73. case 2:
  74. case 3:
  75. case 4:
  76. case 5:
  77. case 6:
  78. case 7:
  79. return npad_id;
  80. case HANDHELD_INDEX:
  81. case NPAD_HANDHELD:
  82. return HANDHELD_INDEX;
  83. case 9:
  84. case NPAD_UNKNOWN:
  85. return 9;
  86. default:
  87. UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id);
  88. return 0;
  89. }
  90. }
  91. u32 Controller_NPad::IndexToNPad(std::size_t index) {
  92. switch (index) {
  93. case 0:
  94. case 1:
  95. case 2:
  96. case 3:
  97. case 4:
  98. case 5:
  99. case 6:
  100. case 7:
  101. return static_cast<u32>(index);
  102. case HANDHELD_INDEX:
  103. return NPAD_HANDHELD;
  104. case 9:
  105. return NPAD_UNKNOWN;
  106. default:
  107. UNIMPLEMENTED_MSG("Unknown npad index {}", index);
  108. return 0;
  109. }
  110. }
  111. bool Controller_NPad::IsNpadIdValid(u32 npad_id) {
  112. switch (npad_id) {
  113. case 0:
  114. case 1:
  115. case 2:
  116. case 3:
  117. case 4:
  118. case 5:
  119. case 6:
  120. case 7:
  121. case NPAD_UNKNOWN:
  122. case NPAD_HANDHELD:
  123. return true;
  124. default:
  125. LOG_ERROR(Service_HID, "Invalid npad id {}", npad_id);
  126. return false;
  127. }
  128. }
  129. bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) {
  130. return IsNpadIdValid(device_handle.npad_id) &&
  131. device_handle.npad_type < NpadType::MaxNpadType &&
  132. device_handle.device_index < DeviceIndex::MaxDeviceIndex;
  133. }
  134. Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {
  135. latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE});
  136. }
  137. Controller_NPad::~Controller_NPad() {
  138. OnRelease();
  139. }
  140. void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
  141. const auto controller_type = connected_controllers[controller_idx].type;
  142. auto& controller = shared_memory_entries[controller_idx];
  143. if (controller_type == NPadControllerType::None) {
  144. styleset_changed_events[controller_idx].writable->Signal();
  145. return;
  146. }
  147. controller.style_set.raw = 0; // Zero out
  148. controller.device_type.raw = 0;
  149. controller.system_properties.raw = 0;
  150. switch (controller_type) {
  151. case NPadControllerType::None:
  152. UNREACHABLE();
  153. break;
  154. case NPadControllerType::ProController:
  155. controller.style_set.fullkey.Assign(1);
  156. controller.device_type.fullkey.Assign(1);
  157. controller.system_properties.is_vertical.Assign(1);
  158. controller.system_properties.use_plus.Assign(1);
  159. controller.system_properties.use_minus.Assign(1);
  160. controller.assignment_mode = NpadAssignments::Single;
  161. break;
  162. case NPadControllerType::Handheld:
  163. controller.style_set.handheld.Assign(1);
  164. controller.device_type.handheld_left.Assign(1);
  165. controller.device_type.handheld_right.Assign(1);
  166. controller.system_properties.is_vertical.Assign(1);
  167. controller.system_properties.use_plus.Assign(1);
  168. controller.system_properties.use_minus.Assign(1);
  169. controller.assignment_mode = NpadAssignments::Dual;
  170. break;
  171. case NPadControllerType::JoyDual:
  172. controller.style_set.joycon_dual.Assign(1);
  173. controller.device_type.joycon_left.Assign(1);
  174. controller.device_type.joycon_right.Assign(1);
  175. controller.system_properties.is_vertical.Assign(1);
  176. controller.system_properties.use_plus.Assign(1);
  177. controller.system_properties.use_minus.Assign(1);
  178. controller.assignment_mode = NpadAssignments::Dual;
  179. break;
  180. case NPadControllerType::JoyLeft:
  181. controller.style_set.joycon_left.Assign(1);
  182. controller.device_type.joycon_left.Assign(1);
  183. controller.system_properties.is_horizontal.Assign(1);
  184. controller.system_properties.use_minus.Assign(1);
  185. controller.assignment_mode = NpadAssignments::Single;
  186. break;
  187. case NPadControllerType::JoyRight:
  188. controller.style_set.joycon_right.Assign(1);
  189. controller.device_type.joycon_right.Assign(1);
  190. controller.system_properties.is_horizontal.Assign(1);
  191. controller.system_properties.use_plus.Assign(1);
  192. controller.assignment_mode = NpadAssignments::Single;
  193. break;
  194. case NPadControllerType::Pokeball:
  195. controller.style_set.palma.Assign(1);
  196. controller.device_type.palma.Assign(1);
  197. controller.assignment_mode = NpadAssignments::Single;
  198. break;
  199. }
  200. controller.fullkey_color.attribute = ColorAttributes::Ok;
  201. controller.fullkey_color.fullkey.body = 0;
  202. controller.fullkey_color.fullkey.button = 0;
  203. controller.joycon_color.attribute = ColorAttributes::Ok;
  204. controller.joycon_color.left.body =
  205. Settings::values.players.GetValue()[controller_idx].body_color_left;
  206. controller.joycon_color.left.button =
  207. Settings::values.players.GetValue()[controller_idx].button_color_left;
  208. controller.joycon_color.right.body =
  209. Settings::values.players.GetValue()[controller_idx].body_color_right;
  210. controller.joycon_color.right.button =
  211. Settings::values.players.GetValue()[controller_idx].button_color_right;
  212. controller.battery_level_dual = BATTERY_FULL;
  213. controller.battery_level_left = BATTERY_FULL;
  214. controller.battery_level_right = BATTERY_FULL;
  215. SignalStyleSetChangedEvent(IndexToNPad(controller_idx));
  216. }
  217. void Controller_NPad::OnInit() {
  218. auto& kernel = system.Kernel();
  219. for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
  220. styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair(
  221. kernel, fmt::format("npad:NpadStyleSetChanged_{}", i));
  222. }
  223. if (!IsControllerActivated()) {
  224. return;
  225. }
  226. OnLoadInputDevices();
  227. if (style.raw == 0) {
  228. // We want to support all controllers
  229. style.handheld.Assign(1);
  230. style.joycon_left.Assign(1);
  231. style.joycon_right.Assign(1);
  232. style.joycon_dual.Assign(1);
  233. style.fullkey.Assign(1);
  234. style.palma.Assign(1);
  235. }
  236. std::transform(Settings::values.players.GetValue().begin(),
  237. Settings::values.players.GetValue().end(), connected_controllers.begin(),
  238. [](const Settings::PlayerInput& player) {
  239. return ControllerHolder{MapSettingsTypeToNPad(player.controller_type),
  240. player.connected};
  241. });
  242. // Connect the Player 1 or Handheld controller if none are connected.
  243. if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
  244. [](const ControllerHolder& controller) { return controller.is_connected; })) {
  245. const auto controller =
  246. MapSettingsTypeToNPad(Settings::values.players.GetValue()[0].controller_type);
  247. if (controller == NPadControllerType::Handheld) {
  248. Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true;
  249. connected_controllers[HANDHELD_INDEX] = {controller, true};
  250. } else {
  251. Settings::values.players.GetValue()[0].connected = true;
  252. connected_controllers[0] = {controller, true};
  253. }
  254. }
  255. // Account for handheld
  256. if (connected_controllers[HANDHELD_INDEX].is_connected) {
  257. connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld;
  258. }
  259. supported_npad_id_types.resize(npad_id_list.size());
  260. std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
  261. npad_id_list.size() * sizeof(u32));
  262. for (std::size_t i = 0; i < connected_controllers.size(); ++i) {
  263. const auto& controller = connected_controllers[i];
  264. if (controller.is_connected) {
  265. AddNewControllerAt(controller.type, i);
  266. }
  267. }
  268. }
  269. void Controller_NPad::OnLoadInputDevices() {
  270. const auto& players = Settings::values.players.GetValue();
  271. for (std::size_t i = 0; i < players.size(); ++i) {
  272. std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
  273. players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
  274. buttons[i].begin(), Input::CreateDevice<Input::ButtonDevice>);
  275. std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
  276. players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
  277. sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>);
  278. std::transform(players[i].vibrations.begin() +
  279. Settings::NativeVibration::VIBRATION_HID_BEGIN,
  280. players[i].vibrations.begin() + Settings::NativeVibration::VIBRATION_HID_END,
  281. vibrations[i].begin(), Input::CreateDevice<Input::VibrationDevice>);
  282. std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
  283. players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END,
  284. motions[i].begin(), Input::CreateDevice<Input::MotionDevice>);
  285. for (std::size_t device_idx = 0; device_idx < vibrations[i].size(); ++device_idx) {
  286. InitializeVibrationDeviceAtIndex(i, device_idx);
  287. }
  288. }
  289. }
  290. void Controller_NPad::OnRelease() {
  291. for (std::size_t npad_idx = 0; npad_idx < vibrations.size(); ++npad_idx) {
  292. for (std::size_t device_idx = 0; device_idx < vibrations[npad_idx].size(); ++device_idx) {
  293. VibrateControllerAtIndex(npad_idx, device_idx, {});
  294. }
  295. }
  296. }
  297. void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
  298. const auto controller_idx = NPadIdToIndex(npad_id);
  299. const auto controller_type = connected_controllers[controller_idx].type;
  300. if (!connected_controllers[controller_idx].is_connected) {
  301. return;
  302. }
  303. auto& pad_state = npad_pad_states[controller_idx].pad_states;
  304. auto& lstick_entry = npad_pad_states[controller_idx].l_stick;
  305. auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
  306. const auto& button_state = buttons[controller_idx];
  307. const auto& analog_state = sticks[controller_idx];
  308. const auto [stick_l_x_f, stick_l_y_f] =
  309. analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
  310. const auto [stick_r_x_f, stick_r_y_f] =
  311. analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
  312. using namespace Settings::NativeButton;
  313. if (controller_type != NPadControllerType::JoyLeft) {
  314. pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
  315. pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus());
  316. pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus());
  317. pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus());
  318. pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus());
  319. pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
  320. pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
  321. pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus());
  322. pad_state.r_stick_right.Assign(
  323. analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
  324. ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
  325. pad_state.r_stick_left.Assign(
  326. analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
  327. ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
  328. pad_state.r_stick_up.Assign(
  329. analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
  330. ->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
  331. pad_state.r_stick_down.Assign(
  332. analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
  333. ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
  334. rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
  335. rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
  336. }
  337. if (controller_type != NPadControllerType::JoyRight) {
  338. pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus());
  339. pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus());
  340. pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
  341. pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
  342. pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus());
  343. pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus());
  344. pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
  345. pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus());
  346. pad_state.l_stick_right.Assign(
  347. analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
  348. ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
  349. pad_state.l_stick_left.Assign(
  350. analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
  351. ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
  352. pad_state.l_stick_up.Assign(
  353. analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
  354. ->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
  355. pad_state.l_stick_down.Assign(
  356. analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
  357. ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
  358. lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
  359. lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
  360. }
  361. if (controller_type == NPadControllerType::JoyLeft ||
  362. controller_type == NPadControllerType::JoyRight) {
  363. pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
  364. pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
  365. }
  366. }
  367. void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
  368. std::size_t data_len) {
  369. if (!IsControllerActivated()) {
  370. return;
  371. }
  372. for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {
  373. auto& npad = shared_memory_entries[i];
  374. const std::array<NPadGeneric*, 7> controller_npads{
  375. &npad.fullkey_states, &npad.handheld_states, &npad.joy_dual_states,
  376. &npad.joy_left_states, &npad.joy_right_states, &npad.palma_states,
  377. &npad.system_ext_states};
  378. for (auto* main_controller : controller_npads) {
  379. main_controller->common.entry_count = 16;
  380. main_controller->common.total_entry_count = 17;
  381. const auto& last_entry =
  382. main_controller->npad[main_controller->common.last_entry_index];
  383. main_controller->common.timestamp = core_timing.GetCPUTicks();
  384. main_controller->common.last_entry_index =
  385. (main_controller->common.last_entry_index + 1) % 17;
  386. auto& cur_entry = main_controller->npad[main_controller->common.last_entry_index];
  387. cur_entry.timestamp = last_entry.timestamp + 1;
  388. cur_entry.timestamp2 = cur_entry.timestamp;
  389. }
  390. const auto& controller_type = connected_controllers[i].type;
  391. if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
  392. continue;
  393. }
  394. const u32 npad_index = static_cast<u32>(i);
  395. RequestPadStateUpdate(npad_index);
  396. auto& pad_state = npad_pad_states[npad_index];
  397. auto& main_controller =
  398. npad.fullkey_states.npad[npad.fullkey_states.common.last_entry_index];
  399. auto& handheld_entry =
  400. npad.handheld_states.npad[npad.handheld_states.common.last_entry_index];
  401. auto& dual_entry = npad.joy_dual_states.npad[npad.joy_dual_states.common.last_entry_index];
  402. auto& left_entry = npad.joy_left_states.npad[npad.joy_left_states.common.last_entry_index];
  403. auto& right_entry =
  404. npad.joy_right_states.npad[npad.joy_right_states.common.last_entry_index];
  405. auto& pokeball_entry = npad.palma_states.npad[npad.palma_states.common.last_entry_index];
  406. auto& libnx_entry =
  407. npad.system_ext_states.npad[npad.system_ext_states.common.last_entry_index];
  408. libnx_entry.connection_status.raw = 0;
  409. libnx_entry.connection_status.IsConnected.Assign(1);
  410. switch (controller_type) {
  411. case NPadControllerType::None:
  412. UNREACHABLE();
  413. break;
  414. case NPadControllerType::ProController:
  415. main_controller.connection_status.raw = 0;
  416. main_controller.connection_status.IsConnected.Assign(1);
  417. main_controller.connection_status.IsWired.Assign(1);
  418. main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
  419. main_controller.pad.l_stick = pad_state.l_stick;
  420. main_controller.pad.r_stick = pad_state.r_stick;
  421. libnx_entry.connection_status.IsWired.Assign(1);
  422. break;
  423. case NPadControllerType::Handheld:
  424. handheld_entry.connection_status.raw = 0;
  425. handheld_entry.connection_status.IsConnected.Assign(1);
  426. handheld_entry.connection_status.IsWired.Assign(1);
  427. handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
  428. handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
  429. handheld_entry.connection_status.IsLeftJoyWired.Assign(1);
  430. handheld_entry.connection_status.IsRightJoyWired.Assign(1);
  431. handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
  432. handheld_entry.pad.l_stick = pad_state.l_stick;
  433. handheld_entry.pad.r_stick = pad_state.r_stick;
  434. libnx_entry.connection_status.IsWired.Assign(1);
  435. libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
  436. libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
  437. libnx_entry.connection_status.IsLeftJoyWired.Assign(1);
  438. libnx_entry.connection_status.IsRightJoyWired.Assign(1);
  439. break;
  440. case NPadControllerType::JoyDual:
  441. dual_entry.connection_status.raw = 0;
  442. dual_entry.connection_status.IsConnected.Assign(1);
  443. dual_entry.connection_status.IsLeftJoyConnected.Assign(1);
  444. dual_entry.connection_status.IsRightJoyConnected.Assign(1);
  445. dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
  446. dual_entry.pad.l_stick = pad_state.l_stick;
  447. dual_entry.pad.r_stick = pad_state.r_stick;
  448. libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
  449. libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
  450. break;
  451. case NPadControllerType::JoyLeft:
  452. left_entry.connection_status.raw = 0;
  453. left_entry.connection_status.IsConnected.Assign(1);
  454. left_entry.connection_status.IsLeftJoyConnected.Assign(1);
  455. left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
  456. left_entry.pad.l_stick = pad_state.l_stick;
  457. left_entry.pad.r_stick = pad_state.r_stick;
  458. libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
  459. break;
  460. case NPadControllerType::JoyRight:
  461. right_entry.connection_status.raw = 0;
  462. right_entry.connection_status.IsConnected.Assign(1);
  463. right_entry.connection_status.IsRightJoyConnected.Assign(1);
  464. right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
  465. right_entry.pad.l_stick = pad_state.l_stick;
  466. right_entry.pad.r_stick = pad_state.r_stick;
  467. libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
  468. break;
  469. case NPadControllerType::Pokeball:
  470. pokeball_entry.connection_status.raw = 0;
  471. pokeball_entry.connection_status.IsConnected.Assign(1);
  472. pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
  473. pokeball_entry.pad.l_stick = pad_state.l_stick;
  474. pokeball_entry.pad.r_stick = pad_state.r_stick;
  475. break;
  476. }
  477. // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
  478. // any controllers.
  479. libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
  480. libnx_entry.pad.l_stick = pad_state.l_stick;
  481. libnx_entry.pad.r_stick = pad_state.r_stick;
  482. press_state |= static_cast<u32>(pad_state.pad_states.raw);
  483. }
  484. std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
  485. shared_memory_entries.size() * sizeof(NPadEntry));
  486. }
  487. void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
  488. std::size_t data_len) {
  489. if (!IsControllerActivated()) {
  490. return;
  491. }
  492. for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {
  493. auto& npad = shared_memory_entries[i];
  494. const auto& controller_type = connected_controllers[i].type;
  495. if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
  496. continue;
  497. }
  498. const std::array<SixAxisGeneric*, 6> controller_sixaxes{
  499. &npad.sixaxis_fullkey, &npad.sixaxis_handheld, &npad.sixaxis_dual_left,
  500. &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right,
  501. };
  502. for (auto* sixaxis_sensor : controller_sixaxes) {
  503. sixaxis_sensor->common.entry_count = 16;
  504. sixaxis_sensor->common.total_entry_count = 17;
  505. const auto& last_entry =
  506. sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index];
  507. sixaxis_sensor->common.timestamp = core_timing.GetCPUTicks();
  508. sixaxis_sensor->common.last_entry_index =
  509. (sixaxis_sensor->common.last_entry_index + 1) % 17;
  510. auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index];
  511. cur_entry.timestamp = last_entry.timestamp + 1;
  512. cur_entry.timestamp2 = cur_entry.timestamp;
  513. }
  514. // Try to read sixaxis sensor states
  515. std::array<MotionDevice, 2> motion_devices;
  516. if (sixaxis_sensors_enabled && Settings::values.motion_enabled.GetValue()) {
  517. sixaxis_at_rest = true;
  518. for (std::size_t e = 0; e < motion_devices.size(); ++e) {
  519. const auto& device = motions[i][e];
  520. if (device) {
  521. std::tie(motion_devices[e].accel, motion_devices[e].gyro,
  522. motion_devices[e].rotation, motion_devices[e].orientation) =
  523. device->GetStatus();
  524. sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f;
  525. }
  526. }
  527. }
  528. auto& full_sixaxis_entry =
  529. npad.sixaxis_fullkey.sixaxis[npad.sixaxis_fullkey.common.last_entry_index];
  530. auto& handheld_sixaxis_entry =
  531. npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index];
  532. auto& dual_left_sixaxis_entry =
  533. npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index];
  534. auto& dual_right_sixaxis_entry =
  535. npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index];
  536. auto& left_sixaxis_entry =
  537. npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index];
  538. auto& right_sixaxis_entry =
  539. npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index];
  540. switch (controller_type) {
  541. case NPadControllerType::None:
  542. UNREACHABLE();
  543. break;
  544. case NPadControllerType::ProController:
  545. full_sixaxis_entry.attribute.raw = 0;
  546. if (sixaxis_sensors_enabled && motions[i][0]) {
  547. full_sixaxis_entry.attribute.IsConnected.Assign(1);
  548. full_sixaxis_entry.accel = motion_devices[0].accel;
  549. full_sixaxis_entry.gyro = motion_devices[0].gyro;
  550. full_sixaxis_entry.rotation = motion_devices[0].rotation;
  551. full_sixaxis_entry.orientation = motion_devices[0].orientation;
  552. }
  553. break;
  554. case NPadControllerType::Handheld:
  555. handheld_sixaxis_entry.attribute.raw = 0;
  556. if (sixaxis_sensors_enabled && motions[i][0]) {
  557. handheld_sixaxis_entry.attribute.IsConnected.Assign(1);
  558. handheld_sixaxis_entry.accel = motion_devices[0].accel;
  559. handheld_sixaxis_entry.gyro = motion_devices[0].gyro;
  560. handheld_sixaxis_entry.rotation = motion_devices[0].rotation;
  561. handheld_sixaxis_entry.orientation = motion_devices[0].orientation;
  562. }
  563. break;
  564. case NPadControllerType::JoyDual:
  565. dual_left_sixaxis_entry.attribute.raw = 0;
  566. dual_right_sixaxis_entry.attribute.raw = 0;
  567. if (sixaxis_sensors_enabled && motions[i][0]) {
  568. // Set motion for the left joycon
  569. dual_left_sixaxis_entry.attribute.IsConnected.Assign(1);
  570. dual_left_sixaxis_entry.accel = motion_devices[0].accel;
  571. dual_left_sixaxis_entry.gyro = motion_devices[0].gyro;
  572. dual_left_sixaxis_entry.rotation = motion_devices[0].rotation;
  573. dual_left_sixaxis_entry.orientation = motion_devices[0].orientation;
  574. }
  575. if (sixaxis_sensors_enabled && motions[i][1]) {
  576. // Set motion for the right joycon
  577. dual_right_sixaxis_entry.attribute.IsConnected.Assign(1);
  578. dual_right_sixaxis_entry.accel = motion_devices[1].accel;
  579. dual_right_sixaxis_entry.gyro = motion_devices[1].gyro;
  580. dual_right_sixaxis_entry.rotation = motion_devices[1].rotation;
  581. dual_right_sixaxis_entry.orientation = motion_devices[1].orientation;
  582. }
  583. break;
  584. case NPadControllerType::JoyLeft:
  585. left_sixaxis_entry.attribute.raw = 0;
  586. if (sixaxis_sensors_enabled && motions[i][0]) {
  587. left_sixaxis_entry.attribute.IsConnected.Assign(1);
  588. left_sixaxis_entry.accel = motion_devices[0].accel;
  589. left_sixaxis_entry.gyro = motion_devices[0].gyro;
  590. left_sixaxis_entry.rotation = motion_devices[0].rotation;
  591. left_sixaxis_entry.orientation = motion_devices[0].orientation;
  592. }
  593. break;
  594. case NPadControllerType::JoyRight:
  595. right_sixaxis_entry.attribute.raw = 0;
  596. if (sixaxis_sensors_enabled && motions[i][1]) {
  597. right_sixaxis_entry.attribute.IsConnected.Assign(1);
  598. right_sixaxis_entry.accel = motion_devices[1].accel;
  599. right_sixaxis_entry.gyro = motion_devices[1].gyro;
  600. right_sixaxis_entry.rotation = motion_devices[1].rotation;
  601. right_sixaxis_entry.orientation = motion_devices[1].orientation;
  602. }
  603. break;
  604. case NPadControllerType::Pokeball:
  605. break;
  606. }
  607. }
  608. std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
  609. shared_memory_entries.size() * sizeof(NPadEntry));
  610. }
  611. void Controller_NPad::SetSupportedStyleSet(NpadStyleSet style_set) {
  612. style.raw = style_set.raw;
  613. }
  614. Controller_NPad::NpadStyleSet Controller_NPad::GetSupportedStyleSet() const {
  615. return style;
  616. }
  617. void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) {
  618. ASSERT(length > 0 && (length % sizeof(u32)) == 0);
  619. supported_npad_id_types.clear();
  620. supported_npad_id_types.resize(length / sizeof(u32));
  621. std::memcpy(supported_npad_id_types.data(), data, length);
  622. }
  623. void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
  624. ASSERT(max_length < supported_npad_id_types.size());
  625. std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size());
  626. }
  627. std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const {
  628. return supported_npad_id_types.size();
  629. }
  630. void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
  631. hold_type = joy_hold_type;
  632. }
  633. Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
  634. return hold_type;
  635. }
  636. void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) {
  637. handheld_activation_mode = activation_mode;
  638. }
  639. Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActivationMode() const {
  640. return handheld_activation_mode;
  641. }
  642. void Controller_NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) {
  643. communication_mode = communication_mode_;
  644. }
  645. Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode() const {
  646. return communication_mode;
  647. }
  648. void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) {
  649. const std::size_t npad_index = NPadIdToIndex(npad_id);
  650. ASSERT(npad_index < shared_memory_entries.size());
  651. if (shared_memory_entries[npad_index].assignment_mode != assignment_mode) {
  652. shared_memory_entries[npad_index].assignment_mode = assignment_mode;
  653. }
  654. }
  655. bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index,
  656. const VibrationValue& vibration_value) {
  657. if (!connected_controllers[npad_index].is_connected || !vibrations[npad_index][device_index]) {
  658. return false;
  659. }
  660. const auto& player = Settings::values.players.GetValue()[npad_index];
  661. if (!player.vibration_enabled) {
  662. if (latest_vibration_values[npad_index][device_index].amp_low != 0.0f ||
  663. latest_vibration_values[npad_index][device_index].amp_high != 0.0f) {
  664. // Send an empty vibration to stop any vibrations.
  665. vibrations[npad_index][device_index]->SetRumblePlay(0.0f, 160.0f, 0.0f, 320.0f);
  666. // Then reset the vibration value to its default value.
  667. latest_vibration_values[npad_index][device_index] = DEFAULT_VIBRATION_VALUE;
  668. }
  669. return false;
  670. }
  671. if (!Settings::values.enable_accurate_vibrations.GetValue()) {
  672. using std::chrono::duration_cast;
  673. using std::chrono::milliseconds;
  674. using std::chrono::steady_clock;
  675. const auto now = steady_clock::now();
  676. // Filter out non-zero vibrations that are within 10ms of each other.
  677. if ((vibration_value.amp_low != 0.0f || vibration_value.amp_high != 0.0f) &&
  678. duration_cast<milliseconds>(now - last_vibration_timepoints[npad_index][device_index]) <
  679. milliseconds(10)) {
  680. return false;
  681. }
  682. last_vibration_timepoints[npad_index][device_index] = now;
  683. }
  684. auto& vibration = vibrations[npad_index][device_index];
  685. const auto player_vibration_strength = static_cast<f32>(player.vibration_strength);
  686. const auto amp_low =
  687. std::min(vibration_value.amp_low * player_vibration_strength / 100.0f, 1.0f);
  688. const auto amp_high =
  689. std::min(vibration_value.amp_high * player_vibration_strength / 100.0f, 1.0f);
  690. return vibration->SetRumblePlay(amp_low, vibration_value.freq_low, amp_high,
  691. vibration_value.freq_high);
  692. }
  693. void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle,
  694. const VibrationValue& vibration_value) {
  695. if (!IsDeviceHandleValid(vibration_device_handle)) {
  696. return;
  697. }
  698. if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
  699. return;
  700. }
  701. const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
  702. const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
  703. if (!vibration_devices_mounted[npad_index][device_index] ||
  704. !connected_controllers[npad_index].is_connected) {
  705. return;
  706. }
  707. if (vibration_device_handle.device_index == DeviceIndex::None) {
  708. UNREACHABLE_MSG("DeviceIndex should never be None!");
  709. return;
  710. }
  711. // Some games try to send mismatched parameters in the device handle, block these.
  712. if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft &&
  713. (vibration_device_handle.npad_type == NpadType::JoyconRight ||
  714. vibration_device_handle.device_index == DeviceIndex::Right)) ||
  715. (connected_controllers[npad_index].type == NPadControllerType::JoyRight &&
  716. (vibration_device_handle.npad_type == NpadType::JoyconLeft ||
  717. vibration_device_handle.device_index == DeviceIndex::Left))) {
  718. return;
  719. }
  720. // Filter out vibrations with equivalent values to reduce unnecessary state changes.
  721. if (vibration_value.amp_low == latest_vibration_values[npad_index][device_index].amp_low &&
  722. vibration_value.amp_high == latest_vibration_values[npad_index][device_index].amp_high) {
  723. return;
  724. }
  725. if (VibrateControllerAtIndex(npad_index, device_index, vibration_value)) {
  726. latest_vibration_values[npad_index][device_index] = vibration_value;
  727. }
  728. }
  729. void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
  730. const std::vector<VibrationValue>& vibration_values) {
  731. if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
  732. return;
  733. }
  734. ASSERT_OR_EXECUTE_MSG(
  735. vibration_device_handles.size() == vibration_values.size(), { return; },
  736. "The amount of device handles does not match with the amount of vibration values,"
  737. "this is undefined behavior!");
  738. for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) {
  739. VibrateController(vibration_device_handles[i], vibration_values[i]);
  740. }
  741. }
  742. Controller_NPad::VibrationValue Controller_NPad::GetLastVibration(
  743. const DeviceHandle& vibration_device_handle) const {
  744. if (!IsDeviceHandleValid(vibration_device_handle)) {
  745. return {};
  746. }
  747. const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
  748. const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
  749. return latest_vibration_values[npad_index][device_index];
  750. }
  751. void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) {
  752. if (!IsDeviceHandleValid(vibration_device_handle)) {
  753. return;
  754. }
  755. const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
  756. const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
  757. InitializeVibrationDeviceAtIndex(npad_index, device_index);
  758. }
  759. void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index,
  760. std::size_t device_index) {
  761. if (vibrations[npad_index][device_index]) {
  762. vibration_devices_mounted[npad_index][device_index] =
  763. vibrations[npad_index][device_index]->GetStatus() == 1;
  764. } else {
  765. vibration_devices_mounted[npad_index][device_index] = false;
  766. }
  767. }
  768. void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) {
  769. permit_vibration_session_enabled = permit_vibration_session;
  770. }
  771. bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const {
  772. if (!IsDeviceHandleValid(vibration_device_handle)) {
  773. return false;
  774. }
  775. const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
  776. const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
  777. return vibration_devices_mounted[npad_index][device_index];
  778. }
  779. std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
  780. const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
  781. return styleset_event.readable;
  782. }
  783. void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const {
  784. styleset_changed_events[NPadIdToIndex(npad_id)].writable->Signal();
  785. }
  786. void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) {
  787. UpdateControllerAt(controller, npad_index, true);
  788. }
  789. void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
  790. bool connected) {
  791. if (!connected) {
  792. DisconnectNpadAtIndex(npad_index);
  793. return;
  794. }
  795. if (controller == NPadControllerType::Handheld && npad_index == HANDHELD_INDEX) {
  796. Settings::values.players.GetValue()[HANDHELD_INDEX].controller_type =
  797. MapNPadToSettingsType(controller);
  798. Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true;
  799. connected_controllers[HANDHELD_INDEX] = {controller, true};
  800. InitNewlyAddedController(HANDHELD_INDEX);
  801. return;
  802. }
  803. Settings::values.players.GetValue()[npad_index].controller_type =
  804. MapNPadToSettingsType(controller);
  805. Settings::values.players.GetValue()[npad_index].connected = true;
  806. connected_controllers[npad_index] = {controller, true};
  807. InitNewlyAddedController(npad_index);
  808. }
  809. void Controller_NPad::DisconnectNpad(u32 npad_id) {
  810. DisconnectNpadAtIndex(NPadIdToIndex(npad_id));
  811. }
  812. void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) {
  813. for (std::size_t device_idx = 0; device_idx < vibrations[npad_index].size(); ++device_idx) {
  814. // Send an empty vibration to stop any vibrations.
  815. VibrateControllerAtIndex(npad_index, device_idx, {});
  816. vibration_devices_mounted[npad_index][device_idx] = false;
  817. }
  818. Settings::values.players.GetValue()[npad_index].connected = false;
  819. connected_controllers[npad_index].is_connected = false;
  820. auto& controller = shared_memory_entries[npad_index];
  821. controller.style_set.raw = 0; // Zero out
  822. controller.device_type.raw = 0;
  823. controller.system_properties.raw = 0;
  824. controller.button_properties.raw = 0;
  825. SignalStyleSetChangedEvent(IndexToNPad(npad_index));
  826. }
  827. void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
  828. gyroscope_zero_drift_mode = drift_mode;
  829. }
  830. Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMode() const {
  831. return gyroscope_zero_drift_mode;
  832. }
  833. bool Controller_NPad::IsSixAxisSensorAtRest() const {
  834. return sixaxis_at_rest;
  835. }
  836. void Controller_NPad::SetSixAxisEnabled(bool six_axis_status) {
  837. sixaxis_sensors_enabled = six_axis_status;
  838. }
  839. void Controller_NPad::SetSixAxisFusionParameters(f32 parameter1, f32 parameter2) {
  840. sixaxis_fusion_parameter1 = parameter1;
  841. sixaxis_fusion_parameter2 = parameter2;
  842. }
  843. std::pair<f32, f32> Controller_NPad::GetSixAxisFusionParameters() {
  844. return {
  845. sixaxis_fusion_parameter1,
  846. sixaxis_fusion_parameter2,
  847. };
  848. }
  849. void Controller_NPad::ResetSixAxisFusionParameters() {
  850. sixaxis_fusion_parameter1 = 0.0f;
  851. sixaxis_fusion_parameter2 = 0.0f;
  852. }
  853. void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) {
  854. const auto npad_index_1 = NPadIdToIndex(npad_id_1);
  855. const auto npad_index_2 = NPadIdToIndex(npad_id_2);
  856. // If the controllers at both npad indices form a pair of left and right joycons, merge them.
  857. // Otherwise, do nothing.
  858. if ((connected_controllers[npad_index_1].type == NPadControllerType::JoyLeft &&
  859. connected_controllers[npad_index_2].type == NPadControllerType::JoyRight) ||
  860. (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft &&
  861. connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) {
  862. // Disconnect the joycon at the second id and connect the dual joycon at the first index.
  863. DisconnectNpad(npad_id_2);
  864. AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1);
  865. }
  866. }
  867. void Controller_NPad::StartLRAssignmentMode() {
  868. // Nothing internally is used for lr assignment mode. Since we have the ability to set the
  869. // controller types from boot, it doesn't really matter about showing a selection screen
  870. is_in_lr_assignment_mode = true;
  871. }
  872. void Controller_NPad::StopLRAssignmentMode() {
  873. is_in_lr_assignment_mode = false;
  874. }
  875. bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) {
  876. if (npad_id_1 == NPAD_HANDHELD || npad_id_2 == NPAD_HANDHELD || npad_id_1 == NPAD_UNKNOWN ||
  877. npad_id_2 == NPAD_UNKNOWN) {
  878. return true;
  879. }
  880. const auto npad_index_1 = NPadIdToIndex(npad_id_1);
  881. const auto npad_index_2 = NPadIdToIndex(npad_id_2);
  882. if (!IsControllerSupported(connected_controllers[npad_index_1].type) ||
  883. !IsControllerSupported(connected_controllers[npad_index_2].type)) {
  884. return false;
  885. }
  886. std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type);
  887. AddNewControllerAt(connected_controllers[npad_index_1].type, npad_index_1);
  888. AddNewControllerAt(connected_controllers[npad_index_2].type, npad_index_2);
  889. return true;
  890. }
  891. Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
  892. if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) {
  893. // These are controllers without led patterns
  894. return LedPattern{0, 0, 0, 0};
  895. }
  896. switch (npad_id) {
  897. case 0:
  898. return LedPattern{1, 0, 0, 0};
  899. case 1:
  900. return LedPattern{1, 1, 0, 0};
  901. case 2:
  902. return LedPattern{1, 1, 1, 0};
  903. case 3:
  904. return LedPattern{1, 1, 1, 1};
  905. case 4:
  906. return LedPattern{1, 0, 0, 1};
  907. case 5:
  908. return LedPattern{1, 0, 1, 0};
  909. case 6:
  910. return LedPattern{1, 0, 1, 1};
  911. case 7:
  912. return LedPattern{0, 1, 1, 0};
  913. default:
  914. return LedPattern{0, 0, 0, 0};
  915. }
  916. }
  917. bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const {
  918. return unintended_home_button_input_protection[NPadIdToIndex(npad_id)];
  919. }
  920. void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
  921. u32 npad_id) {
  922. unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;
  923. }
  924. void Controller_NPad::ClearAllConnectedControllers() {
  925. for (auto& controller : connected_controllers) {
  926. if (controller.is_connected && controller.type != NPadControllerType::None) {
  927. controller.type = NPadControllerType::None;
  928. controller.is_connected = false;
  929. }
  930. }
  931. }
  932. void Controller_NPad::DisconnectAllConnectedControllers() {
  933. for (auto& controller : connected_controllers) {
  934. controller.is_connected = false;
  935. }
  936. }
  937. void Controller_NPad::ConnectAllDisconnectedControllers() {
  938. for (auto& controller : connected_controllers) {
  939. if (controller.type != NPadControllerType::None && !controller.is_connected) {
  940. controller.is_connected = true;
  941. }
  942. }
  943. }
  944. void Controller_NPad::ClearAllControllers() {
  945. for (auto& controller : connected_controllers) {
  946. controller.type = NPadControllerType::None;
  947. controller.is_connected = false;
  948. }
  949. }
  950. u32 Controller_NPad::GetAndResetPressState() {
  951. return press_state.exchange(0);
  952. }
  953. bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const {
  954. if (controller == NPadControllerType::Handheld) {
  955. const bool support_handheld =
  956. std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(),
  957. NPAD_HANDHELD) != supported_npad_id_types.end();
  958. // Handheld is not even a supported type, lets stop here
  959. if (!support_handheld) {
  960. return false;
  961. }
  962. // Handheld should not be supported in docked mode
  963. if (Settings::values.use_docked_mode.GetValue()) {
  964. return false;
  965. }
  966. return true;
  967. }
  968. if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(),
  969. [](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) {
  970. switch (controller) {
  971. case NPadControllerType::ProController:
  972. return style.fullkey;
  973. case NPadControllerType::JoyDual:
  974. return style.joycon_dual;
  975. case NPadControllerType::JoyLeft:
  976. return style.joycon_left;
  977. case NPadControllerType::JoyRight:
  978. return style.joycon_right;
  979. case NPadControllerType::Pokeball:
  980. return style.palma;
  981. default:
  982. return false;
  983. }
  984. }
  985. return false;
  986. }
  987. } // namespace Service::HID