npad.cpp 57 KB

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