summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar David Marcec2018-10-20 15:07:18 +1100
committerGravatar David Marcec2018-10-20 15:07:18 +1100
commita03600ba28698ba2c9a7ded20c6da1c22986bf9e (patch)
treefeb7ad14772b04bd0de3cdcff429f6beb84b778f
parentMerge pull request #1501 from ReinUsesLisp/half-float (diff)
downloadyuzu-a03600ba28698ba2c9a7ded20c6da1c22986bf9e.tar.gz
yuzu-a03600ba28698ba2c9a7ded20c6da1c22986bf9e.tar.xz
yuzu-a03600ba28698ba2c9a7ded20c6da1c22986bf9e.zip
Added auto controller switching to supported controllers and single joycon button rotation
This is a subset of the better-hid-2 changes, this fixes input in various games which don't support dual joycons. This pr will search for the next best controller which is supported by the current game
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp191
-rw-r--r--src/core/hle/service/hid/controllers/npad.h2
2 files changed, 189 insertions, 4 deletions
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index b26593b4f..b06e65a77 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -26,7 +26,11 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
26constexpr s32 HID_JOYSTICK_MIN = -0x7fff; 26constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
27constexpr std::size_t NPAD_OFFSET = 0x9A00; 27constexpr std::size_t NPAD_OFFSET = 0x9A00;
28constexpr u32 BATTERY_FULL = 2; 28constexpr u32 BATTERY_FULL = 2;
29 29constexpr u32 NPAD_HANDHELD = 32;
30constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
31constexpr u32 MAX_NPAD_ID = 7;
32constexpr Controller_NPad::NPadControllerType PREFERRED_CONTROLLER =
33 Controller_NPad::NPadControllerType::JoyDual;
30constexpr std::array<u32, 10> npad_id_list{ 34constexpr std::array<u32, 10> npad_id_list{
31 0, 1, 2, 3, 4, 5, 6, 7, 32, 16, 35 0, 1, 2, 3, 4, 5, 6, 7, 32, 16,
32}; 36};
@@ -121,7 +125,7 @@ void Controller_NPad::OnInit() {
121 supported_npad_id_types.resize(npad_id_list.size()); 125 supported_npad_id_types.resize(npad_id_list.size());
122 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), 126 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
123 npad_id_list.size() * sizeof(u32)); 127 npad_id_list.size() * sizeof(u32));
124 AddNewController(NPadControllerType::JoyDual); 128 AddNewController(PREFERRED_CONTROLLER);
125 } 129 }
126} 130}
127 131
@@ -218,6 +222,51 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
218 rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); 222 rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
219 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); 223 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
220 224
225 if (controller_type == NPadControllerType::JoyLeft ||
226 controller_type == NPadControllerType::JoyRight) {
227 if (npad.properties.is_horizontal) {
228 ControllerPadState state{};
229 AnalogPosition temp_lstick_entry{};
230 AnalogPosition temp_rstick_entry{};
231 if (controller_type == NPadControllerType::JoyLeft) {
232 state.d_down.Assign(pad_state.d_left.Value());
233 state.d_left.Assign(pad_state.d_up.Value());
234 state.d_right.Assign(pad_state.d_down.Value());
235 state.d_up.Assign(pad_state.d_right.Value());
236 state.l.Assign(pad_state.l.Value() | pad_state.sl.Value());
237 state.r.Assign(pad_state.r.Value() | pad_state.sr.Value());
238
239 state.zl.Assign(pad_state.zl.Value());
240 state.plus.Assign(pad_state.minus.Value());
241
242 temp_lstick_entry = lstick_entry;
243 temp_rstick_entry = rstick_entry;
244 std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
245 std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
246 temp_lstick_entry.y *= -1;
247 } else if (controller_type == NPadControllerType::JoyRight) {
248 state.x.Assign(pad_state.a.Value());
249 state.a.Assign(pad_state.b.Value());
250 state.b.Assign(pad_state.y.Value());
251 state.y.Assign(pad_state.b.Value());
252
253 state.l.Assign(pad_state.l.Value() | pad_state.sl.Value());
254 state.r.Assign(pad_state.r.Value() | pad_state.sr.Value());
255 state.zr.Assign(pad_state.zr.Value());
256 state.plus.Assign(pad_state.plus.Value());
257
258 temp_lstick_entry = lstick_entry;
259 temp_rstick_entry = rstick_entry;
260 std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
261 std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
262 temp_rstick_entry.x *= -1;
263 }
264 pad_state.raw = state.raw;
265 lstick_entry = temp_lstick_entry;
266 rstick_entry = temp_rstick_entry;
267 }
268 }
269
221 auto& main_controller = 270 auto& main_controller =
222 npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index]; 271 npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
223 auto& handheld_entry = 272 auto& handheld_entry =
@@ -320,6 +369,16 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
320 supported_npad_id_types.clear(); 369 supported_npad_id_types.clear();
321 supported_npad_id_types.resize(length / sizeof(u32)); 370 supported_npad_id_types.resize(length / sizeof(u32));
322 std::memcpy(supported_npad_id_types.data(), data, length); 371 std::memcpy(supported_npad_id_types.data(), data, length);
372 for (std::size_t i = 0; i < connected_controllers.size(); i++) {
373 auto& controller = connected_controllers[i];
374 if (!controller.is_connected) {
375 continue;
376 }
377 if (!IsControllerSupported(PREFERRED_CONTROLLER)) {
378 controller.type = DecideBestController(PREFERRED_CONTROLLER);
379 InitNewlyAddedControler(i);
380 }
381 }
323} 382}
324 383
325void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { 384void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
@@ -351,11 +410,11 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
351 for (std::size_t i = 0; i < controller_ids.size(); i++) { 410 for (std::size_t i = 0; i < controller_ids.size(); i++) {
352 std::size_t controller_pos = i; 411 std::size_t controller_pos = i;
353 // Handheld controller conversion 412 // Handheld controller conversion
354 if (controller_pos == 32) { 413 if (controller_pos == NPAD_HANDHELD) {
355 controller_pos = 8; 414 controller_pos = 8;
356 } 415 }
357 // Unknown controller conversion 416 // Unknown controller conversion
358 if (controller_pos == 16) { 417 if (controller_pos == NPAD_UNKNOWN) {
359 controller_pos = 9; 418 controller_pos = 9;
360 } 419 }
361 if (connected_controllers[controller_pos].is_connected) { 420 if (connected_controllers[controller_pos].is_connected) {
@@ -433,4 +492,128 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
433void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { 492void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
434 can_controllers_vibrate = can_vibrate; 493 can_controllers_vibrate = can_vibrate;
435} 494}
495
496bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const {
497 const bool support_handheld =
498 std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) !=
499 supported_npad_id_types.end();
500 if (controller == NPadControllerType::Handheld) {
501 // Handheld is not even a supported type, lets stop here
502 if (!support_handheld) {
503 return false;
504 }
505 // Handheld should not be supported in docked mode
506 if (Settings::values.use_docked_mode) {
507 return false;
508 }
509
510 return true;
511 }
512 if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(),
513 [](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) {
514 switch (controller) {
515 case NPadControllerType::ProController:
516 return style.pro_controller;
517 case NPadControllerType::JoyDual:
518 return style.joycon_dual;
519 case NPadControllerType::JoyLeft:
520 return style.joycon_left;
521 case NPadControllerType::JoyRight:
522 return style.joycon_right;
523 case NPadControllerType::Pokeball:
524 return style.pokeball;
525 default:
526 return false;
527 }
528 }
529 return false;
530}
531
532Controller_NPad::NPadControllerType Controller_NPad::DecideBestController(
533 NPadControllerType priority) const {
534 if (IsControllerSupported(priority)) {
535 return priority;
536 }
537 const auto is_docked = Settings::values.use_docked_mode;
538 if (is_docked && priority == NPadControllerType::Handheld) {
539 priority = NPadControllerType::JoyDual;
540 if (IsControllerSupported(priority)) {
541 return priority;
542 }
543 }
544 std::vector<NPadControllerType> priority_list;
545 switch (priority) {
546 case NPadControllerType::ProController:
547 priority_list.push_back(NPadControllerType::JoyDual);
548 if (!is_docked) {
549 priority_list.push_back(NPadControllerType::Handheld);
550 }
551 priority_list.push_back(NPadControllerType::JoyLeft);
552 priority_list.push_back(NPadControllerType::JoyRight);
553 priority_list.push_back(NPadControllerType::Pokeball);
554 break;
555 case NPadControllerType::Handheld:
556 priority_list.push_back(NPadControllerType::JoyDual);
557 priority_list.push_back(NPadControllerType::ProController);
558 priority_list.push_back(NPadControllerType::JoyLeft);
559 priority_list.push_back(NPadControllerType::JoyRight);
560 priority_list.push_back(NPadControllerType::Pokeball);
561 break;
562 case NPadControllerType::JoyDual:
563 if (!is_docked) {
564 priority_list.push_back(NPadControllerType::Handheld);
565 }
566 priority_list.push_back(NPadControllerType::ProController);
567 priority_list.push_back(NPadControllerType::JoyLeft);
568 priority_list.push_back(NPadControllerType::JoyRight);
569 priority_list.push_back(NPadControllerType::Pokeball);
570 break;
571 case NPadControllerType::JoyLeft:
572 priority_list.push_back(NPadControllerType::JoyRight);
573 priority_list.push_back(NPadControllerType::JoyDual);
574 if (!is_docked) {
575 priority_list.push_back(NPadControllerType::Handheld);
576 }
577 priority_list.push_back(NPadControllerType::ProController);
578 priority_list.push_back(NPadControllerType::Pokeball);
579 break;
580 case NPadControllerType::JoyRight:
581 priority_list.push_back(NPadControllerType::JoyLeft);
582 priority_list.push_back(NPadControllerType::JoyDual);
583 if (!is_docked) {
584 priority_list.push_back(NPadControllerType::Handheld);
585 }
586 priority_list.push_back(NPadControllerType::ProController);
587 priority_list.push_back(NPadControllerType::Pokeball);
588 break;
589 case NPadControllerType::Pokeball:
590 priority_list.push_back(NPadControllerType::JoyLeft);
591 priority_list.push_back(NPadControllerType::JoyRight);
592 priority_list.push_back(NPadControllerType::JoyDual);
593 if (!is_docked) {
594 priority_list.push_back(NPadControllerType::Handheld);
595 }
596 priority_list.push_back(NPadControllerType::ProController);
597 break;
598 default:
599 priority_list.push_back(NPadControllerType::JoyDual);
600 if (!is_docked) {
601 priority_list.push_back(NPadControllerType::Handheld);
602 }
603 priority_list.push_back(NPadControllerType::ProController);
604 priority_list.push_back(NPadControllerType::JoyLeft);
605 priority_list.push_back(NPadControllerType::JoyRight);
606 priority_list.push_back(NPadControllerType::JoyDual);
607 }
608
609 const auto iter = std::find_if(priority_list.begin(), priority_list.end(),
610 [this](auto type) { return IsControllerSupported(type); });
611 if (iter == priority_list.end()) {
612 UNIMPLEMENTED_MSG("Could not find supported controller!");
613 return priority;
614 }
615
616 return *iter;
617}
618
436} // namespace Service::HID 619} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 7c0f93acf..ac86985ff 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -283,5 +283,7 @@ private:
283 bool can_controllers_vibrate{true}; 283 bool can_controllers_vibrate{true};
284 284
285 void InitNewlyAddedControler(std::size_t controller_idx); 285 void InitNewlyAddedControler(std::size_t controller_idx);
286 bool IsControllerSupported(NPadControllerType controller) const;
287 NPadControllerType DecideBestController(NPadControllerType priority) const;
286}; 288};
287} // namespace Service::HID 289} // namespace Service::HID