npad.cpp 73 KB

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