mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-10-30 23:49:01 -05:00 
			
		
		
		
	Using dual joycons as the default controller
Reason for the change is to allow both docked and undocked mode to work
This commit is contained in:
		| @@ -27,7 +27,7 @@ constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E; | ||||
| constexpr s32 HID_JOYSTICK_MAX = 0x7fff; | ||||
| constexpr s32 HID_JOYSTICK_MIN = -0x7fff; | ||||
| constexpr std::size_t NPAD_OFFSET = 0x9A00; | ||||
|  | ||||
| constexpr u32 BATTERY_FULL = 2; | ||||
| enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; | ||||
|  | ||||
| Controller_NPad::Controller_NPad() = default; | ||||
| @@ -46,6 +46,12 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | ||||
|         controller.device_type.handheld.Assign(1); | ||||
|         controller.pad_assignment = NPadAssignments::Dual; | ||||
|         break; | ||||
|     case NPadControllerType::JoyDual: | ||||
|         controller.joy_styles.joycon_dual.Assign(1); | ||||
|         controller.device_type.joycon_left.Assign(1); | ||||
|         controller.device_type.joycon_right.Assign(1); | ||||
|         controller.pad_assignment = NPadAssignments::Dual; | ||||
|         break; | ||||
|     case NPadControllerType::JoyLeft: | ||||
|         controller.joy_styles.joycon_left.Assign(1); | ||||
|         controller.device_type.joycon_left.Assign(1); | ||||
| @@ -56,9 +62,6 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | ||||
|         controller.device_type.joycon_right.Assign(1); | ||||
|         controller.pad_assignment = NPadAssignments::Dual; | ||||
|         break; | ||||
|     case NPadControllerType::Tabletop: | ||||
|         UNIMPLEMENTED_MSG("Tabletop is not implemented"); | ||||
|         break; | ||||
|     case NPadControllerType::Pokeball: | ||||
|         controller.joy_styles.pokeball.Assign(1); | ||||
|         controller.device_type.pokeball.Assign(1); | ||||
| @@ -82,6 +85,11 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | ||||
|     controller.right_color.button_color = JOYCON_BUTTONS_NEON_RED; | ||||
|  | ||||
|     controller.properties.is_vertical.Assign(1); // TODO(ogniK): Swap joycons orientations | ||||
|     controller.properties.use_plus.Assign(1); | ||||
|     controller.properties.use_minus.Assign(1); | ||||
|     controller.battery_level[0] = BATTERY_FULL; | ||||
|     controller.battery_level[1] = BATTERY_FULL; | ||||
|     controller.battery_level[2] = BATTERY_FULL; | ||||
| } | ||||
|  | ||||
| void Controller_NPad::OnInit() { | ||||
| @@ -106,7 +114,7 @@ void Controller_NPad::OnInit() { | ||||
|         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::Handheld); | ||||
|         AddNewController(NPadControllerType::JoyDual); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -218,9 +226,11 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { | ||||
|         if (hold_type == NpadHoldType::Horizontal) { | ||||
|             // TODO(ogniK): Remap buttons for different orientations | ||||
|         } | ||||
|         libnx_entry.connection_status.raw = 0; | ||||
|  | ||||
|         switch (controller_type) { | ||||
|         case NPadControllerType::Handheld: | ||||
|             handheld_entry.connection_status.raw = 0; | ||||
|             handheld_entry.connection_status.IsConnected.Assign(1); | ||||
|             if (!Settings::values.use_docked_mode) { | ||||
|                 handheld_entry.connection_status.IsWired.Assign(1); | ||||
| @@ -229,26 +239,39 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { | ||||
|             handheld_entry.l_stick = lstick_entry; | ||||
|             handheld_entry.r_stick = rstick_entry; | ||||
|             break; | ||||
|         case NPadControllerType::JoyDual: | ||||
|             dual_entry.connection_status.raw = 0; | ||||
|  | ||||
|             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_states.raw = pad_state.raw; | ||||
|             dual_entry.l_stick = lstick_entry; | ||||
|             dual_entry.r_stick = rstick_entry; | ||||
|         case NPadControllerType::JoyLeft: | ||||
|             left_entry.connection_status.raw = 0; | ||||
|  | ||||
|             left_entry.connection_status.IsConnected.Assign(1); | ||||
|             left_entry.pad_states.raw = pad_state.raw; | ||||
|             left_entry.l_stick = lstick_entry; | ||||
|             left_entry.r_stick = rstick_entry; | ||||
|             break; | ||||
|         case NPadControllerType::JoyRight: | ||||
|             right_entry.connection_status.raw = 0; | ||||
|  | ||||
|             right_entry.connection_status.IsConnected.Assign(1); | ||||
|             right_entry.pad_states.raw = pad_state.raw; | ||||
|             right_entry.l_stick = lstick_entry; | ||||
|             right_entry.r_stick = rstick_entry; | ||||
|             break; | ||||
|         case NPadControllerType::Tabletop: | ||||
|             // TODO(ogniK): Figure out how to add proper tabletop support | ||||
|             dual_entry.pad_states.raw = pad_state.raw; | ||||
|             dual_entry.l_stick = lstick_entry; | ||||
|             dual_entry.r_stick = rstick_entry; | ||||
|             dual_entry.connection_status.IsConnected.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); | ||||
|  | ||||
| @@ -257,18 +280,18 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { | ||||
|             pokeball_entry.r_stick = rstick_entry; | ||||
|             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_states.raw = pad_state.raw; | ||||
|             main_controller.l_stick = lstick_entry; | ||||
|             main_controller.r_stick = rstick_entry; | ||||
|             main_controller.connection_status.IsConnected.Assign(1); | ||||
|             main_controller.connection_status.IsWired.Assign(1); | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate | ||||
|         // any controllers. | ||||
|         libnx_entry.connection_status.IsConnected.Assign(1); | ||||
|         libnx_entry.connection_status.IsWired.Assign(1); | ||||
|         libnx_entry.pad_states.raw = pad_state.raw; | ||||
|         libnx_entry.l_stick = lstick_entry; | ||||
|         libnx_entry.r_stick = rstick_entry; | ||||
| @@ -290,44 +313,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); | ||||
|     CheckForHandheldVariant(); | ||||
| } | ||||
| #pragma optimize("", off) | ||||
| void Controller_NPad::CheckForHandheldVariant() { | ||||
|     // As some games expect us to use the variant of handheld mode and some games don't. It's | ||||
|     // consistent that games set the npad ids in order of priority. We can just swap the controller | ||||
|     // ids on the fly then if we're in handheld mode | ||||
|     if (std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), 32) != | ||||
|         supported_npad_id_types.end()) { | ||||
|         const auto& first_controller = connected_controllers.front(); | ||||
|         if (first_controller.is_connected && | ||||
|             first_controller.type == NPadControllerType::Handheld) { | ||||
|             DisconnectNPad(0); | ||||
|             AddNewController(NPadControllerType::Handheld, true); | ||||
|         } | ||||
|     } else { | ||||
|         if (connected_controllers[8].is_connected) { | ||||
|             DisconnectNPad(8); | ||||
|             AddNewController(NPadControllerType::Handheld); | ||||
|         } | ||||
|     } | ||||
|     /* | ||||
|     if (supported_npad_id_types.size() > 0) { | ||||
|         const auto& first_controller = supported_npad_id_types.front(); | ||||
|         if (first_controller == 32 && !connected_controllers[8].is_connected) { | ||||
|             const auto& first_controller = connected_controllers.front(); | ||||
|             if (first_controller.is_connected && | ||||
|                 first_controller.type == NPadControllerType::Handheld) { | ||||
|                 DisconnectNPad(0); | ||||
|                 AddNewController(NPadControllerType::Handheld, true); | ||||
|             } | ||||
|         } else if (first_controller != 32 && connected_controllers[8].is_connected) { | ||||
|             if (!connected_controllers[0].is_connected) { | ||||
|                 DisconnectNPad(8); | ||||
|                 AddNewController(NPadControllerType::Handheld); | ||||
|             } | ||||
|         } | ||||
|     }*/ | ||||
| } | ||||
|  | ||||
| const void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { | ||||
| @@ -358,11 +343,14 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, | ||||
|     } | ||||
|     for (std::size_t i = 0; i < controller_ids.size(); i++) { | ||||
|         std::size_t controller_pos = i; | ||||
|         if (controller_pos == 32) | ||||
|         // Handheld controller conversion | ||||
|         if (controller_pos == 32) { | ||||
|             controller_pos = 8; | ||||
|         if (controller_pos == 16) | ||||
|         } | ||||
|         // Unknown controller conversion | ||||
|         if (controller_pos == 16) { | ||||
|             controller_pos = 9; | ||||
|  | ||||
|         } | ||||
|         if (connected_controllers[controller_pos].is_connected) { | ||||
|             // TODO(ogniK): Vibrate the physical controller | ||||
|         } | ||||
| @@ -378,8 +366,8 @@ Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() cons | ||||
| Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { | ||||
|     return last_processed_vibration; | ||||
| } | ||||
| void Controller_NPad::AddNewController(NPadControllerType controller, bool is_handheld_variant) { | ||||
|     if (is_handheld_variant) { | ||||
| void Controller_NPad::AddNewController(NPadControllerType controller) { | ||||
|     if (controller == NPadControllerType::Handheld) { | ||||
|         connected_controllers[8] = {controller, true}; | ||||
|         InitNewlyAddedControler(8); | ||||
|         return; | ||||
| @@ -438,13 +426,4 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { | ||||
| void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { | ||||
|     can_controllers_vibrate = can_vibrate; | ||||
| } | ||||
|  | ||||
| void Controller_NPad::SetHandheldActiviationMode(u32 mode) { | ||||
|     const auto& first_controller = connected_controllers.front(); | ||||
|     if (!first_controller.is_connected || connected_controllers[8].is_connected) { | ||||
|         return; | ||||
|     } | ||||
|     DisconnectNPad(0); | ||||
|     AddNewController(NPadControllerType::Handheld, true); | ||||
| } | ||||
| } // namespace Service::HID | ||||
|   | ||||
| @@ -65,9 +65,9 @@ public: | ||||
|         None, | ||||
|         ProController, | ||||
|         Handheld, | ||||
|         JoyDual, | ||||
|         JoyLeft, | ||||
|         JoyRight, | ||||
|         Tabletop, | ||||
|         Pokeball, | ||||
|     }; | ||||
|  | ||||
| @@ -105,13 +105,12 @@ public: | ||||
|     Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const; | ||||
|     Vibration GetLastVibration() const; | ||||
|  | ||||
|     void AddNewController(NPadControllerType controller, bool is_handheld_variant = false); | ||||
|     void AddNewController(NPadControllerType controller); | ||||
|  | ||||
|     void ConnectNPad(u32 npad_id); | ||||
|     void DisconnectNPad(u32 npad_id); | ||||
|     LedPattern GetLedPattern(u32 npad_id); | ||||
|     void SetVibrationEnabled(bool can_vibrate); | ||||
|     void SetHandheldActiviationMode(u32 mode); | ||||
|  | ||||
| private: | ||||
|     struct CommonHeader { | ||||
| @@ -181,6 +180,10 @@ private: | ||||
|             u32_le raw{}; | ||||
|             BitField<0, 1, u32_le> IsConnected; | ||||
|             BitField<1, 1, u32_le> IsWired; | ||||
|             BitField<2, 1, u32_le> IsLeftJoyConnected; | ||||
|             BitField<3, 1, u32_le> IsLeftJoyWired; | ||||
|             BitField<4, 1, u32_le> IsRightJoyConnected; | ||||
|             BitField<5, 1, u32_le> IsRightJoyWired; | ||||
|         }; | ||||
|     }; | ||||
|     static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); | ||||
| @@ -212,6 +215,8 @@ private: | ||||
|             s64_le raw{}; | ||||
|             BitField<11, 1, s64_le> is_vertical; | ||||
|             BitField<12, 1, s64_le> is_horizontal; | ||||
|             BitField<13, 1, s64_le> use_plus; | ||||
|             BitField<14, 1, s64_le> use_minus; | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
| @@ -252,8 +257,9 @@ private: | ||||
|             6); // TODO(ogniK): SixAxis states, require more information before implementation | ||||
|         NPadDevice device_type; | ||||
|         NPadProperties properties; | ||||
|         INSERT_PADDING_WORDS(4); | ||||
|         INSERT_PADDING_BYTES(0x60); | ||||
|         INSERT_PADDING_WORDS(1); | ||||
|         std::array<u32, 3> battery_level; | ||||
|         INSERT_PADDING_BYTES(0x5c); | ||||
|         INSERT_PADDING_BYTES(0xdf8); | ||||
|     }; | ||||
|     static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); | ||||
| @@ -276,7 +282,6 @@ private: | ||||
|     static constexpr std::array<u32, 10> npad_id_list{0, 1, 2, 3, 4, 5, 6, 7, 32, 16}; | ||||
|     std::array<ControllerHolder, 10> connected_controllers{}; | ||||
|     bool can_controllers_vibrate{true}; | ||||
|     void CheckForHandheldVariant(); | ||||
|  | ||||
|     void InitNewlyAddedControler(std::size_t controller_idx); | ||||
| }; | ||||
|   | ||||
| @@ -284,7 +284,7 @@ public: | ||||
|  | ||||
| private: | ||||
|     std::shared_ptr<IAppletResource> applet_resource; | ||||
| #pragma optimize("", off) | ||||
|  | ||||
|     void CreateAppletResource(Kernel::HLERequestContext& ctx) { | ||||
|         if (applet_resource == nullptr) { | ||||
|             applet_resource = std::make_shared<IAppletResource>(); | ||||
| @@ -545,8 +545,6 @@ private: | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         LOG_WARNING(Service_HID, "(STUBBED) called"); | ||||
|         applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||||
|             .SetHandheldActiviationMode(mode); | ||||
|     } | ||||
|  | ||||
|     void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 David Marcec
					David Marcec