diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/service/hid/controllers/controller_base.h | 4 | ||||
-rw-r--r-- | src/core/hle/service/hid/controllers/debug_pad.cpp | 53 | ||||
-rw-r--r-- | src/core/hle/service/hid/controllers/keyboard.cpp | 17 | ||||
-rw-r--r-- | src/core/hle/service/hid/controllers/npad.cpp | 672 | ||||
-rw-r--r-- | src/core/hle/service/hid/controllers/npad.h | 92 | ||||
-rw-r--r-- | src/core/hle/service/hid/controllers/touchscreen.cpp | 12 | ||||
-rw-r--r-- | src/core/hle/service/hid/controllers/touchscreen.h | 1 |
7 files changed, 532 insertions, 319 deletions
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h index 8bc69c372..f47a9e61c 100644 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h @@ -31,6 +31,10 @@ public: virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) = 0; + // When the controller is requesting a motion update for the shared memory + virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, + std::size_t size) {} + // Called when input devices should be loaded virtual void OnLoadInputDevices() = 0; diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index cb35919e9..ad251ed4a 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -39,33 +39,36 @@ void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, cur_entry.sampling_number = last_entry.sampling_number + 1; cur_entry.sampling_number2 = cur_entry.sampling_number; - cur_entry.attribute.connected.Assign(1); - auto& pad = cur_entry.pad_state; - using namespace Settings::NativeButton; - pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); - pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); - pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); - pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); - pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); - pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); - pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); - pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); - pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); - pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); - pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); - pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); - pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); - pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); + if (Settings::values.debug_pad_enabled) { + cur_entry.attribute.connected.Assign(1); + auto& pad = cur_entry.pad_state; - const auto [stick_l_x_f, stick_l_y_f] = - analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); - const auto [stick_r_x_f, stick_r_y_f] = - analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); - cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); - cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); - cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); - cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); + using namespace Settings::NativeButton; + pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); + pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); + pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); + pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); + pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); + pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); + pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); + pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); + pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); + pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); + pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); + pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); + pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); + pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); + + const auto [stick_l_x_f, stick_l_y_f] = + analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); + const auto [stick_r_x_f, stick_r_y_f] = + analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); + cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); + cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); + cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); + cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); + } std::memcpy(data, &shared_memory, sizeof(SharedMemory)); } diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index feae89525..0b896d5ad 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -40,15 +40,16 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, cur_entry.key.fill(0); cur_entry.modifier = 0; - - for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { - cur_entry.key[i / KEYS_PER_BYTE] |= (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE)); - } - - for (std::size_t i = 0; i < keyboard_mods.size(); ++i) { - cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i); + if (Settings::values.keyboard_enabled) { + for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { + cur_entry.key[i / KEYS_PER_BYTE] |= + (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE)); + } + + for (std::size_t i = 0; i < keyboard_mods.size(); ++i) { + cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i); + } } - std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); } diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index ef67ad690..2de4ed348 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -24,6 +24,7 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff; constexpr std::size_t NPAD_OFFSET = 0x9A00; constexpr u32 BATTERY_FULL = 2; constexpr u32 MAX_NPAD_ID = 7; +constexpr std::size_t HANDHELD_INDEX = 8; constexpr std::array<u32, 10> npad_id_list{ 0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN, }; @@ -33,19 +34,41 @@ enum class JoystickId : std::size_t { Joystick_Right, }; -static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type) { +Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad( + Settings::ControllerType type) { switch (type) { case Settings::ControllerType::ProController: - return Controller_NPad::NPadControllerType::ProController; - case Settings::ControllerType::DualJoycon: - return Controller_NPad::NPadControllerType::JoyDual; + return NPadControllerType::ProController; + case Settings::ControllerType::DualJoyconDetached: + return NPadControllerType::JoyDual; case Settings::ControllerType::LeftJoycon: - return Controller_NPad::NPadControllerType::JoyLeft; + return NPadControllerType::JoyLeft; case Settings::ControllerType::RightJoycon: - return Controller_NPad::NPadControllerType::JoyRight; + return NPadControllerType::JoyRight; + case Settings::ControllerType::Handheld: + return NPadControllerType::Handheld; default: UNREACHABLE(); - return Controller_NPad::NPadControllerType::JoyDual; + return NPadControllerType::ProController; + } +} + +Settings::ControllerType Controller_NPad::MapNPadToSettingsType( + Controller_NPad::NPadControllerType type) { + switch (type) { + case NPadControllerType::ProController: + return Settings::ControllerType::ProController; + case NPadControllerType::JoyDual: + return Settings::ControllerType::DualJoyconDetached; + case NPadControllerType::JoyLeft: + return Settings::ControllerType::LeftJoycon; + case NPadControllerType::JoyRight: + return Settings::ControllerType::RightJoycon; + case NPadControllerType::Handheld: + return Settings::ControllerType::Handheld; + default: + UNREACHABLE(); + return Settings::ControllerType::ProController; } } @@ -60,9 +83,9 @@ std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) { case 6: case 7: return npad_id; - case 8: + case HANDHELD_INDEX: case NPAD_HANDHELD: - return 8; + return HANDHELD_INDEX; case 9: case NPAD_UNKNOWN: return 9; @@ -83,38 +106,48 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) { case 6: case 7: return static_cast<u32>(index); - case 8: + case HANDHELD_INDEX: return NPAD_HANDHELD; case 9: return NPAD_UNKNOWN; default: UNIMPLEMENTED_MSG("Unknown npad index {}", index); return 0; - }; + } } Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} Controller_NPad::~Controller_NPad() = default; -void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { +void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { const auto controller_type = connected_controllers[controller_idx].type; auto& controller = shared_memory_entries[controller_idx]; if (controller_type == NPadControllerType::None) { + styleset_changed_events[controller_idx].writable->Signal(); return; } controller.joy_styles.raw = 0; // Zero out controller.device_type.raw = 0; + controller.properties.raw = 0; switch (controller_type) { case NPadControllerType::None: UNREACHABLE(); break; + case NPadControllerType::ProController: + controller.joy_styles.pro_controller.Assign(1); + controller.device_type.pro_controller.Assign(1); + controller.properties.is_vertical.Assign(1); + controller.properties.use_plus.Assign(1); + controller.properties.use_minus.Assign(1); + controller.pad_assignment = NPadAssignments::Single; + break; case NPadControllerType::Handheld: controller.joy_styles.handheld.Assign(1); controller.device_type.handheld.Assign(1); - controller.pad_assignment = NPadAssignments::Dual; controller.properties.is_vertical.Assign(1); controller.properties.use_plus.Assign(1); controller.properties.use_minus.Assign(1); + controller.pad_assignment = NPadAssignments::Dual; break; case NPadControllerType::JoyDual: controller.joy_styles.joycon_dual.Assign(1); @@ -144,14 +177,6 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { controller.device_type.pokeball.Assign(1); controller.pad_assignment = NPadAssignments::Single; break; - case NPadControllerType::ProController: - controller.joy_styles.pro_controller.Assign(1); - controller.device_type.pro_controller.Assign(1); - controller.properties.is_vertical.Assign(1); - controller.properties.use_plus.Assign(1); - controller.properties.use_minus.Assign(1); - controller.pad_assignment = NPadAssignments::Single; - break; } controller.single_color_error = ColorReadError::ReadOk; @@ -168,7 +193,8 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { controller.battery_level[0] = BATTERY_FULL; controller.battery_level[1] = BATTERY_FULL; controller.battery_level[2] = BATTERY_FULL; - styleset_changed_events[controller_idx].writable->Signal(); + + SignalStyleSetChangedEvent(IndexToNPad(controller_idx)); } void Controller_NPad::OnInit() { @@ -192,36 +218,25 @@ void Controller_NPad::OnInit() { style.pokeball.Assign(1); } - std::transform( - Settings::values.players.begin(), Settings::values.players.end(), - connected_controllers.begin(), [](const Settings::PlayerInput& player) { - return ControllerHolder{MapSettingsTypeToNPad(player.type), player.connected}; - }); - - std::stable_partition(connected_controllers.begin(), connected_controllers.begin() + 8, - [](const ControllerHolder& holder) { return holder.is_connected; }); + std::transform(Settings::values.players.begin(), Settings::values.players.end(), + connected_controllers.begin(), [](const Settings::PlayerInput& player) { + return ControllerHolder{MapSettingsTypeToNPad(player.controller_type), + player.connected}; + }); // Account for handheld - if (connected_controllers[8].is_connected) - connected_controllers[8].type = NPadControllerType::Handheld; + if (connected_controllers[HANDHELD_INDEX].is_connected) { + connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld; + } supported_npad_id_types.resize(npad_id_list.size()); std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), npad_id_list.size() * sizeof(u32)); - // Add a default dual joycon controller if none are present. - if (std::none_of(connected_controllers.begin(), connected_controllers.end(), - [](const ControllerHolder& controller) { return controller.is_connected; })) { - supported_npad_id_types.resize(npad_id_list.size()); - std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), - npad_id_list.size() * sizeof(u32)); - AddNewController(NPadControllerType::JoyDual); - } - for (std::size_t i = 0; i < connected_controllers.size(); ++i) { const auto& controller = connected_controllers[i]; if (controller.is_connected) { - AddNewControllerAt(controller.type, IndexToNPad(i)); + AddNewControllerAt(controller.type, i); } } } @@ -235,6 +250,9 @@ void Controller_NPad::OnLoadInputDevices() { std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>); + std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, + players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END, + motions[i].begin(), Input::CreateDevice<Input::MotionDevice>); } } @@ -242,7 +260,7 @@ void Controller_NPad::OnRelease() {} void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { const auto controller_idx = NPadIdToIndex(npad_id); - [[maybe_unused]] const auto controller_type = connected_controllers[controller_idx].type; + const auto controller_type = connected_controllers[controller_idx].type; if (!connected_controllers[controller_idx].is_connected) { return; } @@ -251,66 +269,77 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { auto& rstick_entry = npad_pad_states[controller_idx].r_stick; const auto& button_state = buttons[controller_idx]; const auto& analog_state = sticks[controller_idx]; + const auto& motion_state = motions[controller_idx]; const auto [stick_l_x_f, stick_l_y_f] = analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); const auto [stick_r_x_f, stick_r_y_f] = analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); using namespace Settings::NativeButton; - pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus()); - - pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); - - pad_state.l_stick_right.Assign( - analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( - Input::AnalogDirection::RIGHT)); - pad_state.l_stick_left.Assign( - analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( - Input::AnalogDirection::LEFT)); - pad_state.l_stick_up.Assign( - analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( - Input::AnalogDirection::UP)); - pad_state.l_stick_down.Assign( - analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( - Input::AnalogDirection::DOWN)); - - pad_state.r_stick_right.Assign( - analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] - ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); - pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] - ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); - pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] - ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); - pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] - ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); - - pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); - - lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); - lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); - rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); - rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); + if (controller_type != NPadControllerType::JoyLeft) { + pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus()); + + pad_state.r_stick_right.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); + pad_state.r_stick_left.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); + pad_state.r_stick_up.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); + pad_state.r_stick_down.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); + rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); + rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); + } + + if (controller_type != NPadControllerType::JoyRight) { + pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus()); + + pad_state.l_stick_right.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); + pad_state.l_stick_left.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); + pad_state.l_stick_up.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); + pad_state.l_stick_down.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); + lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); + lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); + } + + if (controller_type == NPadControllerType::JoyLeft || + controller_type == NPadControllerType::JoyRight) { + pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); + } } void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t data_len) { - if (!IsControllerActivated()) + if (!IsControllerActivated()) { return; + } for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { auto& npad = shared_memory_entries[i]; const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states, @@ -344,6 +373,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* continue; } const u32 npad_index = static_cast<u32>(i); + RequestPadStateUpdate(npad_index); auto& pad_state = npad_pad_states[npad_index]; @@ -360,13 +390,37 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; libnx_entry.connection_status.raw = 0; + libnx_entry.connection_status.IsConnected.Assign(1); + auto& full_sixaxis_entry = + npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index]; + auto& handheld_sixaxis_entry = + npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index]; + auto& dual_left_sixaxis_entry = + npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index]; + auto& dual_right_sixaxis_entry = + npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index]; + auto& left_sixaxis_entry = + npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index]; + auto& right_sixaxis_entry = + npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index]; switch (controller_type) { case NPadControllerType::None: UNREACHABLE(); break; + case NPadControllerType::ProController: + main_controller.connection_status.raw = 0; + main_controller.connection_status.IsConnected.Assign(1); + main_controller.connection_status.IsWired.Assign(1); + main_controller.pad.pad_states.raw = pad_state.pad_states.raw; + main_controller.pad.l_stick = pad_state.l_stick; + main_controller.pad.r_stick = pad_state.r_stick; + + libnx_entry.connection_status.IsWired.Assign(1); + break; case NPadControllerType::Handheld: handheld_entry.connection_status.raw = 0; + handheld_entry.connection_status.IsConnected.Assign(1); handheld_entry.connection_status.IsWired.Assign(1); handheld_entry.connection_status.IsLeftJoyConnected.Assign(1); handheld_entry.connection_status.IsRightJoyConnected.Assign(1); @@ -375,57 +429,52 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw; handheld_entry.pad.l_stick = pad_state.l_stick; handheld_entry.pad.r_stick = pad_state.r_stick; + + libnx_entry.connection_status.IsWired.Assign(1); + libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); + libnx_entry.connection_status.IsRightJoyConnected.Assign(1); + libnx_entry.connection_status.IsLeftJoyWired.Assign(1); + libnx_entry.connection_status.IsRightJoyWired.Assign(1); break; case NPadControllerType::JoyDual: dual_entry.connection_status.raw = 0; - + dual_entry.connection_status.IsConnected.Assign(1); dual_entry.connection_status.IsLeftJoyConnected.Assign(1); dual_entry.connection_status.IsRightJoyConnected.Assign(1); - dual_entry.connection_status.IsConnected.Assign(1); - - libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); - libnx_entry.connection_status.IsRightJoyConnected.Assign(1); - libnx_entry.connection_status.IsConnected.Assign(1); - dual_entry.pad.pad_states.raw = pad_state.pad_states.raw; dual_entry.pad.l_stick = pad_state.l_stick; dual_entry.pad.r_stick = pad_state.r_stick; + + libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); + libnx_entry.connection_status.IsRightJoyConnected.Assign(1); break; case NPadControllerType::JoyLeft: left_entry.connection_status.raw = 0; - left_entry.connection_status.IsConnected.Assign(1); + left_entry.connection_status.IsLeftJoyConnected.Assign(1); left_entry.pad.pad_states.raw = pad_state.pad_states.raw; left_entry.pad.l_stick = pad_state.l_stick; left_entry.pad.r_stick = pad_state.r_stick; + + libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); break; case NPadControllerType::JoyRight: right_entry.connection_status.raw = 0; - right_entry.connection_status.IsConnected.Assign(1); + right_entry.connection_status.IsRightJoyConnected.Assign(1); right_entry.pad.pad_states.raw = pad_state.pad_states.raw; right_entry.pad.l_stick = pad_state.l_stick; right_entry.pad.r_stick = pad_state.r_stick; + + libnx_entry.connection_status.IsRightJoyConnected.Assign(1); break; case NPadControllerType::Pokeball: pokeball_entry.connection_status.raw = 0; - pokeball_entry.connection_status.IsConnected.Assign(1); - pokeball_entry.connection_status.IsWired.Assign(1); - pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw; pokeball_entry.pad.l_stick = pad_state.l_stick; pokeball_entry.pad.r_stick = pad_state.r_stick; break; - case NPadControllerType::ProController: - main_controller.connection_status.raw = 0; - - main_controller.connection_status.IsConnected.Assign(1); - main_controller.connection_status.IsWired.Assign(1); - main_controller.pad.pad_states.raw = pad_state.pad_states.raw; - main_controller.pad.l_stick = pad_state.l_stick; - main_controller.pad.r_stick = pad_state.r_stick; - break; } // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate @@ -440,6 +489,143 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* shared_memory_entries.size() * sizeof(NPadEntry)); } +void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, + std::size_t data_len) { + if (!IsControllerActivated()) { + return; + } + for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { + auto& npad = shared_memory_entries[i]; + + const auto& controller_type = connected_controllers[i].type; + + if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { + continue; + } + + const std::array<SixAxisGeneric*, 6> controller_sixaxes{ + &npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left, + &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right, + }; + + for (auto* sixaxis_sensor : controller_sixaxes) { + sixaxis_sensor->common.entry_count = 16; + sixaxis_sensor->common.total_entry_count = 17; + + const auto& last_entry = + sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; + + sixaxis_sensor->common.timestamp = core_timing.GetCPUTicks(); + sixaxis_sensor->common.last_entry_index = + (sixaxis_sensor->common.last_entry_index + 1) % 17; + + auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; + + cur_entry.timestamp = last_entry.timestamp + 1; + cur_entry.timestamp2 = cur_entry.timestamp; + } + + // Try to read sixaxis sensor states + std::array<MotionDevice, 2> motion_devices; + + if (sixaxis_sensors_enabled && Settings::values.motion_enabled) { + sixaxis_at_rest = true; + for (std::size_t e = 0; e < motion_devices.size(); ++e) { + const auto& device = motions[i][e]; + if (device) { + std::tie(motion_devices[e].accel, motion_devices[e].gyro, + motion_devices[e].rotation, motion_devices[e].orientation) = + device->GetStatus(); + sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f; + } + } + } + + auto& main_controller = + npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index]; + auto& handheld_entry = + npad.handheld_states.npad[npad.handheld_states.common.last_entry_index]; + auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index]; + auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index]; + auto& right_entry = + npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index]; + auto& pokeball_entry = + npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index]; + auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; + + auto& full_sixaxis_entry = + npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index]; + auto& handheld_sixaxis_entry = + npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index]; + auto& dual_left_sixaxis_entry = + npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index]; + auto& dual_right_sixaxis_entry = + npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index]; + auto& left_sixaxis_entry = + npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index]; + auto& right_sixaxis_entry = + npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index]; + + switch (controller_type) { + case NPadControllerType::None: + UNREACHABLE(); + break; + case NPadControllerType::ProController: + if (sixaxis_sensors_enabled && motions[i][0]) { + full_sixaxis_entry.accel = motion_devices[0].accel; + full_sixaxis_entry.gyro = motion_devices[0].gyro; + full_sixaxis_entry.rotation = motion_devices[0].rotation; + full_sixaxis_entry.orientation = motion_devices[0].orientation; + } + break; + case NPadControllerType::Handheld: + if (sixaxis_sensors_enabled && motions[i][0]) { + handheld_sixaxis_entry.accel = motion_devices[0].accel; + handheld_sixaxis_entry.gyro = motion_devices[0].gyro; + handheld_sixaxis_entry.rotation = motion_devices[0].rotation; + handheld_sixaxis_entry.orientation = motion_devices[0].orientation; + } + break; + case NPadControllerType::JoyDual: + if (sixaxis_sensors_enabled && motions[i][0]) { + // Set motion for the left joycon + dual_left_sixaxis_entry.accel = motion_devices[0].accel; + dual_left_sixaxis_entry.gyro = motion_devices[0].gyro; + dual_left_sixaxis_entry.rotation = motion_devices[0].rotation; + dual_left_sixaxis_entry.orientation = motion_devices[0].orientation; + } + if (sixaxis_sensors_enabled && motions[i][1]) { + // Set motion for the right joycon + dual_right_sixaxis_entry.accel = motion_devices[1].accel; + dual_right_sixaxis_entry.gyro = motion_devices[1].gyro; + dual_right_sixaxis_entry.rotation = motion_devices[1].rotation; + dual_right_sixaxis_entry.orientation = motion_devices[1].orientation; + } + break; + case NPadControllerType::JoyLeft: + if (sixaxis_sensors_enabled && motions[i][0]) { + left_sixaxis_entry.accel = motion_devices[0].accel; + left_sixaxis_entry.gyro = motion_devices[0].gyro; + left_sixaxis_entry.rotation = motion_devices[0].rotation; + left_sixaxis_entry.orientation = motion_devices[0].orientation; + } + break; + case NPadControllerType::JoyRight: + if (sixaxis_sensors_enabled && motions[i][1]) { + right_sixaxis_entry.accel = motion_devices[1].accel; + right_sixaxis_entry.gyro = motion_devices[1].gyro; + right_sixaxis_entry.rotation = motion_devices[1].rotation; + right_sixaxis_entry.orientation = motion_devices[1].orientation; + } + break; + case NPadControllerType::Pokeball: + break; + } + } + std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), + shared_memory_entries.size() * sizeof(NPadEntry)); +} + void Controller_NPad::SetSupportedStyleSet(NPadType style_set) { style.raw = style_set.raw; } @@ -453,26 +639,6 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { supported_npad_id_types.clear(); supported_npad_id_types.resize(length / sizeof(u32)); std::memcpy(supported_npad_id_types.data(), data, length); - for (std::size_t i = 0; i < connected_controllers.size(); i++) { - auto& controller = connected_controllers[i]; - if (!controller.is_connected) { - continue; - } - const auto requested_controller = - i <= MAX_NPAD_ID ? MapSettingsTypeToNPad(Settings::values.players[i].type) - : NPadControllerType::Handheld; - if (!IsControllerSupported(requested_controller)) { - const auto is_handheld = requested_controller == NPadControllerType::Handheld; - if (is_handheld) { - controller.type = NPadControllerType::None; - controller.is_connected = false; - AddNewController(requested_controller); - } else { - controller.type = requested_controller; - InitNewlyAddedControler(i); - } - } - } } void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { @@ -492,6 +658,14 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { return hold_type; } +void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) { + handheld_activation_mode = activation_mode; +} + +Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActivationMode() const { + return handheld_activation_mode; +} + void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { const std::size_t npad_index = NPadIdToIndex(npad_id); ASSERT(npad_index < shared_memory_entries.size()); @@ -500,70 +674,86 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) } } -void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, +void Controller_NPad::VibrateController(const std::vector<u32>& controllers, const std::vector<Vibration>& vibrations) { - LOG_DEBUG(Service_HID, "(STUBBED) called"); + LOG_TRACE(Service_HID, "called"); - if (!can_controllers_vibrate) { + if (!Settings::values.vibration_enabled || !can_controllers_vibrate) { return; } - for (std::size_t i = 0; i < controller_ids.size(); i++) { - std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i)); - if (connected_controllers[controller_pos].is_connected) { - // TODO(ogniK): Vibrate the physical controller + bool success = true; + for (std::size_t i = 0; i < controllers.size(); ++i) { + if (!connected_controllers[i].is_connected) { + continue; + } + using namespace Settings::NativeButton; + const auto& button_state = buttons[i]; + if (button_state[A - BUTTON_HID_BEGIN]) { + if (button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay( + vibrations[0].amp_high, vibrations[0].amp_low, vibrations[0].freq_high, + vibrations[0].freq_low)) { + success = false; + } } } - last_processed_vibration = vibrations.back(); + if (success) { + last_processed_vibration = vibrations.back(); + } +} + +Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { + return last_processed_vibration; } std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { - // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should - // be signalled at least once, and signaled after a new controller is connected? const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; return styleset_event.readable; } -Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { - return last_processed_vibration; +void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { + styleset_changed_events[NPadIdToIndex(npad_id)].writable->Signal(); } -void Controller_NPad::AddNewController(NPadControllerType controller) { - controller = DecideBestController(controller); - if (controller == NPadControllerType::Handheld) { - connected_controllers[8] = {controller, true}; - InitNewlyAddedControler(8); - return; - } - const auto pos = - std::find_if(connected_controllers.begin(), connected_controllers.end() - 2, - [](const ControllerHolder& holder) { return !holder.is_connected; }); - if (pos == connected_controllers.end() - 2) { - LOG_ERROR(Service_HID, "Cannot connect any more controllers!"); +void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { + UpdateControllerAt(controller, npad_index, true); +} + +void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, + bool connected) { + if (!connected) { + DisconnectNPadAtIndex(npad_index); return; } - const auto controller_id = std::distance(connected_controllers.begin(), pos); - connected_controllers[controller_id] = {controller, true}; - InitNewlyAddedControler(controller_id); -} -void Controller_NPad::AddNewControllerAt(NPadControllerType controller, u32 npad_id) { - controller = DecideBestController(controller); if (controller == NPadControllerType::Handheld) { - connected_controllers[NPadIdToIndex(NPAD_HANDHELD)] = {controller, true}; - InitNewlyAddedControler(NPadIdToIndex(NPAD_HANDHELD)); + Settings::values.players[HANDHELD_INDEX].controller_type = + MapNPadToSettingsType(controller); + Settings::values.players[HANDHELD_INDEX].connected = true; + connected_controllers[HANDHELD_INDEX] = {controller, true}; + InitNewlyAddedController(HANDHELD_INDEX); return; } - connected_controllers[NPadIdToIndex(npad_id)] = {controller, true}; - InitNewlyAddedControler(NPadIdToIndex(npad_id)); + Settings::values.players[npad_index].controller_type = MapNPadToSettingsType(controller); + Settings::values.players[npad_index].connected = true; + connected_controllers[npad_index] = {controller, true}; + InitNewlyAddedController(npad_index); } -void Controller_NPad::ConnectNPad(u32 npad_id) { - connected_controllers[NPadIdToIndex(npad_id)].is_connected = true; +void Controller_NPad::DisconnectNPad(u32 npad_id) { + DisconnectNPadAtIndex(NPadIdToIndex(npad_id)); } -void Controller_NPad::DisconnectNPad(u32 npad_id) { - connected_controllers[NPadIdToIndex(npad_id)].is_connected = false; +void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) { + Settings::values.players[npad_index].connected = false; + connected_controllers[npad_index].is_connected = false; + + auto& controller = shared_memory_entries[npad_index]; + controller.joy_styles.raw = 0; // Zero out + controller.device_type.raw = 0; + controller.properties.raw = 0; + + SignalStyleSetChangedEvent(IndexToNPad(npad_index)); } void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { @@ -574,6 +764,30 @@ Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMo return gyroscope_zero_drift_mode; } +bool Controller_NPad::IsSixAxisSensorAtRest() const { + return sixaxis_at_rest; +} + +void Controller_NPad::SetSixAxisEnabled(bool six_axis_status) { + sixaxis_sensors_enabled = six_axis_status; +} + +void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { + const auto npad_index_1 = NPadIdToIndex(npad_id_1); + const auto npad_index_2 = NPadIdToIndex(npad_id_2); + + // If the controllers at both npad indices form a pair of left and right joycons, merge them. + // Otherwise, do nothing. + if ((connected_controllers[npad_index_1].type == NPadControllerType::JoyLeft && + connected_controllers[npad_index_2].type == NPadControllerType::JoyRight) || + (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft && + connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) { + // Disconnect the joycon at the second id and connect the dual joycon at the first index. + DisconnectNPad(npad_id_2); + AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1); + } +} + void Controller_NPad::StartLRAssignmentMode() { // Nothing internally is used for lr assignment mode. Since we have the ability to set the // controller types from boot, it doesn't really matter about showing a selection screen @@ -599,8 +813,8 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) { std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type); - InitNewlyAddedControler(npad_index_1); - InitNewlyAddedControler(npad_index_2); + AddNewControllerAt(connected_controllers[npad_index_1].type, npad_index_1); + AddNewControllerAt(connected_controllers[npad_index_2].type, npad_index_2); return true; } @@ -614,11 +828,11 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { case 0: return LedPattern{1, 0, 0, 0}; case 1: - return LedPattern{0, 1, 0, 0}; + return LedPattern{1, 1, 0, 0}; case 2: - return LedPattern{0, 0, 1, 0}; + return LedPattern{1, 1, 1, 0}; case 3: - return LedPattern{0, 0, 0, 1}; + return LedPattern{1, 1, 1, 1}; case 4: return LedPattern{1, 0, 0, 1}; case 5: @@ -628,9 +842,17 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { case 7: return LedPattern{0, 1, 1, 0}; default: - UNIMPLEMENTED_MSG("Unhandled npad_id {}", npad_id); return LedPattern{0, 0, 0, 0}; - }; + } +} + +bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const { + return unintended_home_button_input_protection[NPadIdToIndex(npad_id)]; +} + +void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, + u32 npad_id) { + unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled; } void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { @@ -651,13 +873,13 @@ void Controller_NPad::ClearAllConnectedControllers() { } void Controller_NPad::DisconnectAllConnectedControllers() { - for (ControllerHolder& controller : connected_controllers) { + for (auto& controller : connected_controllers) { controller.is_connected = false; } } void Controller_NPad::ConnectAllDisconnectedControllers() { - for (ControllerHolder& controller : connected_controllers) { + for (auto& controller : connected_controllers) { if (controller.type != NPadControllerType::None && !controller.is_connected) { controller.is_connected = true; } @@ -665,7 +887,7 @@ void Controller_NPad::ConnectAllDisconnectedControllers() { } void Controller_NPad::ClearAllControllers() { - for (ControllerHolder& controller : connected_controllers) { + for (auto& controller : connected_controllers) { controller.type = NPadControllerType::None; controller.is_connected = false; } @@ -713,92 +935,4 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const return false; } -Controller_NPad::NPadControllerType Controller_NPad::DecideBestController( - NPadControllerType priority) const { - if (IsControllerSupported(priority)) { - return priority; - } - const auto is_docked = Settings::values.use_docked_mode; - if (is_docked && priority == NPadControllerType::Handheld) { - priority = NPadControllerType::JoyDual; - if (IsControllerSupported(priority)) { - return priority; - } - } - std::vector<NPadControllerType> priority_list; - switch (priority) { - case NPadControllerType::ProController: - priority_list.push_back(NPadControllerType::JoyDual); - if (!is_docked) { - priority_list.push_back(NPadControllerType::Handheld); - } - priority_list.push_back(NPadControllerType::JoyLeft); - priority_list.push_back(NPadControllerType::JoyRight); - priority_list.push_back(NPadControllerType::Pokeball); - break; - case NPadControllerType::Handheld: - priority_list.push_back(NPadControllerType::JoyDual); - priority_list.push_back(NPadControllerType::ProController); - priority_list.push_back(NPadControllerType::JoyLeft); - priority_list.push_back(NPadControllerType::JoyRight); - priority_list.push_back(NPadControllerType::Pokeball); - break; - case NPadControllerType::JoyDual: - if (!is_docked) { - priority_list.push_back(NPadControllerType::Handheld); - } - priority_list.push_back(NPadControllerType::ProController); - priority_list.push_back(NPadControllerType::JoyLeft); - priority_list.push_back(NPadControllerType::JoyRight); - priority_list.push_back(NPadControllerType::Pokeball); - break; - case NPadControllerType::JoyLeft: - priority_list.push_back(NPadControllerType::JoyRight); - priority_list.push_back(NPadControllerType::JoyDual); - if (!is_docked) { - priority_list.push_back(NPadControllerType::Handheld); - } - priority_list.push_back(NPadControllerType::ProController); - priority_list.push_back(NPadControllerType::Pokeball); - break; - case NPadControllerType::JoyRight: - priority_list.push_back(NPadControllerType::JoyLeft); - priority_list.push_back(NPadControllerType::JoyDual); - if (!is_docked) { - priority_list.push_back(NPadControllerType::Handheld); - } - priority_list.push_back(NPadControllerType::ProController); - priority_list.push_back(NPadControllerType::Pokeball); - break; - case NPadControllerType::Pokeball: - priority_list.push_back(NPadControllerType::JoyLeft); - priority_list.push_back(NPadControllerType::JoyRight); - priority_list.push_back(NPadControllerType::JoyDual); - if (!is_docked) { - priority_list.push_back(NPadControllerType::Handheld); - } - priority_list.push_back(NPadControllerType::ProController); - break; - default: - priority_list.push_back(NPadControllerType::JoyDual); - if (!is_docked) { - priority_list.push_back(NPadControllerType::Handheld); - } - priority_list.push_back(NPadControllerType::ProController); - priority_list.push_back(NPadControllerType::JoyLeft); - priority_list.push_back(NPadControllerType::JoyRight); - priority_list.push_back(NPadControllerType::JoyDual); - break; - } - - const auto iter = std::find_if(priority_list.begin(), priority_list.end(), - [this](auto type) { return IsControllerSupported(type); }); - if (iter == priority_list.end()) { - UNIMPLEMENTED_MSG("Could not find supported controller!"); - return priority; - } - - return *iter; -} - } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 5d4c58a43..fd5c5a6eb 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -32,6 +32,10 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + // When the controller is requesting a motion update for the shared memory + void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, + std::size_t size) override; + // Called when input devices should be loaded void OnLoadInputDevices() override; @@ -74,6 +78,12 @@ public: Single = 1, }; + enum class NpadHandheldActivationMode : u64 { + Dual = 0, + Single = 1, + None = 2, + }; + enum class NPadControllerType { None, ProController, @@ -110,22 +120,34 @@ public: void SetHoldType(NpadHoldType joy_hold_type); NpadHoldType GetHoldType() const; + void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); + NpadHandheldActivationMode GetNpadHandheldActivationMode() const; + void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); - void VibrateController(const std::vector<u32>& controller_ids, + void VibrateController(const std::vector<u32>& controllers, const std::vector<Vibration>& vibrations); - std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; Vibration GetLastVibration() const; - void AddNewController(NPadControllerType controller); - void AddNewControllerAt(NPadControllerType controller, u32 npad_id); + std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; + void SignalStyleSetChangedEvent(u32 npad_id) const; + + // Adds a new controller at an index. + void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index); + // Adds a new controller at an index with connection status. + void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); - void ConnectNPad(u32 npad_id); void DisconnectNPad(u32 npad_id); + void DisconnectNPadAtIndex(std::size_t index); + void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; + bool IsSixAxisSensorAtRest() const; + void SetSixAxisEnabled(bool six_axis_status); LedPattern GetLedPattern(u32 npad_id); + bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; + void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); void SetVibrationEnabled(bool can_vibrate); bool IsVibrationEnabled() const; void ClearAllConnectedControllers(); @@ -133,6 +155,7 @@ public: void ConnectAllDisconnectedControllers(); void ClearAllControllers(); + void MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2); void StartLRAssignmentMode(); void StopLRAssignmentMode(); bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2); @@ -141,6 +164,8 @@ public: // Specifically for cheat engine and other features. u32 GetAndResetPressState(); + static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type); + static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type); static std::size_t NPadIdToIndex(u32 npad_id); static u32 IndexToNPad(std::size_t index); @@ -244,6 +269,24 @@ private: }; static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size"); + struct SixAxisStates { + s64_le timestamp{}; + INSERT_PADDING_WORDS(2); + s64_le timestamp2{}; + Common::Vec3f accel{}; + Common::Vec3f gyro{}; + Common::Vec3f rotation{}; + std::array<Common::Vec3f, 3> orientation{}; + s64_le always_one{1}; + }; + static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size"); + + struct SixAxisGeneric { + CommonHeader common{}; + std::array<SixAxisStates, 17> sixaxis{}; + }; + static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size"); + enum class ColorReadError : u32_le { ReadOk = 0, ColorDoesntExist = 1, @@ -273,6 +316,13 @@ private: }; }; + struct MotionDevice { + Common::Vec3f accel; + Common::Vec3f gyro; + Common::Vec3f rotation; + std::array<Common::Vec3f, 3> orientation; + }; + struct NPadEntry { NPadType joy_styles; NPadAssignments pad_assignment; @@ -292,9 +342,12 @@ private: NPadGeneric pokeball_states; NPadGeneric libnx; // TODO(ogniK): Find out what this actually is, libnx seems to only be // relying on this for the time being - INSERT_PADDING_BYTES( - 0x708 * - 6); // TODO(ogniK): SixAxis states, require more information before implementation + SixAxisGeneric sixaxis_full; + SixAxisGeneric sixaxis_handheld; + SixAxisGeneric sixaxis_dual_left; + SixAxisGeneric sixaxis_dual_right; + SixAxisGeneric sixaxis_left; + SixAxisGeneric sixaxis_right; NPadDevice device_type; NPadProperties properties; INSERT_PADDING_WORDS(1); @@ -309,31 +362,38 @@ private: bool is_connected; }; - void InitNewlyAddedControler(std::size_t controller_idx); + void InitNewlyAddedController(std::size_t controller_idx); bool IsControllerSupported(NPadControllerType controller) const; - NPadControllerType DecideBestController(NPadControllerType priority) const; void RequestPadStateUpdate(u32 npad_id); u32 press_state{}; NPadType style{}; std::array<NPadEntry, 10> shared_memory_entries{}; - std::array< + using ButtonArray = std::array< std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>, - 10> - buttons; - std::array< + 10>; + using StickArray = std::array< std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>, - 10> - sticks; + 10>; + using MotionArray = std::array< + std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTION_HID>, + 10>; + ButtonArray buttons; + StickArray sticks; + MotionArray motions; std::vector<u32> supported_npad_id_types{}; NpadHoldType hold_type{NpadHoldType::Vertical}; + NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; // Each controller should have their own styleset changed event std::array<Kernel::EventPair, 10> styleset_changed_events; Vibration last_processed_vibration{}; std::array<ControllerHolder, 10> connected_controllers{}; + std::array<bool, 10> unintended_home_button_input_protection{}; GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; bool can_controllers_vibrate{true}; + bool sixaxis_sensors_enabled{true}; + bool sixaxis_at_rest{true}; std::array<ControllerPad, 10> npad_pad_states{}; bool is_in_lr_assignment_mode{false}; Core::System& system; diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index e326f8f5c..0df395e85 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -40,9 +40,14 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin cur_entry.sampling_number = last_entry.sampling_number + 1; cur_entry.sampling_number2 = cur_entry.sampling_number; - const auto [x, y, pressed] = touch_device->GetStatus(); + bool pressed = false; + float x, y; + std::tie(x, y, pressed) = touch_device->GetStatus(); auto& touch_entry = cur_entry.states[0]; touch_entry.attribute.raw = 0; + if (!pressed && touch_btn_device) { + std::tie(x, y, pressed) = touch_btn_device->GetStatus(); + } if (pressed && Settings::values.touchscreen.enabled) { touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); @@ -63,5 +68,10 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin void Controller_Touchscreen::OnLoadInputDevices() { touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device); + if (Settings::values.use_touch_from_button) { + touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); + } else { + touch_btn_device.reset(); + } } } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index a1d97269e..4d9042adc 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -68,6 +68,7 @@ private: "TouchScreenSharedMemory is an invalid size"); TouchScreenSharedMemory shared_memory{}; std::unique_ptr<Input::TouchDevice> touch_device; + std::unique_ptr<Input::TouchDevice> touch_btn_device; s64_le last_touch{}; }; } // namespace Service::HID |