diff options
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.cpp | 191 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.h | 2 |
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; | |||
| 26 | constexpr s32 HID_JOYSTICK_MIN = -0x7fff; | 26 | constexpr s32 HID_JOYSTICK_MIN = -0x7fff; |
| 27 | constexpr std::size_t NPAD_OFFSET = 0x9A00; | 27 | constexpr std::size_t NPAD_OFFSET = 0x9A00; |
| 28 | constexpr u32 BATTERY_FULL = 2; | 28 | constexpr u32 BATTERY_FULL = 2; |
| 29 | 29 | constexpr u32 NPAD_HANDHELD = 32; | |
| 30 | constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this? | ||
| 31 | constexpr u32 MAX_NPAD_ID = 7; | ||
| 32 | constexpr Controller_NPad::NPadControllerType PREFERRED_CONTROLLER = | ||
| 33 | Controller_NPad::NPadControllerType::JoyDual; | ||
| 30 | constexpr std::array<u32, 10> npad_id_list{ | 34 | constexpr 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 | ||
| 325 | void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { | 384 | void 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) { | |||
| 433 | void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { | 492 | void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { |
| 434 | can_controllers_vibrate = can_vibrate; | 493 | can_controllers_vibrate = can_vibrate; |
| 435 | } | 494 | } |
| 495 | |||
| 496 | bool 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 | |||
| 532 | Controller_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 |