|
|
|
@ -21,13 +21,9 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff; |
|
|
|
constexpr s32 HID_JOYSTICK_MIN = -0x7fff; |
|
|
|
constexpr std::size_t NPAD_OFFSET = 0x9A00; |
|
|
|
constexpr u32 BATTERY_FULL = 2; |
|
|
|
constexpr u32 NPAD_HANDHELD = 32; |
|
|
|
constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
|
|
|
|
constexpr u32 MAX_NPAD_ID = 7; |
|
|
|
constexpr Controller_NPad::NPadControllerType PREFERRED_CONTROLLER = |
|
|
|
Controller_NPad::NPadControllerType::JoyDual; |
|
|
|
constexpr std::array<u32, 10> npad_id_list{ |
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, 32, 16, |
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN, |
|
|
|
}; |
|
|
|
|
|
|
|
enum class JoystickId : std::size_t { |
|
|
|
@ -51,7 +47,7 @@ static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::Contr |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static std::size_t NPadIdToIndex(u32 npad_id) { |
|
|
|
std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) { |
|
|
|
switch (npad_id) { |
|
|
|
case 0: |
|
|
|
case 1: |
|
|
|
@ -74,6 +70,27 @@ static std::size_t NPadIdToIndex(u32 npad_id) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
u32 Controller_NPad::IndexToNPad(std::size_t index) { |
|
|
|
switch (index) { |
|
|
|
case 0: |
|
|
|
case 1: |
|
|
|
case 2: |
|
|
|
case 3: |
|
|
|
case 4: |
|
|
|
case 5: |
|
|
|
case 6: |
|
|
|
case 7: |
|
|
|
return static_cast<u32>(index); |
|
|
|
case 8: |
|
|
|
return NPAD_HANDHELD; |
|
|
|
case 9: |
|
|
|
return NPAD_UNKNOWN; |
|
|
|
default: |
|
|
|
UNIMPLEMENTED_MSG("Unknown npad index {}", index); |
|
|
|
return 0; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
Controller_NPad::Controller_NPad() = default; |
|
|
|
Controller_NPad::~Controller_NPad() = default; |
|
|
|
|
|
|
|
@ -190,7 +207,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(PREFERRED_CONTROLLER); |
|
|
|
AddNewController(NPadControllerType::JoyDual); |
|
|
|
} |
|
|
|
|
|
|
|
for (std::size_t i = 0; i < connected_controllers.size(); ++i) { |
|
|
|
@ -391,9 +408,9 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { |
|
|
|
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; |
|
|
|
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; |
|
|
|
break; |
|
|
|
case NPadControllerType::JoyLeft: |
|
|
|
left_entry.connection_status.raw = 0; |
|
|
|
@ -461,23 +478,24 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { |
|
|
|
if (!controller.is_connected) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (!IsControllerSupported(PREFERRED_CONTROLLER)) { |
|
|
|
const auto best_type = DecideBestController(PREFERRED_CONTROLLER); |
|
|
|
const bool is_handheld = (best_type == NPadControllerType::Handheld || |
|
|
|
PREFERRED_CONTROLLER == NPadControllerType::Handheld); |
|
|
|
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(best_type); |
|
|
|
AddNewController(requested_controller); |
|
|
|
} else { |
|
|
|
controller.type = best_type; |
|
|
|
controller.type = requested_controller; |
|
|
|
InitNewlyAddedControler(i); |
|
|
|
} |
|
|
|
had_controller_update = true; |
|
|
|
} |
|
|
|
} |
|
|
|
if (had_controller_update) { |
|
|
|
styleset_changed_event->Signal(); |
|
|
|
if (had_controller_update) { |
|
|
|
styleset_changed_event->Signal(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -530,50 +548,6 @@ Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { |
|
|
|
return last_processed_vibration; |
|
|
|
} |
|
|
|
|
|
|
|
std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) { |
|
|
|
switch (npad_id) { |
|
|
|
case 0: |
|
|
|
case 1: |
|
|
|
case 2: |
|
|
|
case 3: |
|
|
|
case 4: |
|
|
|
case 5: |
|
|
|
case 6: |
|
|
|
case 7: |
|
|
|
return static_cast<std::size_t>(npad_id); |
|
|
|
case 8: |
|
|
|
case 32: |
|
|
|
return 8; |
|
|
|
case 9: |
|
|
|
case 16: |
|
|
|
return 9; |
|
|
|
default: |
|
|
|
UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
u32 Controller_NPad::IndexToNPad(std::size_t index) { |
|
|
|
switch (index) { |
|
|
|
case 0: |
|
|
|
case 1: |
|
|
|
case 2: |
|
|
|
case 3: |
|
|
|
case 4: |
|
|
|
case 5: |
|
|
|
case 6: |
|
|
|
case 7: |
|
|
|
return static_cast<u32>(index); |
|
|
|
case 8: |
|
|
|
return 32; |
|
|
|
case 9: |
|
|
|
return 16; |
|
|
|
default: |
|
|
|
UNIMPLEMENTED_MSG("Unknown npad index {}", index); |
|
|
|
return 0; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
void Controller_NPad::AddNewController(NPadControllerType controller) { |
|
|
|
controller = DecideBestController(controller); |
|
|
|
if (controller == NPadControllerType::Handheld) { |
|
|
|
@ -596,13 +570,13 @@ void Controller_NPad::AddNewController(NPadControllerType controller) { |
|
|
|
void Controller_NPad::AddNewControllerAt(NPadControllerType controller, u32 npad_id) { |
|
|
|
controller = DecideBestController(controller); |
|
|
|
if (controller == NPadControllerType::Handheld) { |
|
|
|
connected_controllers[8] = {controller, true}; |
|
|
|
InitNewlyAddedControler(8); |
|
|
|
connected_controllers[NPadIdToIndex(NPAD_HANDHELD)] = {controller, true}; |
|
|
|
InitNewlyAddedControler(NPadIdToIndex(NPAD_HANDHELD)); |
|
|
|
return; |
|
|
|
} |
|
|
|
const size_t controller_id = static_cast<std::size_t>(npad_id); |
|
|
|
connected_controllers[controller_id] = {controller, true}; |
|
|
|
InitNewlyAddedControler(controller_id); |
|
|
|
|
|
|
|
connected_controllers[npad_id] = {controller, true}; |
|
|
|
InitNewlyAddedControler(npad_id); |
|
|
|
} |
|
|
|
|
|
|
|
void Controller_NPad::ConnectNPad(u32 npad_id) { |
|
|
|
@ -613,97 +587,11 @@ void Controller_NPad::DisconnectNPad(u32 npad_id) { |
|
|
|
connected_controllers[NPadIdToIndex(npad_id)].is_connected = false; |
|
|
|
} |
|
|
|
|
|
|
|
Controller_NPad::NPadControllerType Controller_NPad::DecideBestController( |
|
|
|
NPadControllerType priority) { |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
for (const auto controller_type : priority_list) { |
|
|
|
if (IsControllerSupported(controller_type)) { |
|
|
|
return controller_type; |
|
|
|
} |
|
|
|
} |
|
|
|
UNIMPLEMENTED_MSG("Could not find supported controller!"); |
|
|
|
return priority; |
|
|
|
} |
|
|
|
|
|
|
|
bool Controller_NPad::IsControllerSupported(NPadControllerType controller) { |
|
|
|
if (controller == NPadControllerType::Handheld) { |
|
|
|
// Handheld is not even a supported type, lets stop here
|
|
|
|
if (std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), 32) == |
|
|
|
supported_npad_id_types.end()) { |
|
|
|
if (std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), |
|
|
|
NPAD_HANDHELD) == supported_npad_id_types.end()) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Handheld should not be supported in docked mode
|
|
|
|
@ -761,13 +649,12 @@ void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { |
|
|
|
} |
|
|
|
|
|
|
|
void Controller_NPad::ClearAllConnectedControllers() { |
|
|
|
std::for_each(connected_controllers.begin(), connected_controllers.end(), |
|
|
|
[](ControllerHolder& controller) { |
|
|
|
if (controller.is_connected && controller.type != NPadControllerType::None) { |
|
|
|
controller.type = NPadControllerType::None; |
|
|
|
controller.is_connected = false; |
|
|
|
} |
|
|
|
}); |
|
|
|
for (auto& controller : connected_controllers) { |
|
|
|
if (controller.is_connected && controller.type != NPadControllerType::None) { |
|
|
|
controller.type = NPadControllerType::None; |
|
|
|
controller.is_connected = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
void Controller_NPad::DisconnectAllConnectedControllers() { |
|
|
|
std::for_each(connected_controllers.begin(), connected_controllers.end(), |
|
|
|
|