2018-10-05 16:23:21 +02:00
|
|
|
// Copyright 2018 yuzu emulator team
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2018-10-06 05:14:42 +02:00
|
|
|
#include <algorithm>
|
2018-10-05 16:23:21 +02:00
|
|
|
#include <array>
|
2018-10-06 05:14:42 +02:00
|
|
|
#include <cstring>
|
2018-10-05 16:23:21 +02:00
|
|
|
#include "common/assert.h"
|
|
|
|
#include "common/bit_field.h"
|
|
|
|
#include "common/common_types.h"
|
2018-10-06 05:14:42 +02:00
|
|
|
#include "common/logging/log.h"
|
2018-10-05 16:23:21 +02:00
|
|
|
#include "core/core.h"
|
|
|
|
#include "core/core_timing.h"
|
|
|
|
#include "core/frontend/input.h"
|
2018-11-27 00:34:07 +01:00
|
|
|
#include "core/hle/kernel/kernel.h"
|
|
|
|
#include "core/hle/kernel/readable_event.h"
|
|
|
|
#include "core/hle/kernel/writable_event.h"
|
2018-10-05 16:23:21 +02:00
|
|
|
#include "core/hle/service/hid/controllers/npad.h"
|
|
|
|
#include "core/settings.h"
|
|
|
|
|
|
|
|
namespace Service::HID {
|
|
|
|
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
|
2019-10-05 00:57:50 +02:00
|
|
|
[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
|
2018-10-06 05:14:42 +02:00
|
|
|
constexpr std::size_t NPAD_OFFSET = 0x9A00;
|
2018-10-17 15:11:47 +02:00
|
|
|
constexpr u32 BATTERY_FULL = 2;
|
2018-10-20 06:07:18 +02:00
|
|
|
constexpr u32 MAX_NPAD_ID = 7;
|
2020-07-22 16:39:53 +02:00
|
|
|
constexpr std::size_t HANDHELD_INDEX = 8;
|
2018-10-18 02:41:45 +02:00
|
|
|
constexpr std::array<u32, 10> npad_id_list{
|
2018-11-03 17:55:39 +01:00
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN,
|
2018-10-18 02:41:45 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
enum class JoystickId : std::size_t {
|
|
|
|
Joystick_Left,
|
|
|
|
Joystick_Right,
|
|
|
|
};
|
2018-10-05 16:23:21 +02:00
|
|
|
|
2020-07-22 16:39:53 +02:00
|
|
|
Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad(
|
|
|
|
Settings::ControllerType type) {
|
2018-11-02 03:03:17 +01:00
|
|
|
switch (type) {
|
|
|
|
case Settings::ControllerType::ProController:
|
2020-07-22 16:39:53 +02:00
|
|
|
return NPadControllerType::ProController;
|
|
|
|
case Settings::ControllerType::DualJoyconDetached:
|
|
|
|
return NPadControllerType::JoyDual;
|
2018-11-02 03:03:17 +01:00
|
|
|
case Settings::ControllerType::LeftJoycon:
|
2020-07-22 16:39:53 +02:00
|
|
|
return NPadControllerType::JoyLeft;
|
2018-11-02 03:03:17 +01:00
|
|
|
case Settings::ControllerType::RightJoycon:
|
2020-07-22 16:39:53 +02:00
|
|
|
return NPadControllerType::JoyRight;
|
|
|
|
case Settings::ControllerType::Handheld:
|
|
|
|
return NPadControllerType::Handheld;
|
2018-11-02 03:03:17 +01:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
2020-07-22 16:39:53 +02:00
|
|
|
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;
|
2018-11-02 03:03:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-03 17:55:39 +01:00
|
|
|
std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) {
|
2018-11-16 05:31:27 +01:00
|
|
|
switch (npad_id) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
case 3:
|
|
|
|
case 4:
|
|
|
|
case 5:
|
|
|
|
case 6:
|
|
|
|
case 7:
|
|
|
|
return npad_id;
|
2020-07-22 16:39:53 +02:00
|
|
|
case HANDHELD_INDEX:
|
2018-11-16 05:31:27 +01:00
|
|
|
case NPAD_HANDHELD:
|
2020-07-22 16:39:53 +02:00
|
|
|
return HANDHELD_INDEX;
|
2018-11-16 05:31:27 +01:00
|
|
|
case 9:
|
|
|
|
case NPAD_UNKNOWN:
|
|
|
|
return 9;
|
|
|
|
default:
|
|
|
|
UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-03 17:55:39 +01:00
|
|
|
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);
|
2020-07-22 16:39:53 +02:00
|
|
|
case HANDHELD_INDEX:
|
2018-11-03 17:55:39 +01:00
|
|
|
return NPAD_HANDHELD;
|
|
|
|
case 9:
|
|
|
|
return NPAD_UNKNOWN;
|
|
|
|
default:
|
|
|
|
UNIMPLEMENTED_MSG("Unknown npad index {}", index);
|
|
|
|
return 0;
|
2020-08-14 15:04:44 +02:00
|
|
|
}
|
2018-11-03 17:55:39 +01:00
|
|
|
}
|
|
|
|
|
2019-09-22 08:41:34 +02:00
|
|
|
Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
|
2018-10-18 02:34:25 +02:00
|
|
|
Controller_NPad::~Controller_NPad() = default;
|
2018-10-05 16:23:21 +02:00
|
|
|
|
2020-07-22 16:39:53 +02:00
|
|
|
void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
|
2018-10-07 11:17:04 +02:00
|
|
|
const auto controller_type = connected_controllers[controller_idx].type;
|
2018-10-05 16:23:21 +02:00
|
|
|
auto& controller = shared_memory_entries[controller_idx];
|
|
|
|
if (controller_type == NPadControllerType::None) {
|
2020-07-22 16:39:53 +02:00
|
|
|
styleset_changed_events[controller_idx].writable->Signal();
|
2018-10-05 16:23:21 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
controller.joy_styles.raw = 0; // Zero out
|
|
|
|
controller.device_type.raw = 0;
|
2020-07-22 16:39:53 +02:00
|
|
|
controller.properties.raw = 0;
|
2018-10-05 16:23:21 +02:00
|
|
|
switch (controller_type) {
|
2019-10-05 00:57:50 +02:00
|
|
|
case NPadControllerType::None:
|
|
|
|
UNREACHABLE();
|
2020-04-18 20:41:08 +02:00
|
|
|
break;
|
2020-07-22 16:39:53 +02:00
|
|
|
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;
|
2018-10-05 16:23:21 +02:00
|
|
|
case NPadControllerType::Handheld:
|
|
|
|
controller.joy_styles.handheld.Assign(1);
|
|
|
|
controller.device_type.handheld.Assign(1);
|
2018-10-18 10:00:16 +02:00
|
|
|
controller.properties.is_vertical.Assign(1);
|
|
|
|
controller.properties.use_plus.Assign(1);
|
|
|
|
controller.properties.use_minus.Assign(1);
|
2020-07-22 16:39:53 +02:00
|
|
|
controller.pad_assignment = NPadAssignments::Dual;
|
2018-10-05 16:23:21 +02:00
|
|
|
break;
|
2018-10-17 15:11:47 +02:00
|
|
|
case NPadControllerType::JoyDual:
|
|
|
|
controller.joy_styles.joycon_dual.Assign(1);
|
|
|
|
controller.device_type.joycon_left.Assign(1);
|
|
|
|
controller.device_type.joycon_right.Assign(1);
|
2018-10-18 10:00:16 +02:00
|
|
|
controller.properties.is_vertical.Assign(1);
|
|
|
|
controller.properties.use_plus.Assign(1);
|
|
|
|
controller.properties.use_minus.Assign(1);
|
2018-10-17 15:11:47 +02:00
|
|
|
controller.pad_assignment = NPadAssignments::Dual;
|
|
|
|
break;
|
2018-10-05 16:23:21 +02:00
|
|
|
case NPadControllerType::JoyLeft:
|
|
|
|
controller.joy_styles.joycon_left.Assign(1);
|
|
|
|
controller.device_type.joycon_left.Assign(1);
|
2018-10-18 10:00:16 +02:00
|
|
|
controller.properties.is_horizontal.Assign(1);
|
|
|
|
controller.properties.use_minus.Assign(1);
|
2018-10-18 06:09:55 +02:00
|
|
|
controller.pad_assignment = NPadAssignments::Single;
|
2018-10-05 16:23:21 +02:00
|
|
|
break;
|
|
|
|
case NPadControllerType::JoyRight:
|
|
|
|
controller.joy_styles.joycon_right.Assign(1);
|
|
|
|
controller.device_type.joycon_right.Assign(1);
|
2018-10-18 10:00:16 +02:00
|
|
|
controller.properties.is_horizontal.Assign(1);
|
|
|
|
controller.properties.use_plus.Assign(1);
|
2018-10-18 06:09:55 +02:00
|
|
|
controller.pad_assignment = NPadAssignments::Single;
|
2018-10-05 16:23:21 +02:00
|
|
|
break;
|
|
|
|
case NPadControllerType::Pokeball:
|
|
|
|
controller.joy_styles.pokeball.Assign(1);
|
|
|
|
controller.device_type.pokeball.Assign(1);
|
|
|
|
controller.pad_assignment = NPadAssignments::Single;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller.single_color_error = ColorReadError::ReadOk;
|
|
|
|
controller.single_color.body_color = 0;
|
|
|
|
controller.single_color.button_color = 0;
|
|
|
|
|
|
|
|
controller.dual_color_error = ColorReadError::ReadOk;
|
2018-11-02 03:03:17 +01:00
|
|
|
controller.left_color.body_color = Settings::values.players[controller_idx].body_color_left;
|
|
|
|
controller.left_color.button_color = Settings::values.players[controller_idx].button_color_left;
|
|
|
|
controller.right_color.body_color = Settings::values.players[controller_idx].body_color_right;
|
|
|
|
controller.right_color.button_color =
|
|
|
|
Settings::values.players[controller_idx].button_color_right;
|
2018-10-05 16:23:21 +02:00
|
|
|
|
2018-10-17 15:11:47 +02:00
|
|
|
controller.battery_level[0] = BATTERY_FULL;
|
|
|
|
controller.battery_level[1] = BATTERY_FULL;
|
|
|
|
controller.battery_level[2] = BATTERY_FULL;
|
2020-08-21 13:39:24 +02:00
|
|
|
|
|
|
|
SignalStyleSetChangedEvent(IndexToNPad(controller_idx));
|
2018-10-05 16:23:21 +02:00
|
|
|
}
|
|
|
|
|
2019-09-22 08:41:34 +02:00
|
|
|
void Controller_NPad::OnInit() {
|
2019-09-21 10:43:43 +02:00
|
|
|
auto& kernel = system.Kernel();
|
2019-09-22 15:42:41 +02:00
|
|
|
for (std::size_t i = 0; i < styleset_changed_events.size(); i++) {
|
|
|
|
styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair(
|
2019-11-03 10:10:12 +01:00
|
|
|
kernel, fmt::format("npad:NpadStyleSetChanged_{}", i));
|
2019-09-22 15:42:41 +02:00
|
|
|
}
|
2018-10-05 16:23:21 +02:00
|
|
|
|
2018-10-24 06:37:36 +02:00
|
|
|
if (!IsControllerActivated()) {
|
2018-10-05 16:23:21 +02:00
|
|
|
return;
|
2018-10-24 06:37:36 +02:00
|
|
|
}
|
|
|
|
|
2018-10-05 16:23:21 +02:00
|
|
|
if (style.raw == 0) {
|
|
|
|
// We want to support all controllers
|
|
|
|
style.handheld.Assign(1);
|
|
|
|
style.joycon_left.Assign(1);
|
|
|
|
style.joycon_right.Assign(1);
|
|
|
|
style.joycon_dual.Assign(1);
|
|
|
|
style.pro_controller.Assign(1);
|
|
|
|
style.pokeball.Assign(1);
|
|
|
|
}
|
2018-11-02 03:03:17 +01:00
|
|
|
|
2020-07-22 16:39:53 +02:00
|
|
|
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};
|
|
|
|
});
|
2018-11-02 03:03:17 +01:00
|
|
|
|
|
|
|
// Account for handheld
|
2020-07-22 16:39:53 +02:00
|
|
|
if (connected_controllers[HANDHELD_INDEX].is_connected) {
|
|
|
|
connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld;
|
|
|
|
}
|
2018-11-02 03:03:17 +01:00
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
for (std::size_t i = 0; i < connected_controllers.size(); ++i) {
|
|
|
|
const auto& controller = connected_controllers[i];
|
|
|
|
if (controller.is_connected) {
|
2020-07-22 16:39:53 +02:00
|
|
|
AddNewControllerAt(controller.type, i);
|
2018-11-02 03:03:17 +01:00
|
|
|
}
|
|
|
|
}
|
2018-10-05 16:23:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Controller_NPad::OnLoadInputDevices() {
|
2018-11-02 03:03:17 +01:00
|
|
|
const auto& players = Settings::values.players;
|
|
|
|
for (std::size_t i = 0; i < players.size(); ++i) {
|
|
|
|
std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
|
|
|
|
players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
|
|
|
|
buttons[i].begin(), Input::CreateDevice<Input::ButtonDevice>);
|
|
|
|
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>);
|
2020-09-05 04:48:03 +02:00
|
|
|
std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
|
|
|
|
players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END,
|
2020-09-03 02:59:34 +02:00
|
|
|
motions[i].begin(), Input::CreateDevice<Input::MotionDevice>);
|
2018-11-02 03:03:17 +01:00
|
|
|
}
|
2018-10-05 16:23:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Controller_NPad::OnRelease() {}
|
|
|
|
|
2018-10-18 05:11:15 +02:00
|
|
|
void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
|
|
|
|
const auto controller_idx = NPadIdToIndex(npad_id);
|
2019-10-05 00:57:50 +02:00
|
|
|
[[maybe_unused]] const auto controller_type = connected_controllers[controller_idx].type;
|
2018-10-18 05:11:15 +02:00
|
|
|
if (!connected_controllers[controller_idx].is_connected) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto& pad_state = npad_pad_states[controller_idx].pad_states;
|
|
|
|
auto& lstick_entry = npad_pad_states[controller_idx].l_stick;
|
|
|
|
auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
|
2018-11-02 03:03:17 +01:00
|
|
|
const auto& button_state = buttons[controller_idx];
|
|
|
|
const auto& analog_state = sticks[controller_idx];
|
2020-09-05 04:48:03 +02:00
|
|
|
const auto& motion_state = motions[controller_idx];
|
2020-01-09 02:40:55 +01:00
|
|
|
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();
|
2018-11-02 03:03:17 +01:00
|
|
|
|
2018-10-18 05:11:15 +02:00
|
|
|
using namespace Settings::NativeButton;
|
2018-11-02 03:03:17 +01:00
|
|
|
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());
|
|
|
|
|
2020-01-15 11:25:15 +01:00
|
|
|
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));
|
2018-11-02 03:03:17 +01:00
|
|
|
|
2020-01-15 11:25:15 +01:00
|
|
|
pad_state.r_stick_right.Assign(
|
|
|
|
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
|
2020-02-18 06:45:37 +01:00
|
|
|
->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));
|
2020-01-15 11:25:15 +01:00
|
|
|
pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
|
|
|
|
->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
|
2018-11-02 03:03:17 +01:00
|
|
|
|
|
|
|
pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
|
|
|
|
pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
|
2018-10-18 05:11:15 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-02-14 18:42:58 +01:00
|
|
|
void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
|
|
|
std::size_t data_len) {
|
2020-07-22 16:39:53 +02:00
|
|
|
if (!IsControllerActivated()) {
|
2018-10-05 16:23:21 +02:00
|
|
|
return;
|
2020-07-22 16:39:53 +02:00
|
|
|
}
|
2018-10-06 05:14:42 +02:00
|
|
|
for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
|
2018-10-05 16:23:21 +02:00
|
|
|
auto& npad = shared_memory_entries[i];
|
|
|
|
const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states,
|
|
|
|
&npad.handheld_states,
|
|
|
|
&npad.dual_states,
|
|
|
|
&npad.left_joy_states,
|
|
|
|
&npad.right_joy_states,
|
|
|
|
&npad.pokeball_states,
|
|
|
|
&npad.libnx};
|
|
|
|
|
2018-10-06 05:14:42 +02:00
|
|
|
for (auto* main_controller : controller_npads) {
|
2018-10-05 16:23:21 +02:00
|
|
|
main_controller->common.entry_count = 16;
|
|
|
|
main_controller->common.total_entry_count = 17;
|
|
|
|
|
2018-10-06 05:14:42 +02:00
|
|
|
const auto& last_entry =
|
|
|
|
main_controller->npad[main_controller->common.last_entry_index];
|
2018-10-05 16:23:21 +02:00
|
|
|
|
2020-02-25 03:04:12 +01:00
|
|
|
main_controller->common.timestamp = core_timing.GetCPUTicks();
|
2018-10-05 16:23:21 +02:00
|
|
|
main_controller->common.last_entry_index =
|
|
|
|
(main_controller->common.last_entry_index + 1) % 17;
|
|
|
|
|
|
|
|
auto& cur_entry = main_controller->npad[main_controller->common.last_entry_index];
|
|
|
|
|
|
|
|
cur_entry.timestamp = last_entry.timestamp + 1;
|
|
|
|
cur_entry.timestamp2 = cur_entry.timestamp;
|
|
|
|
}
|
|
|
|
|
2018-10-07 11:17:04 +02:00
|
|
|
const auto& controller_type = connected_controllers[i].type;
|
|
|
|
|
|
|
|
if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
|
2018-10-05 16:23:21 +02:00
|
|
|
continue;
|
|
|
|
}
|
2018-10-18 05:11:15 +02:00
|
|
|
const u32 npad_index = static_cast<u32>(i);
|
2020-09-05 04:48:03 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-09-05 15:42:01 +02:00
|
|
|
if (sixaxis_sensors_enabled && Settings::values.motion_enabled) {
|
2020-09-05 04:48:03 +02:00
|
|
|
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();
|
2020-09-05 04:35:42 +02:00
|
|
|
sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f;
|
2020-09-05 04:48:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-18 05:11:15 +02:00
|
|
|
RequestPadStateUpdate(npad_index);
|
|
|
|
auto& pad_state = npad_pad_states[npad_index];
|
2018-10-20 06:07:18 +02:00
|
|
|
|
2018-10-05 16:23:21 +02:00
|
|
|
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];
|
|
|
|
|
2018-10-17 15:11:47 +02:00
|
|
|
libnx_entry.connection_status.raw = 0;
|
2020-08-21 13:49:22 +02:00
|
|
|
libnx_entry.connection_status.IsConnected.Assign(1);
|
2020-09-05 04:48:03 +02:00
|
|
|
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];
|
2018-10-05 16:23:21 +02:00
|
|
|
|
|
|
|
switch (controller_type) {
|
2019-10-05 00:57:50 +02:00
|
|
|
case NPadControllerType::None:
|
|
|
|
UNREACHABLE();
|
2020-04-18 20:41:08 +02:00
|
|
|
break;
|
2020-07-22 16:39:53 +02:00
|
|
|
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;
|
2020-08-21 13:49:22 +02:00
|
|
|
|
|
|
|
libnx_entry.connection_status.IsWired.Assign(1);
|
2020-09-05 04:48:03 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2020-07-22 16:39:53 +02:00
|
|
|
break;
|
2018-10-05 16:23:21 +02:00
|
|
|
case NPadControllerType::Handheld:
|
2018-10-17 15:11:47 +02:00
|
|
|
handheld_entry.connection_status.raw = 0;
|
2020-08-21 13:51:13 +02:00
|
|
|
handheld_entry.connection_status.IsConnected.Assign(1);
|
2018-11-16 05:31:27 +01:00
|
|
|
handheld_entry.connection_status.IsWired.Assign(1);
|
|
|
|
handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
|
|
|
handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
|
|
|
|
handheld_entry.connection_status.IsLeftJoyWired.Assign(1);
|
|
|
|
handheld_entry.connection_status.IsRightJoyWired.Assign(1);
|
2018-10-18 05:11:15 +02:00
|
|
|
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;
|
2020-08-21 13:49:22 +02:00
|
|
|
|
|
|
|
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);
|
2020-09-05 04:48:03 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2018-10-05 16:23:21 +02:00
|
|
|
break;
|
2018-10-17 15:11:47 +02:00
|
|
|
case NPadControllerType::JoyDual:
|
|
|
|
dual_entry.connection_status.raw = 0;
|
2020-07-22 16:39:53 +02:00
|
|
|
dual_entry.connection_status.IsConnected.Assign(1);
|
2018-10-17 15:11:47 +02:00
|
|
|
dual_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
|
|
|
dual_entry.connection_status.IsRightJoyConnected.Assign(1);
|
2018-11-03 17:55:39 +01:00
|
|
|
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;
|
2020-07-22 16:39:53 +02:00
|
|
|
|
|
|
|
libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
|
|
|
libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
|
2020-09-05 04:48:03 +02:00
|
|
|
|
2020-09-02 18:18:41 +02:00
|
|
|
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;
|
2020-09-05 04:48:03 +02:00
|
|
|
}
|
2018-11-14 06:59:17 +01:00
|
|
|
break;
|
2018-10-05 16:23:21 +02:00
|
|
|
case NPadControllerType::JoyLeft:
|
2018-10-17 15:11:47 +02:00
|
|
|
left_entry.connection_status.raw = 0;
|
2018-10-05 16:23:21 +02:00
|
|
|
left_entry.connection_status.IsConnected.Assign(1);
|
2020-08-21 13:51:13 +02:00
|
|
|
left_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
2018-10-18 05:11:15 +02:00
|
|
|
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;
|
2020-08-21 13:51:13 +02:00
|
|
|
|
|
|
|
libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
2020-09-05 04:48:03 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2018-10-05 16:23:21 +02:00
|
|
|
break;
|
|
|
|
case NPadControllerType::JoyRight:
|
2018-10-17 15:11:47 +02:00
|
|
|
right_entry.connection_status.raw = 0;
|
2018-10-05 16:23:21 +02:00
|
|
|
right_entry.connection_status.IsConnected.Assign(1);
|
2020-08-21 13:51:13 +02:00
|
|
|
right_entry.connection_status.IsRightJoyConnected.Assign(1);
|
2018-10-18 05:11:15 +02:00
|
|
|
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;
|
2020-08-21 13:51:13 +02:00
|
|
|
|
|
|
|
libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
|
2020-09-05 04:48:03 +02:00
|
|
|
|
2020-09-02 18:18:41 +02:00
|
|
|
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;
|
2020-09-05 04:48:03 +02:00
|
|
|
}
|
2018-10-05 16:23:21 +02:00
|
|
|
break;
|
|
|
|
case NPadControllerType::Pokeball:
|
2018-10-17 15:11:47 +02:00
|
|
|
pokeball_entry.connection_status.raw = 0;
|
2018-10-05 16:23:21 +02:00
|
|
|
pokeball_entry.connection_status.IsConnected.Assign(1);
|
2018-10-18 05:11:15 +02:00
|
|
|
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;
|
2018-10-05 16:23:21 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
|
|
|
|
// any controllers.
|
2018-10-18 05:11:15 +02:00
|
|
|
libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
|
|
|
|
libnx_entry.pad.l_stick = pad_state.l_stick;
|
|
|
|
libnx_entry.pad.r_stick = pad_state.r_stick;
|
2018-12-24 22:19:16 +01:00
|
|
|
|
|
|
|
press_state |= static_cast<u32>(pad_state.pad_states.raw);
|
2018-10-05 16:23:21 +02:00
|
|
|
}
|
|
|
|
std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
|
|
|
|
shared_memory_entries.size() * sizeof(NPadEntry));
|
2018-10-18 06:09:55 +02:00
|
|
|
}
|
2018-10-05 16:23:21 +02:00
|
|
|
|
|
|
|
void Controller_NPad::SetSupportedStyleSet(NPadType style_set) {
|
|
|
|
style.raw = style_set.raw;
|
|
|
|
}
|
|
|
|
|
|
|
|
Controller_NPad::NPadType Controller_NPad::GetSupportedStyleSet() const {
|
|
|
|
return style;
|
|
|
|
}
|
|
|
|
|
2018-10-06 05:14:42 +02:00
|
|
|
void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
|
2018-10-05 16:23:21 +02:00
|
|
|
ASSERT(length > 0 && (length % sizeof(u32)) == 0);
|
2018-10-12 07:28:00 +02:00
|
|
|
supported_npad_id_types.clear();
|
2018-10-06 05:14:42 +02:00
|
|
|
supported_npad_id_types.resize(length / sizeof(u32));
|
2018-10-05 16:23:21 +02:00
|
|
|
std::memcpy(supported_npad_id_types.data(), data, length);
|
|
|
|
}
|
|
|
|
|
2018-10-18 02:37:45 +02:00
|
|
|
void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
|
2018-10-05 16:23:21 +02:00
|
|
|
ASSERT(max_length < supported_npad_id_types.size());
|
|
|
|
std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size());
|
|
|
|
}
|
|
|
|
|
2018-10-06 05:14:42 +02:00
|
|
|
std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
|
2018-10-05 16:23:21 +02:00
|
|
|
return supported_npad_id_types.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
|
|
|
|
hold_type = joy_hold_type;
|
|
|
|
}
|
2018-11-07 15:07:14 +01:00
|
|
|
|
2018-10-05 16:23:21 +02:00
|
|
|
Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
|
|
|
|
return hold_type;
|
|
|
|
}
|
|
|
|
|
2020-09-18 16:10:30 +02:00
|
|
|
void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) {
|
|
|
|
handheld_activation_mode = activation_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActivationMode() const {
|
|
|
|
return handheld_activation_mode;
|
|
|
|
}
|
|
|
|
|
2018-10-05 16:23:21 +02:00
|
|
|
void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
|
2018-12-02 16:45:08 +01:00
|
|
|
const std::size_t npad_index = NPadIdToIndex(npad_id);
|
|
|
|
ASSERT(npad_index < shared_memory_entries.size());
|
2019-09-22 15:42:41 +02:00
|
|
|
if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) {
|
|
|
|
shared_memory_entries[npad_index].pad_assignment = assignment_mode;
|
|
|
|
}
|
2018-10-05 16:23:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
|
|
|
|
const std::vector<Vibration>& vibrations) {
|
2020-04-20 18:44:57 +02:00
|
|
|
LOG_DEBUG(Service_HID, "(STUBBED) called");
|
2018-11-26 07:06:13 +01:00
|
|
|
|
2020-07-22 16:39:53 +02:00
|
|
|
if (!Settings::values.vibration_enabled || !can_controllers_vibrate) {
|
2018-10-10 15:58:47 +02:00
|
|
|
return;
|
|
|
|
}
|
2018-10-06 05:14:42 +02:00
|
|
|
for (std::size_t i = 0; i < controller_ids.size(); i++) {
|
2018-10-18 05:11:15 +02:00
|
|
|
std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i));
|
2018-10-11 17:56:49 +02:00
|
|
|
if (connected_controllers[controller_pos].is_connected) {
|
|
|
|
// TODO(ogniK): Vibrate the physical controller
|
2018-10-05 16:23:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
last_processed_vibration = vibrations.back();
|
|
|
|
}
|
|
|
|
|
2020-08-21 13:39:24 +02:00
|
|
|
Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
|
|
|
|
return last_processed_vibration;
|
|
|
|
}
|
|
|
|
|
2019-11-25 02:15:51 +01:00
|
|
|
std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
|
2019-09-22 15:42:41 +02:00
|
|
|
const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
|
|
|
|
return styleset_event.readable;
|
2018-10-05 16:23:21 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 13:39:24 +02:00
|
|
|
void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const {
|
|
|
|
styleset_changed_events[NPadIdToIndex(npad_id)].writable->Signal();
|
2018-10-05 16:23:21 +02:00
|
|
|
}
|
2018-10-18 05:11:15 +02:00
|
|
|
|
2020-07-22 16:39:53 +02:00
|
|
|
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) {
|
2020-08-21 13:39:24 +02:00
|
|
|
DisconnectNPadAtIndex(npad_index);
|
2018-10-11 17:56:49 +02:00
|
|
|
return;
|
|
|
|
}
|
2018-10-07 11:17:04 +02:00
|
|
|
|
2018-10-18 05:11:15 +02:00
|
|
|
if (controller == NPadControllerType::Handheld) {
|
2020-07-22 16:39:53 +02:00
|
|
|
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);
|
2018-10-18 05:11:15 +02:00
|
|
|
return;
|
|
|
|
}
|
2018-11-03 17:55:39 +01:00
|
|
|
|
2020-07-22 16:39:53 +02:00
|
|
|
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);
|
2018-10-07 11:17:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Controller_NPad::DisconnectNPad(u32 npad_id) {
|
2020-08-21 13:39:24 +02:00
|
|
|
DisconnectNPadAtIndex(NPadIdToIndex(npad_id));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) {
|
2020-07-22 16:39:53 +02:00
|
|
|
Settings::values.players[npad_index].connected = false;
|
2020-08-21 13:39:24 +02:00
|
|
|
connected_controllers[npad_index].is_connected = false;
|
2020-07-22 16:39:53 +02:00
|
|
|
|
|
|
|
auto& controller = shared_memory_entries[npad_index];
|
|
|
|
controller.joy_styles.raw = 0; // Zero out
|
|
|
|
controller.device_type.raw = 0;
|
|
|
|
controller.properties.raw = 0;
|
|
|
|
|
2020-08-21 13:39:24 +02:00
|
|
|
SignalStyleSetChangedEvent(IndexToNPad(npad_index));
|
2018-10-05 16:23:21 +02:00
|
|
|
}
|
2018-10-10 12:38:43 +02:00
|
|
|
|
2020-06-21 21:48:02 +02:00
|
|
|
void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
|
|
|
|
gyroscope_zero_drift_mode = drift_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMode() const {
|
|
|
|
return gyroscope_zero_drift_mode;
|
|
|
|
}
|
|
|
|
|
2020-09-05 04:48:03 +02:00
|
|
|
bool Controller_NPad::IsSixAxisSensorAtRest() const {
|
|
|
|
return sixaxis_at_rest;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller_NPad::SetSixAxisEnabled(bool six_axis_status) {
|
|
|
|
sixaxis_sensors_enabled = six_axis_status;
|
|
|
|
}
|
|
|
|
|
2020-08-27 19:27:03 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-01 07:12:57 +02:00
|
|
|
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
|
|
|
|
is_in_lr_assignment_mode = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller_NPad::StopLRAssignmentMode() {
|
|
|
|
is_in_lr_assignment_mode = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) {
|
|
|
|
if (npad_id_1 == NPAD_HANDHELD || npad_id_2 == NPAD_HANDHELD || npad_id_1 == NPAD_UNKNOWN ||
|
|
|
|
npad_id_2 == NPAD_UNKNOWN) {
|
|
|
|
return true;
|
|
|
|
}
|
2019-07-08 06:51:40 +02:00
|
|
|
const auto npad_index_1 = NPadIdToIndex(npad_id_1);
|
|
|
|
const auto npad_index_2 = NPadIdToIndex(npad_id_2);
|
2019-07-01 07:12:57 +02:00
|
|
|
|
2019-07-08 06:51:40 +02:00
|
|
|
if (!IsControllerSupported(connected_controllers[npad_index_1].type) ||
|
|
|
|
!IsControllerSupported(connected_controllers[npad_index_2].type)) {
|
2019-07-01 07:12:57 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-07-08 06:51:40 +02:00
|
|
|
std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type);
|
2019-07-01 07:12:57 +02:00
|
|
|
|
2020-07-22 16:39:53 +02:00
|
|
|
AddNewControllerAt(connected_controllers[npad_index_1].type, npad_index_1);
|
|
|
|
AddNewControllerAt(connected_controllers[npad_index_2].type, npad_index_2);
|
2019-07-01 07:12:57 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-10-10 12:38:43 +02:00
|
|
|
Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
|
|
|
|
if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) {
|
|
|
|
// These are controllers without led patterns
|
|
|
|
return LedPattern{0, 0, 0, 0};
|
|
|
|
}
|
|
|
|
switch (npad_id) {
|
|
|
|
case 0:
|
|
|
|
return LedPattern{1, 0, 0, 0};
|
|
|
|
case 1:
|
2020-08-20 09:42:46 +02:00
|
|
|
return LedPattern{1, 1, 0, 0};
|
2018-10-10 12:38:43 +02:00
|
|
|
case 2:
|
2020-08-20 09:42:46 +02:00
|
|
|
return LedPattern{1, 1, 1, 0};
|
2018-10-10 12:38:43 +02:00
|
|
|
case 3:
|
2020-08-20 09:42:46 +02:00
|
|
|
return LedPattern{1, 1, 1, 1};
|
2018-10-10 12:38:43 +02:00
|
|
|
case 4:
|
|
|
|
return LedPattern{1, 0, 0, 1};
|
|
|
|
case 5:
|
|
|
|
return LedPattern{1, 0, 1, 0};
|
|
|
|
case 6:
|
|
|
|
return LedPattern{1, 0, 1, 1};
|
|
|
|
case 7:
|
|
|
|
return LedPattern{0, 1, 1, 0};
|
|
|
|
default:
|
|
|
|
return LedPattern{0, 0, 0, 0};
|
2020-08-14 15:04:44 +02:00
|
|
|
}
|
2018-10-10 12:38:43 +02:00
|
|
|
}
|
2019-09-04 08:42:58 +02:00
|
|
|
|
2018-10-10 15:58:47 +02:00
|
|
|
void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
|
|
|
|
can_controllers_vibrate = can_vibrate;
|
|
|
|
}
|
2018-10-20 06:07:18 +02:00
|
|
|
|
2019-09-04 16:15:49 +02:00
|
|
|
bool Controller_NPad::IsVibrationEnabled() const {
|
2019-09-04 08:42:58 +02:00
|
|
|
return can_controllers_vibrate;
|
|
|
|
}
|
|
|
|
|
2018-10-18 12:45:10 +02:00
|
|
|
void Controller_NPad::ClearAllConnectedControllers() {
|
2018-11-03 17:55:39 +01:00
|
|
|
for (auto& controller : connected_controllers) {
|
|
|
|
if (controller.is_connected && controller.type != NPadControllerType::None) {
|
|
|
|
controller.type = NPadControllerType::None;
|
|
|
|
controller.is_connected = false;
|
|
|
|
}
|
|
|
|
}
|
2018-10-18 12:45:10 +02:00
|
|
|
}
|
2019-09-04 08:42:58 +02:00
|
|
|
|
2018-10-18 12:45:10 +02:00
|
|
|
void Controller_NPad::DisconnectAllConnectedControllers() {
|
2020-08-21 13:39:24 +02:00
|
|
|
for (auto& controller : connected_controllers) {
|
2019-10-18 00:15:39 +02:00
|
|
|
controller.is_connected = false;
|
|
|
|
}
|
2018-10-18 12:45:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Controller_NPad::ConnectAllDisconnectedControllers() {
|
2020-08-21 13:39:24 +02:00
|
|
|
for (auto& controller : connected_controllers) {
|
2019-10-18 00:15:39 +02:00
|
|
|
if (controller.type != NPadControllerType::None && !controller.is_connected) {
|
2019-10-18 00:19:44 +02:00
|
|
|
controller.is_connected = true;
|
2019-10-18 00:15:39 +02:00
|
|
|
}
|
|
|
|
}
|
2018-10-18 12:45:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Controller_NPad::ClearAllControllers() {
|
2020-08-21 13:39:24 +02:00
|
|
|
for (auto& controller : connected_controllers) {
|
2019-10-18 00:15:39 +02:00
|
|
|
controller.type = NPadControllerType::None;
|
|
|
|
controller.is_connected = false;
|
|
|
|
}
|
2018-10-18 12:45:10 +02:00
|
|
|
}
|
|
|
|
|
2018-12-29 00:20:29 +01:00
|
|
|
u32 Controller_NPad::GetAndResetPressState() {
|
|
|
|
return std::exchange(press_state, 0);
|
2018-12-24 22:19:16 +01:00
|
|
|
}
|
|
|
|
|
2018-10-20 06:07:18 +02:00
|
|
|
bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const {
|
|
|
|
if (controller == NPadControllerType::Handheld) {
|
2019-10-18 00:11:39 +02:00
|
|
|
const bool support_handheld =
|
|
|
|
std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(),
|
|
|
|
NPAD_HANDHELD) != supported_npad_id_types.end();
|
2018-10-20 06:07:18 +02:00
|
|
|
// Handheld is not even a supported type, lets stop here
|
|
|
|
if (!support_handheld) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Handheld should not be supported in docked mode
|
|
|
|
if (Settings::values.use_docked_mode) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2019-10-18 00:11:39 +02:00
|
|
|
|
2018-10-20 06:07:18 +02:00
|
|
|
if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(),
|
|
|
|
[](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) {
|
|
|
|
switch (controller) {
|
|
|
|
case NPadControllerType::ProController:
|
|
|
|
return style.pro_controller;
|
|
|
|
case NPadControllerType::JoyDual:
|
|
|
|
return style.joycon_dual;
|
|
|
|
case NPadControllerType::JoyLeft:
|
|
|
|
return style.joycon_left;
|
|
|
|
case NPadControllerType::JoyRight:
|
|
|
|
return style.joycon_right;
|
|
|
|
case NPadControllerType::Pokeball:
|
|
|
|
return style.pokeball;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2019-10-18 00:11:39 +02:00
|
|
|
|
2018-10-20 06:07:18 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-10-06 05:14:42 +02:00
|
|
|
} // namespace Service::HID
|