npad.cpp 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include <array>
  5. #include <chrono>
  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 "common/settings.h"
  12. #include "core/core_timing.h"
  13. #include "core/hid/emulated_controller.h"
  14. #include "core/hid/hid_core.h"
  15. #include "core/hle/kernel/k_event.h"
  16. #include "core/hle/kernel/k_readable_event.h"
  17. #include "core/hle/kernel/k_writable_event.h"
  18. #include "core/hle/service/hid/controllers/npad.h"
  19. #include "core/hle/service/hid/errors.h"
  20. #include "core/hle/service/kernel_helpers.h"
  21. namespace Service::HID {
  22. constexpr std::size_t NPAD_OFFSET = 0x9A00;
  23. constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{
  24. Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3,
  25. Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6,
  26. Core::HID::NpadIdType::Player7, Core::HID::NpadIdType::Player8, Core::HID::NpadIdType::Other,
  27. Core::HID::NpadIdType::Handheld,
  28. };
  29. bool Controller_NPad::IsNpadIdValid(Core::HID::NpadIdType npad_id) {
  30. switch (npad_id) {
  31. case Core::HID::NpadIdType::Player1:
  32. case Core::HID::NpadIdType::Player2:
  33. case Core::HID::NpadIdType::Player3:
  34. case Core::HID::NpadIdType::Player4:
  35. case Core::HID::NpadIdType::Player5:
  36. case Core::HID::NpadIdType::Player6:
  37. case Core::HID::NpadIdType::Player7:
  38. case Core::HID::NpadIdType::Player8:
  39. case Core::HID::NpadIdType::Other:
  40. case Core::HID::NpadIdType::Handheld:
  41. return true;
  42. default:
  43. LOG_ERROR(Service_HID, "Invalid npad id {}", npad_id);
  44. return false;
  45. }
  46. }
  47. bool Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) {
  48. const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id));
  49. const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
  50. const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
  51. return npad_id && npad_type && device_index;
  52. }
  53. ResultCode Controller_NPad::VerifyValidSixAxisSensorHandle(
  54. const Core::HID::SixAxisSensorHandle& device_handle) {
  55. const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id));
  56. if (!npad_id) {
  57. return InvalidNpadId;
  58. }
  59. const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
  60. if (!device_index) {
  61. return NpadDeviceIndexOutOfRange;
  62. }
  63. // This doesn't get validaded on nnsdk
  64. const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
  65. if (!npad_type) {
  66. return NpadInvalidHandle;
  67. }
  68. return ResultSuccess;
  69. }
  70. Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
  71. KernelHelpers::ServiceContext& service_context_)
  72. : ControllerBase{hid_core_}, service_context{service_context_} {
  73. static_assert(NPAD_OFFSET + (NPAD_COUNT * sizeof(NpadInternalState)) < shared_memory_size);
  74. for (std::size_t i = 0; i < controller_data.size(); ++i) {
  75. auto& controller = controller_data[i];
  76. controller.shared_memory = std::construct_at(reinterpret_cast<NpadInternalState*>(
  77. raw_shared_memory_ + NPAD_OFFSET + (i * sizeof(NpadInternalState))));
  78. controller.device = hid_core.GetEmulatedControllerByIndex(i);
  79. controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value =
  80. Core::HID::DEFAULT_VIBRATION_VALUE;
  81. controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex].latest_vibration_value =
  82. Core::HID::DEFAULT_VIBRATION_VALUE;
  83. Core::HID::ControllerUpdateCallback engine_callback{
  84. .on_change = [this,
  85. i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); },
  86. .is_npad_service = true,
  87. };
  88. controller.callback_key = controller.device->SetCallback(engine_callback);
  89. }
  90. }
  91. Controller_NPad::~Controller_NPad() {
  92. for (std::size_t i = 0; i < controller_data.size(); ++i) {
  93. auto& controller = controller_data[i];
  94. controller.device->DeleteCallback(controller.callback_key);
  95. }
  96. OnRelease();
  97. }
  98. void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type,
  99. std::size_t controller_idx) {
  100. if (type == Core::HID::ControllerTriggerType::All) {
  101. ControllerUpdate(Core::HID::ControllerTriggerType::Connected, controller_idx);
  102. ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx);
  103. return;
  104. }
  105. if (controller_idx >= controller_data.size()) {
  106. return;
  107. }
  108. auto& controller = controller_data[controller_idx];
  109. const auto is_connected = controller.device->IsConnected();
  110. const auto npad_type = controller.device->GetNpadStyleIndex();
  111. const auto npad_id = controller.device->GetNpadIdType();
  112. switch (type) {
  113. case Core::HID::ControllerTriggerType::Connected:
  114. case Core::HID::ControllerTriggerType::Disconnected:
  115. if (is_connected == controller.is_connected) {
  116. return;
  117. }
  118. UpdateControllerAt(npad_type, npad_id, is_connected);
  119. break;
  120. case Core::HID::ControllerTriggerType::Battery: {
  121. if (!controller.device->IsConnected()) {
  122. return;
  123. }
  124. auto* shared_memory = controller.shared_memory;
  125. const auto& battery_level = controller.device->GetBattery();
  126. shared_memory->battery_level_dual = battery_level.dual.battery_level;
  127. shared_memory->battery_level_left = battery_level.left.battery_level;
  128. shared_memory->battery_level_right = battery_level.right.battery_level;
  129. break;
  130. }
  131. default:
  132. break;
  133. }
  134. }
  135. void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
  136. auto& controller = GetControllerFromNpadIdType(npad_id);
  137. if (!IsControllerSupported(controller.device->GetNpadStyleIndex())) {
  138. return;
  139. }
  140. LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
  141. const auto controller_type = controller.device->GetNpadStyleIndex();
  142. auto* shared_memory = controller.shared_memory;
  143. if (controller_type == Core::HID::NpadStyleIndex::None) {
  144. controller.styleset_changed_event->GetWritableEvent().Signal();
  145. return;
  146. }
  147. shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None;
  148. shared_memory->device_type.raw = 0;
  149. shared_memory->system_properties.raw = 0;
  150. switch (controller_type) {
  151. case Core::HID::NpadStyleIndex::None:
  152. UNREACHABLE();
  153. break;
  154. case Core::HID::NpadStyleIndex::ProController:
  155. shared_memory->style_tag.fullkey.Assign(1);
  156. shared_memory->device_type.fullkey.Assign(1);
  157. shared_memory->system_properties.is_vertical.Assign(1);
  158. shared_memory->system_properties.use_plus.Assign(1);
  159. shared_memory->system_properties.use_minus.Assign(1);
  160. shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController;
  161. break;
  162. case Core::HID::NpadStyleIndex::Handheld:
  163. shared_memory->style_tag.handheld.Assign(1);
  164. shared_memory->device_type.handheld_left.Assign(1);
  165. shared_memory->device_type.handheld_right.Assign(1);
  166. shared_memory->system_properties.is_vertical.Assign(1);
  167. shared_memory->system_properties.use_plus.Assign(1);
  168. shared_memory->system_properties.use_minus.Assign(1);
  169. shared_memory->system_properties.use_directional_buttons.Assign(1);
  170. shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
  171. shared_memory->applet_nfc_xcd.applet_footer.type =
  172. AppletFooterUiType::HandheldJoyConLeftJoyConRight;
  173. break;
  174. case Core::HID::NpadStyleIndex::JoyconDual:
  175. shared_memory->style_tag.joycon_dual.Assign(1);
  176. if (controller.is_dual_left_connected) {
  177. shared_memory->device_type.joycon_left.Assign(1);
  178. shared_memory->system_properties.use_minus.Assign(1);
  179. }
  180. if (controller.is_dual_right_connected) {
  181. shared_memory->device_type.joycon_right.Assign(1);
  182. shared_memory->system_properties.use_plus.Assign(1);
  183. }
  184. shared_memory->system_properties.use_directional_buttons.Assign(1);
  185. shared_memory->system_properties.is_vertical.Assign(1);
  186. shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
  187. if (controller.is_dual_left_connected && controller.is_dual_right_connected) {
  188. shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual;
  189. } else if (controller.is_dual_left_connected) {
  190. shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly;
  191. } else {
  192. shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly;
  193. }
  194. break;
  195. case Core::HID::NpadStyleIndex::JoyconLeft:
  196. shared_memory->style_tag.joycon_left.Assign(1);
  197. shared_memory->device_type.joycon_left.Assign(1);
  198. shared_memory->system_properties.is_horizontal.Assign(1);
  199. shared_memory->system_properties.use_minus.Assign(1);
  200. shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal;
  201. break;
  202. case Core::HID::NpadStyleIndex::JoyconRight:
  203. shared_memory->style_tag.joycon_right.Assign(1);
  204. shared_memory->device_type.joycon_right.Assign(1);
  205. shared_memory->system_properties.is_horizontal.Assign(1);
  206. shared_memory->system_properties.use_plus.Assign(1);
  207. shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal;
  208. break;
  209. case Core::HID::NpadStyleIndex::GameCube:
  210. shared_memory->style_tag.gamecube.Assign(1);
  211. shared_memory->device_type.fullkey.Assign(1);
  212. shared_memory->system_properties.is_vertical.Assign(1);
  213. shared_memory->system_properties.use_plus.Assign(1);
  214. break;
  215. case Core::HID::NpadStyleIndex::Pokeball:
  216. shared_memory->style_tag.palma.Assign(1);
  217. shared_memory->device_type.palma.Assign(1);
  218. break;
  219. case Core::HID::NpadStyleIndex::NES:
  220. shared_memory->style_tag.lark.Assign(1);
  221. shared_memory->device_type.fullkey.Assign(1);
  222. break;
  223. case Core::HID::NpadStyleIndex::SNES:
  224. shared_memory->style_tag.lucia.Assign(1);
  225. shared_memory->device_type.fullkey.Assign(1);
  226. shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::Lucia;
  227. break;
  228. case Core::HID::NpadStyleIndex::N64:
  229. shared_memory->style_tag.lagoon.Assign(1);
  230. shared_memory->device_type.fullkey.Assign(1);
  231. shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::Lagon;
  232. break;
  233. case Core::HID::NpadStyleIndex::SegaGenesis:
  234. shared_memory->style_tag.lager.Assign(1);
  235. shared_memory->device_type.fullkey.Assign(1);
  236. break;
  237. default:
  238. break;
  239. }
  240. const auto& body_colors = controller.device->GetColors();
  241. shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
  242. shared_memory->fullkey_color.fullkey = body_colors.fullkey;
  243. shared_memory->joycon_color.attribute = ColorAttribute::Ok;
  244. shared_memory->joycon_color.left = body_colors.left;
  245. shared_memory->joycon_color.right = body_colors.right;
  246. // TODO: Investigate when we should report all batery types
  247. const auto& battery_level = controller.device->GetBattery();
  248. shared_memory->battery_level_dual = battery_level.dual.battery_level;
  249. shared_memory->battery_level_left = battery_level.left.battery_level;
  250. shared_memory->battery_level_right = battery_level.right.battery_level;
  251. controller.is_connected = true;
  252. controller.device->Connect();
  253. SignalStyleSetChangedEvent(npad_id);
  254. WriteEmptyEntry(controller.shared_memory);
  255. }
  256. void Controller_NPad::OnInit() {
  257. if (!IsControllerActivated()) {
  258. return;
  259. }
  260. for (std::size_t i = 0; i < controller_data.size(); ++i) {
  261. auto& controller = controller_data[i];
  262. controller.styleset_changed_event =
  263. service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i));
  264. }
  265. supported_npad_id_types.resize(npad_id_list.size());
  266. std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
  267. npad_id_list.size() * sizeof(Core::HID::NpadIdType));
  268. // Prefill controller buffers
  269. for (auto& controller : controller_data) {
  270. auto* npad = controller.shared_memory;
  271. npad->fullkey_color = {
  272. .attribute = ColorAttribute::NoController,
  273. .fullkey = {},
  274. };
  275. npad->joycon_color = {
  276. .attribute = ColorAttribute::NoController,
  277. .left = {},
  278. .right = {},
  279. };
  280. // HW seems to initialize the first 19 entries
  281. for (std::size_t i = 0; i < 19; ++i) {
  282. WriteEmptyEntry(npad);
  283. }
  284. }
  285. }
  286. void Controller_NPad::WriteEmptyEntry(NpadInternalState* npad) {
  287. NPadGenericState dummy_pad_state{};
  288. NpadGcTriggerState dummy_gc_state{};
  289. dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().sampling_number + 1;
  290. npad->fullkey_lifo.WriteNextEntry(dummy_pad_state);
  291. dummy_pad_state.sampling_number = npad->handheld_lifo.ReadCurrentEntry().sampling_number + 1;
  292. npad->handheld_lifo.WriteNextEntry(dummy_pad_state);
  293. dummy_pad_state.sampling_number = npad->joy_dual_lifo.ReadCurrentEntry().sampling_number + 1;
  294. npad->joy_dual_lifo.WriteNextEntry(dummy_pad_state);
  295. dummy_pad_state.sampling_number = npad->joy_left_lifo.ReadCurrentEntry().sampling_number + 1;
  296. npad->joy_left_lifo.WriteNextEntry(dummy_pad_state);
  297. dummy_pad_state.sampling_number = npad->joy_right_lifo.ReadCurrentEntry().sampling_number + 1;
  298. npad->joy_right_lifo.WriteNextEntry(dummy_pad_state);
  299. dummy_pad_state.sampling_number = npad->palma_lifo.ReadCurrentEntry().sampling_number + 1;
  300. npad->palma_lifo.WriteNextEntry(dummy_pad_state);
  301. dummy_pad_state.sampling_number = npad->system_ext_lifo.ReadCurrentEntry().sampling_number + 1;
  302. npad->system_ext_lifo.WriteNextEntry(dummy_pad_state);
  303. dummy_gc_state.sampling_number = npad->gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1;
  304. npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state);
  305. }
  306. void Controller_NPad::OnRelease() {
  307. is_controller_initialized = false;
  308. for (std::size_t i = 0; i < controller_data.size(); ++i) {
  309. auto& controller = controller_data[i];
  310. service_context.CloseEvent(controller.styleset_changed_event);
  311. for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) {
  312. VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_idx, {});
  313. }
  314. }
  315. }
  316. void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
  317. std::scoped_lock lock{mutex};
  318. auto& controller = GetControllerFromNpadIdType(npad_id);
  319. const auto controller_type = controller.device->GetNpadStyleIndex();
  320. if (!controller.device->IsConnected()) {
  321. return;
  322. }
  323. auto& pad_entry = controller.npad_pad_state;
  324. auto& trigger_entry = controller.npad_trigger_state;
  325. const auto button_state = controller.device->GetNpadButtons();
  326. const auto stick_state = controller.device->GetSticks();
  327. using btn = Core::HID::NpadButton;
  328. pad_entry.npad_buttons.raw = btn::None;
  329. if (controller_type != Core::HID::NpadStyleIndex::JoyconLeft) {
  330. constexpr btn right_button_mask = btn::A | btn::B | btn::X | btn::Y | btn::StickR | btn::R |
  331. btn::ZR | btn::Plus | btn::StickRLeft | btn::StickRUp |
  332. btn::StickRRight | btn::StickRDown;
  333. pad_entry.npad_buttons.raw = button_state.raw & right_button_mask;
  334. pad_entry.r_stick = stick_state.right;
  335. }
  336. if (controller_type != Core::HID::NpadStyleIndex::JoyconRight) {
  337. constexpr btn left_button_mask =
  338. btn::Left | btn::Up | btn::Right | btn::Down | btn::StickL | btn::L | btn::ZL |
  339. btn::Minus | btn::StickLLeft | btn::StickLUp | btn::StickLRight | btn::StickLDown;
  340. pad_entry.npad_buttons.raw |= button_state.raw & left_button_mask;
  341. pad_entry.l_stick = stick_state.left;
  342. }
  343. if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft) {
  344. pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl);
  345. pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr);
  346. }
  347. if (controller_type == Core::HID::NpadStyleIndex::JoyconRight) {
  348. pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl);
  349. pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr);
  350. }
  351. if (controller_type == Core::HID::NpadStyleIndex::GameCube) {
  352. const auto& trigger_state = controller.device->GetTriggers();
  353. trigger_entry.l_analog = trigger_state.left;
  354. trigger_entry.r_analog = trigger_state.right;
  355. pad_entry.npad_buttons.zl.Assign(false);
  356. pad_entry.npad_buttons.zr.Assign(button_state.r);
  357. pad_entry.npad_buttons.l.Assign(button_state.zl);
  358. pad_entry.npad_buttons.r.Assign(button_state.zr);
  359. }
  360. }
  361. void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
  362. if (!IsControllerActivated()) {
  363. return;
  364. }
  365. for (std::size_t i = 0; i < controller_data.size(); ++i) {
  366. auto& controller = controller_data[i];
  367. auto* npad = controller.shared_memory;
  368. const auto& controller_type = controller.device->GetNpadStyleIndex();
  369. if (controller_type == Core::HID::NpadStyleIndex::None ||
  370. !controller.device->IsConnected()) {
  371. continue;
  372. }
  373. RequestPadStateUpdate(controller.device->GetNpadIdType());
  374. auto& pad_state = controller.npad_pad_state;
  375. auto& libnx_state = controller.npad_libnx_state;
  376. auto& trigger_state = controller.npad_trigger_state;
  377. // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
  378. // any controllers.
  379. libnx_state.connection_status.raw = 0;
  380. libnx_state.connection_status.is_connected.Assign(1);
  381. switch (controller_type) {
  382. case Core::HID::NpadStyleIndex::None:
  383. UNREACHABLE();
  384. break;
  385. case Core::HID::NpadStyleIndex::ProController:
  386. case Core::HID::NpadStyleIndex::NES:
  387. case Core::HID::NpadStyleIndex::SNES:
  388. case Core::HID::NpadStyleIndex::N64:
  389. case Core::HID::NpadStyleIndex::SegaGenesis:
  390. pad_state.connection_status.raw = 0;
  391. pad_state.connection_status.is_connected.Assign(1);
  392. pad_state.connection_status.is_wired.Assign(1);
  393. libnx_state.connection_status.is_wired.Assign(1);
  394. pad_state.sampling_number =
  395. npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
  396. npad->fullkey_lifo.WriteNextEntry(pad_state);
  397. break;
  398. case Core::HID::NpadStyleIndex::Handheld:
  399. pad_state.connection_status.raw = 0;
  400. pad_state.connection_status.is_connected.Assign(1);
  401. pad_state.connection_status.is_wired.Assign(1);
  402. pad_state.connection_status.is_left_connected.Assign(1);
  403. pad_state.connection_status.is_right_connected.Assign(1);
  404. pad_state.connection_status.is_left_wired.Assign(1);
  405. pad_state.connection_status.is_right_wired.Assign(1);
  406. libnx_state.connection_status.is_wired.Assign(1);
  407. libnx_state.connection_status.is_left_connected.Assign(1);
  408. libnx_state.connection_status.is_right_connected.Assign(1);
  409. libnx_state.connection_status.is_left_wired.Assign(1);
  410. libnx_state.connection_status.is_right_wired.Assign(1);
  411. pad_state.sampling_number =
  412. npad->handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
  413. npad->handheld_lifo.WriteNextEntry(pad_state);
  414. break;
  415. case Core::HID::NpadStyleIndex::JoyconDual:
  416. pad_state.connection_status.raw = 0;
  417. pad_state.connection_status.is_connected.Assign(1);
  418. if (controller.is_dual_left_connected) {
  419. pad_state.connection_status.is_left_connected.Assign(1);
  420. libnx_state.connection_status.is_left_connected.Assign(1);
  421. }
  422. if (controller.is_dual_right_connected) {
  423. pad_state.connection_status.is_right_connected.Assign(1);
  424. libnx_state.connection_status.is_right_connected.Assign(1);
  425. }
  426. pad_state.sampling_number =
  427. npad->joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1;
  428. npad->joy_dual_lifo.WriteNextEntry(pad_state);
  429. break;
  430. case Core::HID::NpadStyleIndex::JoyconLeft:
  431. pad_state.connection_status.raw = 0;
  432. pad_state.connection_status.is_connected.Assign(1);
  433. pad_state.connection_status.is_left_connected.Assign(1);
  434. libnx_state.connection_status.is_left_connected.Assign(1);
  435. pad_state.sampling_number =
  436. npad->joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
  437. npad->joy_left_lifo.WriteNextEntry(pad_state);
  438. break;
  439. case Core::HID::NpadStyleIndex::JoyconRight:
  440. pad_state.connection_status.raw = 0;
  441. pad_state.connection_status.is_connected.Assign(1);
  442. pad_state.connection_status.is_right_connected.Assign(1);
  443. libnx_state.connection_status.is_right_connected.Assign(1);
  444. pad_state.sampling_number =
  445. npad->joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
  446. npad->joy_right_lifo.WriteNextEntry(pad_state);
  447. break;
  448. case Core::HID::NpadStyleIndex::GameCube:
  449. pad_state.connection_status.raw = 0;
  450. pad_state.connection_status.is_connected.Assign(1);
  451. pad_state.connection_status.is_wired.Assign(1);
  452. libnx_state.connection_status.is_wired.Assign(1);
  453. pad_state.sampling_number =
  454. npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
  455. trigger_state.sampling_number =
  456. npad->gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1;
  457. npad->fullkey_lifo.WriteNextEntry(pad_state);
  458. npad->gc_trigger_lifo.WriteNextEntry(trigger_state);
  459. break;
  460. case Core::HID::NpadStyleIndex::Pokeball:
  461. pad_state.connection_status.raw = 0;
  462. pad_state.connection_status.is_connected.Assign(1);
  463. pad_state.sampling_number =
  464. npad->palma_lifo.ReadCurrentEntry().state.sampling_number + 1;
  465. npad->palma_lifo.WriteNextEntry(pad_state);
  466. break;
  467. default:
  468. break;
  469. }
  470. libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw;
  471. libnx_state.l_stick = pad_state.l_stick;
  472. libnx_state.r_stick = pad_state.r_stick;
  473. npad->system_ext_lifo.WriteNextEntry(pad_state);
  474. press_state |= static_cast<u64>(pad_state.npad_buttons.raw);
  475. }
  476. }
  477. void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {
  478. if (!IsControllerActivated()) {
  479. return;
  480. }
  481. for (std::size_t i = 0; i < controller_data.size(); ++i) {
  482. auto& controller = controller_data[i];
  483. const auto& controller_type = controller.device->GetNpadStyleIndex();
  484. if (controller_type == Core::HID::NpadStyleIndex::None ||
  485. !controller.device->IsConnected()) {
  486. continue;
  487. }
  488. auto* npad = controller.shared_memory;
  489. const auto& motion_state = controller.device->GetMotions();
  490. auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state;
  491. auto& sixaxis_handheld_state = controller.sixaxis_handheld_state;
  492. auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state;
  493. auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state;
  494. auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state;
  495. auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state;
  496. // Clear previous state
  497. sixaxis_fullkey_state = {};
  498. sixaxis_handheld_state = {};
  499. sixaxis_dual_left_state = {};
  500. sixaxis_dual_right_state = {};
  501. sixaxis_left_lifo_state = {};
  502. sixaxis_right_lifo_state = {};
  503. if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) {
  504. controller.sixaxis_at_rest = true;
  505. for (std::size_t e = 0; e < motion_state.size(); ++e) {
  506. controller.sixaxis_at_rest =
  507. controller.sixaxis_at_rest && motion_state[e].is_at_rest;
  508. }
  509. }
  510. const auto set_motion_state = [&](SixAxisSensorState& state,
  511. const Core::HID::ControllerMotion& hid_state) {
  512. using namespace std::literals::chrono_literals;
  513. static constexpr SixAxisSensorState default_motion_state = {
  514. .delta_time = std::chrono::nanoseconds(5ms).count(),
  515. .accel = {0, 0, -1.0f},
  516. .orientation =
  517. {
  518. Common::Vec3f{1.0f, 0, 0},
  519. Common::Vec3f{0, 1.0f, 0},
  520. Common::Vec3f{0, 0, 1.0f},
  521. },
  522. .attribute = {1},
  523. };
  524. if (!controller.sixaxis_sensor_enabled) {
  525. state = default_motion_state;
  526. return;
  527. }
  528. if (!Settings::values.motion_enabled.GetValue()) {
  529. state = default_motion_state;
  530. return;
  531. }
  532. state.attribute.is_connected.Assign(1);
  533. state.delta_time = std::chrono::nanoseconds(5ms).count();
  534. state.accel = hid_state.accel;
  535. state.gyro = hid_state.gyro;
  536. state.rotation = hid_state.rotation;
  537. state.orientation = hid_state.orientation;
  538. };
  539. switch (controller_type) {
  540. case Core::HID::NpadStyleIndex::None:
  541. UNREACHABLE();
  542. break;
  543. case Core::HID::NpadStyleIndex::ProController:
  544. case Core::HID::NpadStyleIndex::Pokeball:
  545. set_motion_state(sixaxis_fullkey_state, motion_state[0]);
  546. break;
  547. case Core::HID::NpadStyleIndex::Handheld:
  548. set_motion_state(sixaxis_handheld_state, motion_state[0]);
  549. break;
  550. case Core::HID::NpadStyleIndex::JoyconDual:
  551. set_motion_state(sixaxis_dual_left_state, motion_state[0]);
  552. set_motion_state(sixaxis_dual_right_state, motion_state[1]);
  553. break;
  554. case Core::HID::NpadStyleIndex::JoyconLeft:
  555. set_motion_state(sixaxis_left_lifo_state, motion_state[0]);
  556. break;
  557. case Core::HID::NpadStyleIndex::JoyconRight:
  558. set_motion_state(sixaxis_right_lifo_state, motion_state[1]);
  559. break;
  560. default:
  561. break;
  562. }
  563. sixaxis_fullkey_state.sampling_number =
  564. npad->sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
  565. sixaxis_handheld_state.sampling_number =
  566. npad->sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
  567. sixaxis_dual_left_state.sampling_number =
  568. npad->sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
  569. sixaxis_dual_right_state.sampling_number =
  570. npad->sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
  571. sixaxis_left_lifo_state.sampling_number =
  572. npad->sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
  573. sixaxis_right_lifo_state.sampling_number =
  574. npad->sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
  575. if (Core::HID::IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
  576. // This buffer only is updated on handheld on HW
  577. npad->sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state);
  578. } else {
  579. // Handheld doesn't update this buffer on HW
  580. npad->sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state);
  581. }
  582. npad->sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state);
  583. npad->sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state);
  584. npad->sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state);
  585. npad->sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state);
  586. }
  587. }
  588. void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) {
  589. hid_core.SetSupportedStyleTag(style_set);
  590. if (is_controller_initialized) {
  591. return;
  592. }
  593. // Once SetSupportedStyleSet is called controllers are fully initialized
  594. is_controller_initialized = true;
  595. // Connect all active controllers
  596. for (auto& controller : controller_data) {
  597. const auto& device = controller.device;
  598. if (device->IsConnected()) {
  599. AddNewControllerAt(device->GetNpadStyleIndex(), device->GetNpadIdType());
  600. }
  601. }
  602. }
  603. Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const {
  604. if (!is_controller_initialized) {
  605. return {Core::HID::NpadStyleSet::None};
  606. }
  607. return hid_core.GetSupportedStyleTag();
  608. }
  609. void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) {
  610. ASSERT(length > 0 && (length % sizeof(u32)) == 0);
  611. supported_npad_id_types.clear();
  612. supported_npad_id_types.resize(length / sizeof(u32));
  613. std::memcpy(supported_npad_id_types.data(), data, length);
  614. }
  615. void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
  616. ASSERT(max_length < supported_npad_id_types.size());
  617. std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size());
  618. }
  619. std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const {
  620. return supported_npad_id_types.size();
  621. }
  622. void Controller_NPad::SetHoldType(NpadJoyHoldType joy_hold_type) {
  623. if (joy_hold_type != NpadJoyHoldType::Horizontal &&
  624. joy_hold_type != NpadJoyHoldType::Vertical) {
  625. LOG_ERROR(Service_HID, "Npad joy hold type needs to be valid, joy_hold_type={}",
  626. joy_hold_type);
  627. return;
  628. }
  629. hold_type = joy_hold_type;
  630. }
  631. Controller_NPad::NpadJoyHoldType Controller_NPad::GetHoldType() const {
  632. return hold_type;
  633. }
  634. void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) {
  635. handheld_activation_mode = activation_mode;
  636. }
  637. Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActivationMode() const {
  638. return handheld_activation_mode;
  639. }
  640. void Controller_NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) {
  641. communication_mode = communication_mode_;
  642. }
  643. Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode() const {
  644. return communication_mode;
  645. }
  646. ResultCode Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id,
  647. NpadJoyDeviceType npad_device_type,
  648. NpadJoyAssignmentMode assignment_mode) {
  649. if (!IsNpadIdValid(npad_id)) {
  650. LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
  651. return InvalidNpadId;
  652. }
  653. auto& controller = GetControllerFromNpadIdType(npad_id);
  654. if (controller.shared_memory->assignment_mode != assignment_mode) {
  655. controller.shared_memory->assignment_mode = assignment_mode;
  656. }
  657. if (!controller.device->IsConnected()) {
  658. return ResultSuccess;
  659. }
  660. if (assignment_mode == NpadJoyAssignmentMode::Dual) {
  661. if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft) {
  662. DisconnectNpad(npad_id);
  663. controller.is_dual_left_connected = true;
  664. controller.is_dual_right_connected = false;
  665. UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true);
  666. return ResultSuccess;
  667. }
  668. if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) {
  669. DisconnectNpad(npad_id);
  670. controller.is_dual_left_connected = false;
  671. controller.is_dual_right_connected = true;
  672. UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true);
  673. return ResultSuccess;
  674. }
  675. return ResultSuccess;
  676. }
  677. // This is for NpadJoyAssignmentMode::Single
  678. // Only JoyconDual get affected by this function
  679. if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) {
  680. return ResultSuccess;
  681. }
  682. if (controller.is_dual_left_connected && !controller.is_dual_right_connected) {
  683. DisconnectNpad(npad_id);
  684. UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true);
  685. return ResultSuccess;
  686. }
  687. if (!controller.is_dual_left_connected && controller.is_dual_right_connected) {
  688. DisconnectNpad(npad_id);
  689. UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true);
  690. return ResultSuccess;
  691. }
  692. // We have two controllers connected to the same npad_id we need to split them
  693. const auto npad_id_2 = hid_core.GetFirstDisconnectedNpadId();
  694. auto& controller_2 = GetControllerFromNpadIdType(npad_id_2);
  695. DisconnectNpad(npad_id);
  696. if (npad_device_type == NpadJoyDeviceType::Left) {
  697. UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true);
  698. controller_2.is_dual_left_connected = false;
  699. controller_2.is_dual_right_connected = true;
  700. UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true);
  701. } else {
  702. UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true);
  703. controller_2.is_dual_left_connected = true;
  704. controller_2.is_dual_right_connected = false;
  705. UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true);
  706. }
  707. return ResultSuccess;
  708. }
  709. bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
  710. std::size_t device_index,
  711. const Core::HID::VibrationValue& vibration_value) {
  712. auto& controller = GetControllerFromNpadIdType(npad_id);
  713. if (!controller.device->IsConnected()) {
  714. return false;
  715. }
  716. if (!controller.device->IsVibrationEnabled()) {
  717. if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f ||
  718. controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) {
  719. // Send an empty vibration to stop any vibrations.
  720. Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f};
  721. controller.device->SetVibration(device_index, vibration);
  722. // Then reset the vibration value to its default value.
  723. controller.vibration[device_index].latest_vibration_value =
  724. Core::HID::DEFAULT_VIBRATION_VALUE;
  725. }
  726. return false;
  727. }
  728. if (!Settings::values.enable_accurate_vibrations.GetValue()) {
  729. using std::chrono::duration_cast;
  730. using std::chrono::milliseconds;
  731. using std::chrono::steady_clock;
  732. const auto now = steady_clock::now();
  733. // Filter out non-zero vibrations that are within 10ms of each other.
  734. if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) &&
  735. duration_cast<milliseconds>(
  736. now - controller.vibration[device_index].last_vibration_timepoint) <
  737. milliseconds(10)) {
  738. return false;
  739. }
  740. controller.vibration[device_index].last_vibration_timepoint = now;
  741. }
  742. Core::HID::VibrationValue vibration{
  743. vibration_value.low_amplitude, vibration_value.low_frequency,
  744. vibration_value.high_amplitude, vibration_value.high_frequency};
  745. return controller.device->SetVibration(device_index, vibration);
  746. }
  747. void Controller_NPad::VibrateController(
  748. const Core::HID::VibrationDeviceHandle& vibration_device_handle,
  749. const Core::HID::VibrationValue& vibration_value) {
  750. if (!IsDeviceHandleValid(vibration_device_handle)) {
  751. return;
  752. }
  753. if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
  754. return;
  755. }
  756. auto& controller = GetControllerFromHandle(vibration_device_handle);
  757. const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
  758. if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) {
  759. return;
  760. }
  761. if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) {
  762. UNREACHABLE_MSG("DeviceIndex should never be None!");
  763. return;
  764. }
  765. // Some games try to send mismatched parameters in the device handle, block these.
  766. if ((controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft &&
  767. (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconRight ||
  768. vibration_device_handle.device_index == Core::HID::DeviceIndex::Right)) ||
  769. (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight &&
  770. (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconLeft ||
  771. vibration_device_handle.device_index == Core::HID::DeviceIndex::Left))) {
  772. return;
  773. }
  774. // Filter out vibrations with equivalent values to reduce unnecessary state changes.
  775. if (vibration_value.low_amplitude ==
  776. controller.vibration[device_index].latest_vibration_value.low_amplitude &&
  777. vibration_value.high_amplitude ==
  778. controller.vibration[device_index].latest_vibration_value.high_amplitude) {
  779. return;
  780. }
  781. if (VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_index,
  782. vibration_value)) {
  783. controller.vibration[device_index].latest_vibration_value = vibration_value;
  784. }
  785. }
  786. void Controller_NPad::VibrateControllers(
  787. const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles,
  788. const std::vector<Core::HID::VibrationValue>& vibration_values) {
  789. if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
  790. return;
  791. }
  792. ASSERT_OR_EXECUTE_MSG(
  793. vibration_device_handles.size() == vibration_values.size(), { return; },
  794. "The amount of device handles does not match with the amount of vibration values,"
  795. "this is undefined behavior!");
  796. for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) {
  797. VibrateController(vibration_device_handles[i], vibration_values[i]);
  798. }
  799. }
  800. Core::HID::VibrationValue Controller_NPad::GetLastVibration(
  801. const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
  802. if (!IsDeviceHandleValid(vibration_device_handle)) {
  803. return {};
  804. }
  805. const auto& controller = GetControllerFromHandle(vibration_device_handle);
  806. const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
  807. return controller.vibration[device_index].latest_vibration_value;
  808. }
  809. void Controller_NPad::InitializeVibrationDevice(
  810. const Core::HID::VibrationDeviceHandle& vibration_device_handle) {
  811. if (!IsDeviceHandleValid(vibration_device_handle)) {
  812. return;
  813. }
  814. const auto npad_index = static_cast<Core::HID::NpadIdType>(vibration_device_handle.npad_id);
  815. const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
  816. InitializeVibrationDeviceAtIndex(npad_index, device_index);
  817. }
  818. void Controller_NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id,
  819. std::size_t device_index) {
  820. auto& controller = GetControllerFromNpadIdType(npad_id);
  821. if (!Settings::values.vibration_enabled.GetValue()) {
  822. controller.vibration[device_index].device_mounted = false;
  823. return;
  824. }
  825. controller.vibration[device_index].device_mounted =
  826. controller.device->TestVibration(device_index);
  827. }
  828. void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) {
  829. permit_vibration_session_enabled = permit_vibration_session;
  830. }
  831. bool Controller_NPad::IsVibrationDeviceMounted(
  832. const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
  833. if (!IsDeviceHandleValid(vibration_device_handle)) {
  834. return false;
  835. }
  836. const auto& controller = GetControllerFromHandle(vibration_device_handle);
  837. const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
  838. return controller.vibration[device_index].device_mounted;
  839. }
  840. Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id) {
  841. if (!IsNpadIdValid(npad_id)) {
  842. LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
  843. // Fallback to player 1
  844. const auto& controller = GetControllerFromNpadIdType(Core::HID::NpadIdType::Player1);
  845. return controller.styleset_changed_event->GetReadableEvent();
  846. }
  847. const auto& controller = GetControllerFromNpadIdType(npad_id);
  848. return controller.styleset_changed_event->GetReadableEvent();
  849. }
  850. void Controller_NPad::SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const {
  851. const auto& controller = GetControllerFromNpadIdType(npad_id);
  852. controller.styleset_changed_event->GetWritableEvent().Signal();
  853. }
  854. void Controller_NPad::AddNewControllerAt(Core::HID::NpadStyleIndex controller,
  855. Core::HID::NpadIdType npad_id) {
  856. UpdateControllerAt(controller, npad_id, true);
  857. }
  858. void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type,
  859. Core::HID::NpadIdType npad_id, bool connected) {
  860. auto& controller = GetControllerFromNpadIdType(npad_id);
  861. if (!connected) {
  862. DisconnectNpad(npad_id);
  863. return;
  864. }
  865. controller.device->SetNpadStyleIndex(type);
  866. InitNewlyAddedController(npad_id);
  867. }
  868. ResultCode Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
  869. if (!IsNpadIdValid(npad_id)) {
  870. LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
  871. return InvalidNpadId;
  872. }
  873. LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id);
  874. auto& controller = GetControllerFromNpadIdType(npad_id);
  875. for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) {
  876. // Send an empty vibration to stop any vibrations.
  877. VibrateControllerAtIndex(npad_id, device_idx, {});
  878. controller.vibration[device_idx].device_mounted = false;
  879. }
  880. auto* shared_memory = controller.shared_memory;
  881. // Don't reset shared_memory->assignment_mode this value is persistent
  882. shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out
  883. shared_memory->device_type.raw = 0;
  884. shared_memory->system_properties.raw = 0;
  885. shared_memory->button_properties.raw = 0;
  886. shared_memory->battery_level_dual = 0;
  887. shared_memory->battery_level_left = 0;
  888. shared_memory->battery_level_right = 0;
  889. shared_memory->fullkey_color = {
  890. .attribute = ColorAttribute::NoController,
  891. .fullkey = {},
  892. };
  893. shared_memory->joycon_color = {
  894. .attribute = ColorAttribute::NoController,
  895. .left = {},
  896. .right = {},
  897. };
  898. shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::None;
  899. controller.is_dual_left_connected = true;
  900. controller.is_dual_right_connected = true;
  901. controller.is_connected = false;
  902. controller.device->Disconnect();
  903. SignalStyleSetChangedEvent(npad_id);
  904. WriteEmptyEntry(shared_memory);
  905. return ResultSuccess;
  906. }
  907. ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(
  908. const Core::HID::SixAxisSensorHandle& sixaxis_handle, GyroscopeZeroDriftMode drift_mode) {
  909. const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
  910. if (is_valid.IsError()) {
  911. LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
  912. return is_valid;
  913. }
  914. auto& sixaxis = GetSixaxisState(sixaxis_handle);
  915. sixaxis.gyroscope_zero_drift_mode = drift_mode;
  916. return ResultSuccess;
  917. }
  918. ResultCode Controller_NPad::GetGyroscopeZeroDriftMode(
  919. const Core::HID::SixAxisSensorHandle& sixaxis_handle,
  920. GyroscopeZeroDriftMode& drift_mode) const {
  921. const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
  922. if (is_valid.IsError()) {
  923. LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
  924. return is_valid;
  925. }
  926. const auto& sixaxis = GetSixaxisState(sixaxis_handle);
  927. drift_mode = sixaxis.gyroscope_zero_drift_mode;
  928. return ResultSuccess;
  929. }
  930. ResultCode Controller_NPad::IsSixAxisSensorAtRest(
  931. const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_at_rest) const {
  932. const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
  933. if (is_valid.IsError()) {
  934. LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
  935. return is_valid;
  936. }
  937. const auto& controller = GetControllerFromHandle(sixaxis_handle);
  938. is_at_rest = controller.sixaxis_at_rest;
  939. return ResultSuccess;
  940. }
  941. ResultCode Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor(
  942. const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const {
  943. const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
  944. if (is_valid.IsError()) {
  945. LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
  946. return is_valid;
  947. }
  948. // We don't support joycon firmware updates
  949. is_firmware_available = false;
  950. return ResultSuccess;
  951. }
  952. ResultCode Controller_NPad::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
  953. bool sixaxis_status) {
  954. const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
  955. if (is_valid.IsError()) {
  956. LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
  957. return is_valid;
  958. }
  959. auto& controller = GetControllerFromHandle(sixaxis_handle);
  960. controller.sixaxis_sensor_enabled = sixaxis_status;
  961. return ResultSuccess;
  962. }
  963. ResultCode Controller_NPad::IsSixAxisSensorFusionEnabled(
  964. const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_fusion_enabled) const {
  965. const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
  966. if (is_valid.IsError()) {
  967. LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
  968. return is_valid;
  969. }
  970. const auto& sixaxis = GetSixaxisState(sixaxis_handle);
  971. is_fusion_enabled = sixaxis.is_fusion_enabled;
  972. return ResultSuccess;
  973. }
  974. ResultCode Controller_NPad::SetSixAxisFusionEnabled(
  975. const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_fusion_enabled) {
  976. const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
  977. if (is_valid.IsError()) {
  978. LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
  979. return is_valid;
  980. }
  981. auto& sixaxis = GetSixaxisState(sixaxis_handle);
  982. sixaxis.is_fusion_enabled = is_fusion_enabled;
  983. return ResultSuccess;
  984. }
  985. ResultCode Controller_NPad::SetSixAxisFusionParameters(
  986. const Core::HID::SixAxisSensorHandle& sixaxis_handle,
  987. Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) {
  988. const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
  989. if (is_valid.IsError()) {
  990. LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
  991. return is_valid;
  992. }
  993. const auto param1 = sixaxis_fusion_parameters.parameter1;
  994. if (param1 < 0.0f || param1 > 1.0f) {
  995. return InvalidSixAxisFusionRange;
  996. }
  997. auto& sixaxis = GetSixaxisState(sixaxis_handle);
  998. sixaxis.fusion = sixaxis_fusion_parameters;
  999. return ResultSuccess;
  1000. }
  1001. ResultCode Controller_NPad::GetSixAxisFusionParameters(
  1002. const Core::HID::SixAxisSensorHandle& sixaxis_handle,
  1003. Core::HID::SixAxisSensorFusionParameters& parameters) const {
  1004. const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
  1005. if (is_valid.IsError()) {
  1006. LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
  1007. return is_valid;
  1008. }
  1009. const auto& sixaxis = GetSixaxisState(sixaxis_handle);
  1010. parameters = sixaxis.fusion;
  1011. return ResultSuccess;
  1012. }
  1013. ResultCode Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
  1014. Core::HID::NpadIdType npad_id_2) {
  1015. if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) {
  1016. LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1,
  1017. npad_id_2);
  1018. return InvalidNpadId;
  1019. }
  1020. auto& controller_1 = GetControllerFromNpadIdType(npad_id_1);
  1021. auto& controller_2 = GetControllerFromNpadIdType(npad_id_2);
  1022. auto controller_style_1 = controller_1.device->GetNpadStyleIndex();
  1023. auto controller_style_2 = controller_2.device->GetNpadStyleIndex();
  1024. // Simplify this code by converting dualjoycon with only a side connected to single joycons
  1025. if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual) {
  1026. if (controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) {
  1027. controller_style_1 = Core::HID::NpadStyleIndex::JoyconLeft;
  1028. }
  1029. if (!controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) {
  1030. controller_style_1 = Core::HID::NpadStyleIndex::JoyconRight;
  1031. }
  1032. }
  1033. if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual) {
  1034. if (controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) {
  1035. controller_style_2 = Core::HID::NpadStyleIndex::JoyconLeft;
  1036. }
  1037. if (!controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) {
  1038. controller_style_2 = Core::HID::NpadStyleIndex::JoyconRight;
  1039. }
  1040. }
  1041. // Invalid merge errors
  1042. if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual ||
  1043. controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual) {
  1044. return NpadIsDualJoycon;
  1045. }
  1046. if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft &&
  1047. controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft) {
  1048. return NpadIsSameType;
  1049. }
  1050. if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight &&
  1051. controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight) {
  1052. return NpadIsSameType;
  1053. }
  1054. // These exceptions are handled as if they where dual joycon
  1055. if (controller_style_1 != Core::HID::NpadStyleIndex::JoyconLeft &&
  1056. controller_style_1 != Core::HID::NpadStyleIndex::JoyconRight) {
  1057. return NpadIsDualJoycon;
  1058. }
  1059. if (controller_style_2 != Core::HID::NpadStyleIndex::JoyconLeft &&
  1060. controller_style_2 != Core::HID::NpadStyleIndex::JoyconRight) {
  1061. return NpadIsDualJoycon;
  1062. }
  1063. // Disconnect the joycon at the second id and connect the dual joycon at the first index.
  1064. DisconnectNpad(npad_id_2);
  1065. controller_1.is_dual_left_connected = true;
  1066. controller_1.is_dual_right_connected = true;
  1067. AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1);
  1068. return ResultSuccess;
  1069. }
  1070. void Controller_NPad::StartLRAssignmentMode() {
  1071. // Nothing internally is used for lr assignment mode. Since we have the ability to set the
  1072. // controller types from boot, it doesn't really matter about showing a selection screen
  1073. is_in_lr_assignment_mode = true;
  1074. }
  1075. void Controller_NPad::StopLRAssignmentMode() {
  1076. is_in_lr_assignment_mode = false;
  1077. }
  1078. ResultCode Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1,
  1079. Core::HID::NpadIdType npad_id_2) {
  1080. if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) {
  1081. LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1,
  1082. npad_id_2);
  1083. return InvalidNpadId;
  1084. }
  1085. if (npad_id_1 == Core::HID::NpadIdType::Handheld ||
  1086. npad_id_2 == Core::HID::NpadIdType::Handheld || npad_id_1 == Core::HID::NpadIdType::Other ||
  1087. npad_id_2 == Core::HID::NpadIdType::Other) {
  1088. return ResultSuccess;
  1089. }
  1090. const auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device;
  1091. const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device;
  1092. const auto type_index_1 = controller_1->GetNpadStyleIndex();
  1093. const auto type_index_2 = controller_2->GetNpadStyleIndex();
  1094. const auto is_connected_1 = controller_1->IsConnected();
  1095. const auto is_connected_2 = controller_2->IsConnected();
  1096. if (!IsControllerSupported(type_index_1) && is_connected_1) {
  1097. return NpadNotConnected;
  1098. }
  1099. if (!IsControllerSupported(type_index_2) && is_connected_2) {
  1100. return NpadNotConnected;
  1101. }
  1102. UpdateControllerAt(type_index_2, npad_id_1, is_connected_2);
  1103. UpdateControllerAt(type_index_1, npad_id_2, is_connected_1);
  1104. return ResultSuccess;
  1105. }
  1106. ResultCode Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id,
  1107. Core::HID::LedPattern& pattern) const {
  1108. if (!IsNpadIdValid(npad_id)) {
  1109. LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
  1110. return InvalidNpadId;
  1111. }
  1112. const auto& controller = GetControllerFromNpadIdType(npad_id).device;
  1113. pattern = controller->GetLedPattern();
  1114. return ResultSuccess;
  1115. }
  1116. ResultCode Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(
  1117. Core::HID::NpadIdType npad_id, bool& is_valid) const {
  1118. if (!IsNpadIdValid(npad_id)) {
  1119. LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
  1120. return InvalidNpadId;
  1121. }
  1122. const auto& controller = GetControllerFromNpadIdType(npad_id);
  1123. is_valid = controller.unintended_home_button_input_protection;
  1124. return ResultSuccess;
  1125. }
  1126. ResultCode Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(
  1127. bool is_protection_enabled, Core::HID::NpadIdType npad_id) {
  1128. if (!IsNpadIdValid(npad_id)) {
  1129. LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
  1130. return InvalidNpadId;
  1131. }
  1132. auto& controller = GetControllerFromNpadIdType(npad_id);
  1133. controller.unintended_home_button_input_protection = is_protection_enabled;
  1134. return ResultSuccess;
  1135. }
  1136. void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) {
  1137. analog_stick_use_center_clamp = use_center_clamp;
  1138. }
  1139. void Controller_NPad::ClearAllConnectedControllers() {
  1140. for (auto& controller : controller_data) {
  1141. if (controller.device->IsConnected() &&
  1142. controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None) {
  1143. controller.device->Disconnect();
  1144. controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None);
  1145. }
  1146. }
  1147. }
  1148. void Controller_NPad::DisconnectAllConnectedControllers() {
  1149. for (auto& controller : controller_data) {
  1150. controller.device->Disconnect();
  1151. }
  1152. }
  1153. void Controller_NPad::ConnectAllDisconnectedControllers() {
  1154. for (auto& controller : controller_data) {
  1155. if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None &&
  1156. !controller.device->IsConnected()) {
  1157. controller.device->Connect();
  1158. }
  1159. }
  1160. }
  1161. void Controller_NPad::ClearAllControllers() {
  1162. for (auto& controller : controller_data) {
  1163. controller.device->Disconnect();
  1164. controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None);
  1165. }
  1166. }
  1167. Core::HID::NpadButton Controller_NPad::GetAndResetPressState() {
  1168. return static_cast<Core::HID::NpadButton>(press_state.exchange(0));
  1169. }
  1170. bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller) const {
  1171. if (controller == Core::HID::NpadStyleIndex::Handheld) {
  1172. const bool support_handheld =
  1173. std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(),
  1174. Core::HID::NpadIdType::Handheld) != supported_npad_id_types.end();
  1175. // Handheld is not even a supported type, lets stop here
  1176. if (!support_handheld) {
  1177. return false;
  1178. }
  1179. // Handheld shouldn't be supported in docked mode
  1180. if (Settings::values.use_docked_mode.GetValue()) {
  1181. return false;
  1182. }
  1183. return true;
  1184. }
  1185. if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(),
  1186. [](Core::HID::NpadIdType npad_id) {
  1187. return npad_id <= Core::HID::NpadIdType::Player8;
  1188. })) {
  1189. Core::HID::NpadStyleTag style = GetSupportedStyleSet();
  1190. switch (controller) {
  1191. case Core::HID::NpadStyleIndex::ProController:
  1192. return style.fullkey;
  1193. case Core::HID::NpadStyleIndex::JoyconDual:
  1194. return style.joycon_dual;
  1195. case Core::HID::NpadStyleIndex::JoyconLeft:
  1196. return style.joycon_left;
  1197. case Core::HID::NpadStyleIndex::JoyconRight:
  1198. return style.joycon_right;
  1199. case Core::HID::NpadStyleIndex::GameCube:
  1200. return style.gamecube;
  1201. case Core::HID::NpadStyleIndex::Pokeball:
  1202. return style.palma;
  1203. case Core::HID::NpadStyleIndex::NES:
  1204. return style.lark;
  1205. case Core::HID::NpadStyleIndex::SNES:
  1206. return style.lucia;
  1207. case Core::HID::NpadStyleIndex::N64:
  1208. return style.lagoon;
  1209. case Core::HID::NpadStyleIndex::SegaGenesis:
  1210. return style.lager;
  1211. default:
  1212. return false;
  1213. }
  1214. }
  1215. return false;
  1216. }
  1217. Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle(
  1218. const Core::HID::SixAxisSensorHandle& device_handle) {
  1219. const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
  1220. return GetControllerFromNpadIdType(npad_id);
  1221. }
  1222. const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle(
  1223. const Core::HID::SixAxisSensorHandle& device_handle) const {
  1224. const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
  1225. return GetControllerFromNpadIdType(npad_id);
  1226. }
  1227. Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle(
  1228. const Core::HID::VibrationDeviceHandle& device_handle) {
  1229. const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
  1230. return GetControllerFromNpadIdType(npad_id);
  1231. }
  1232. const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle(
  1233. const Core::HID::VibrationDeviceHandle& device_handle) const {
  1234. const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
  1235. return GetControllerFromNpadIdType(npad_id);
  1236. }
  1237. Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType(
  1238. Core::HID::NpadIdType npad_id) {
  1239. if (!IsNpadIdValid(npad_id)) {
  1240. LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
  1241. npad_id = Core::HID::NpadIdType::Player1;
  1242. }
  1243. const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id);
  1244. return controller_data[npad_index];
  1245. }
  1246. const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType(
  1247. Core::HID::NpadIdType npad_id) const {
  1248. if (!IsNpadIdValid(npad_id)) {
  1249. LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
  1250. npad_id = Core::HID::NpadIdType::Player1;
  1251. }
  1252. const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id);
  1253. return controller_data[npad_index];
  1254. }
  1255. Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState(
  1256. const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
  1257. auto& controller = GetControllerFromHandle(sixaxis_handle);
  1258. switch (sixaxis_handle.npad_type) {
  1259. case Core::HID::NpadStyleIndex::ProController:
  1260. case Core::HID::NpadStyleIndex::Pokeball:
  1261. return controller.sixaxis_fullkey;
  1262. case Core::HID::NpadStyleIndex::Handheld:
  1263. return controller.sixaxis_handheld;
  1264. case Core::HID::NpadStyleIndex::JoyconDual:
  1265. if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
  1266. return controller.sixaxis_dual_left;
  1267. }
  1268. return controller.sixaxis_dual_right;
  1269. case Core::HID::NpadStyleIndex::JoyconLeft:
  1270. return controller.sixaxis_left;
  1271. case Core::HID::NpadStyleIndex::JoyconRight:
  1272. return controller.sixaxis_right;
  1273. default:
  1274. return controller.sixaxis_unknown;
  1275. }
  1276. }
  1277. const Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState(
  1278. const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
  1279. const auto& controller = GetControllerFromHandle(sixaxis_handle);
  1280. switch (sixaxis_handle.npad_type) {
  1281. case Core::HID::NpadStyleIndex::ProController:
  1282. case Core::HID::NpadStyleIndex::Pokeball:
  1283. return controller.sixaxis_fullkey;
  1284. case Core::HID::NpadStyleIndex::Handheld:
  1285. return controller.sixaxis_handheld;
  1286. case Core::HID::NpadStyleIndex::JoyconDual:
  1287. if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
  1288. return controller.sixaxis_dual_left;
  1289. }
  1290. return controller.sixaxis_dual_right;
  1291. case Core::HID::NpadStyleIndex::JoyconLeft:
  1292. return controller.sixaxis_left;
  1293. case Core::HID::NpadStyleIndex::JoyconRight:
  1294. return controller.sixaxis_right;
  1295. default:
  1296. return controller.sixaxis_unknown;
  1297. }
  1298. }
  1299. } // namespace Service::HID