Using dual joycons as the default controller

Reason for the change is to allow both docked and undocked mode to work
master
David Marcec 2018-10-18 00:11:47 +07:00
parent 98b760c645
commit 8144fa42bd
3 changed files with 59 additions and 77 deletions

@ -27,7 +27,7 @@ constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
constexpr s32 HID_JOYSTICK_MAX = 0x7fff; constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
constexpr s32 HID_JOYSTICK_MIN = -0x7fff; constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
constexpr std::size_t NPAD_OFFSET = 0x9A00; constexpr std::size_t NPAD_OFFSET = 0x9A00;
constexpr u32 BATTERY_FULL = 2;
enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
Controller_NPad::Controller_NPad() = default; 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.device_type.handheld.Assign(1);
controller.pad_assignment = NPadAssignments::Dual; controller.pad_assignment = NPadAssignments::Dual;
break; 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: case NPadControllerType::JoyLeft:
controller.joy_styles.joycon_left.Assign(1); controller.joy_styles.joycon_left.Assign(1);
controller.device_type.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.device_type.joycon_right.Assign(1);
controller.pad_assignment = NPadAssignments::Dual; controller.pad_assignment = NPadAssignments::Dual;
break; break;
case NPadControllerType::Tabletop:
UNIMPLEMENTED_MSG("Tabletop is not implemented");
break;
case NPadControllerType::Pokeball: case NPadControllerType::Pokeball:
controller.joy_styles.pokeball.Assign(1); controller.joy_styles.pokeball.Assign(1);
controller.device_type.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.right_color.button_color = JOYCON_BUTTONS_NEON_RED;
controller.properties.is_vertical.Assign(1); // TODO(ogniK): Swap joycons orientations 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() { void Controller_NPad::OnInit() {
@ -106,7 +114,7 @@ void Controller_NPad::OnInit() {
supported_npad_id_types.resize(npad_id_list.size()); supported_npad_id_types.resize(npad_id_list.size());
std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
npad_id_list.size() * sizeof(u32)); 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) { if (hold_type == NpadHoldType::Horizontal) {
// TODO(ogniK): Remap buttons for different orientations // TODO(ogniK): Remap buttons for different orientations
} }
libnx_entry.connection_status.raw = 0;
switch (controller_type) { switch (controller_type) {
case NPadControllerType::Handheld: case NPadControllerType::Handheld:
handheld_entry.connection_status.raw = 0;
handheld_entry.connection_status.IsConnected.Assign(1); handheld_entry.connection_status.IsConnected.Assign(1);
if (!Settings::values.use_docked_mode) { if (!Settings::values.use_docked_mode) {
handheld_entry.connection_status.IsWired.Assign(1); 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.l_stick = lstick_entry;
handheld_entry.r_stick = rstick_entry; handheld_entry.r_stick = rstick_entry;
break; 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: case NPadControllerType::JoyLeft:
left_entry.connection_status.raw = 0;
left_entry.connection_status.IsConnected.Assign(1); left_entry.connection_status.IsConnected.Assign(1);
left_entry.pad_states.raw = pad_state.raw; left_entry.pad_states.raw = pad_state.raw;
left_entry.l_stick = lstick_entry; left_entry.l_stick = lstick_entry;
left_entry.r_stick = rstick_entry; left_entry.r_stick = rstick_entry;
break; break;
case NPadControllerType::JoyRight: case NPadControllerType::JoyRight:
right_entry.connection_status.raw = 0;
right_entry.connection_status.IsConnected.Assign(1); right_entry.connection_status.IsConnected.Assign(1);
right_entry.pad_states.raw = pad_state.raw; right_entry.pad_states.raw = pad_state.raw;
right_entry.l_stick = lstick_entry; right_entry.l_stick = lstick_entry;
right_entry.r_stick = rstick_entry; right_entry.r_stick = rstick_entry;
break; 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: case NPadControllerType::Pokeball:
pokeball_entry.connection_status.raw = 0;
pokeball_entry.connection_status.IsConnected.Assign(1); pokeball_entry.connection_status.IsConnected.Assign(1);
pokeball_entry.connection_status.IsWired.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; pokeball_entry.r_stick = rstick_entry;
break; break;
case NPadControllerType::ProController: 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.pad_states.raw = pad_state.raw;
main_controller.l_stick = lstick_entry; main_controller.l_stick = lstick_entry;
main_controller.r_stick = rstick_entry; main_controller.r_stick = rstick_entry;
main_controller.connection_status.IsConnected.Assign(1);
main_controller.connection_status.IsWired.Assign(1);
break; break;
} }
// LibNX exclusively uses this section, so we always update it since LibNX doesn't activate // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
// any controllers. // 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.pad_states.raw = pad_state.raw;
libnx_entry.l_stick = lstick_entry; libnx_entry.l_stick = lstick_entry;
libnx_entry.r_stick = rstick_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.clear();
supported_npad_id_types.resize(length / sizeof(u32)); supported_npad_id_types.resize(length / sizeof(u32));
std::memcpy(supported_npad_id_types.data(), data, length); 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) { 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++) { for (std::size_t i = 0; i < controller_ids.size(); i++) {
std::size_t controller_pos = i; std::size_t controller_pos = i;
if (controller_pos == 32) // Handheld controller conversion
if (controller_pos == 32) {
controller_pos = 8; controller_pos = 8;
if (controller_pos == 16) }
// Unknown controller conversion
if (controller_pos == 16) {
controller_pos = 9; controller_pos = 9;
}
if (connected_controllers[controller_pos].is_connected) { if (connected_controllers[controller_pos].is_connected) {
// TODO(ogniK): Vibrate the physical controller // 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 { Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
return last_processed_vibration; return last_processed_vibration;
} }
void Controller_NPad::AddNewController(NPadControllerType controller, bool is_handheld_variant) { void Controller_NPad::AddNewController(NPadControllerType controller) {
if (is_handheld_variant) { if (controller == NPadControllerType::Handheld) {
connected_controllers[8] = {controller, true}; connected_controllers[8] = {controller, true};
InitNewlyAddedControler(8); InitNewlyAddedControler(8);
return; return;
@ -438,13 +426,4 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
can_controllers_vibrate = 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 } // namespace Service::HID

@ -65,9 +65,9 @@ public:
None, None,
ProController, ProController,
Handheld, Handheld,
JoyDual,
JoyLeft, JoyLeft,
JoyRight, JoyRight,
Tabletop,
Pokeball, Pokeball,
}; };
@ -105,13 +105,12 @@ public:
Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const; Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const;
Vibration GetLastVibration() const; Vibration GetLastVibration() const;
void AddNewController(NPadControllerType controller, bool is_handheld_variant = false); void AddNewController(NPadControllerType controller);
void ConnectNPad(u32 npad_id); void ConnectNPad(u32 npad_id);
void DisconnectNPad(u32 npad_id); void DisconnectNPad(u32 npad_id);
LedPattern GetLedPattern(u32 npad_id); LedPattern GetLedPattern(u32 npad_id);
void SetVibrationEnabled(bool can_vibrate); void SetVibrationEnabled(bool can_vibrate);
void SetHandheldActiviationMode(u32 mode);
private: private:
struct CommonHeader { struct CommonHeader {
@ -181,6 +180,10 @@ private:
u32_le raw{}; u32_le raw{};
BitField<0, 1, u32_le> IsConnected; BitField<0, 1, u32_le> IsConnected;
BitField<1, 1, u32_le> IsWired; 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"); static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size");
@ -212,6 +215,8 @@ private:
s64_le raw{}; s64_le raw{};
BitField<11, 1, s64_le> is_vertical; BitField<11, 1, s64_le> is_vertical;
BitField<12, 1, s64_le> is_horizontal; 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 6); // TODO(ogniK): SixAxis states, require more information before implementation
NPadDevice device_type; NPadDevice device_type;
NPadProperties properties; NPadProperties properties;
INSERT_PADDING_WORDS(4); INSERT_PADDING_WORDS(1);
INSERT_PADDING_BYTES(0x60); std::array<u32, 3> battery_level;
INSERT_PADDING_BYTES(0x5c);
INSERT_PADDING_BYTES(0xdf8); INSERT_PADDING_BYTES(0xdf8);
}; };
static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); 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}; 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{}; std::array<ControllerHolder, 10> connected_controllers{};
bool can_controllers_vibrate{true}; bool can_controllers_vibrate{true};
void CheckForHandheldVariant();
void InitNewlyAddedControler(std::size_t controller_idx); void InitNewlyAddedControler(std::size_t controller_idx);
}; };

@ -284,7 +284,7 @@ public:
private: private:
std::shared_ptr<IAppletResource> applet_resource; std::shared_ptr<IAppletResource> applet_resource;
#pragma optimize("", off)
void CreateAppletResource(Kernel::HLERequestContext& ctx) { void CreateAppletResource(Kernel::HLERequestContext& ctx) {
if (applet_resource == nullptr) { if (applet_resource == nullptr) {
applet_resource = std::make_shared<IAppletResource>(); applet_resource = std::make_shared<IAppletResource>();
@ -545,8 +545,6 @@ private:
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_HID, "(STUBBED) called"); LOG_WARNING(Service_HID, "(STUBBED) called");
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetHandheldActiviationMode(mode);
} }
void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {