Project Mjölnir: Part 1

Co-authored-by: James Rowe <jroweboy@gmail.com>
Co-authored-by: Its-Rei <kupfel@gmail.com>
This commit is contained in:
Morph 2020-07-22 10:39:53 -04:00
parent b8885aa03b
commit f0fac0c7fb
84 changed files with 8695 additions and 3260 deletions

View file

@ -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,7 +106,7 @@ 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;
@ -96,25 +119,35 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
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::Handheld:
controller.joy_styles.handheld.Assign(1);
controller.device_type.handheld.Assign(1);
controller.pad_assignment = NPadAssignments::Dual;
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.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;
@ -192,36 +217,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);
}
}
}
@ -309,8 +323,9 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
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,
@ -365,6 +380,14 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
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;
break;
case NPadControllerType::Handheld:
handheld_entry.connection_status.raw = 0;
handheld_entry.connection_status.IsWired.Assign(1);
@ -378,22 +401,19 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
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.IsConnected.Assign(1);
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.pad.pad_states.raw = pad_state.pad_states.raw;
left_entry.pad.l_stick = pad_state.l_stick;
@ -401,7 +421,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
break;
case NPadControllerType::JoyRight:
right_entry.connection_status.raw = 0;
right_entry.connection_status.IsConnected.Assign(1);
right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
right_entry.pad.l_stick = pad_state.l_stick;
@ -409,23 +428,12 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
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
@ -453,26 +461,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) {
@ -504,7 +492,7 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
const std::vector<Vibration>& vibrations) {
LOG_DEBUG(Service_HID, "(STUBBED) 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++) {
@ -517,8 +505,6 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
}
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;
}
@ -527,43 +513,43 @@ Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
return last_processed_vibration;
}
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!");
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, std::size_t npad_index) {
UpdateControllerAt(controller, npad_index, true);
}
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));
void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
bool connected) {
if (!connected) {
DisconnectNPad(IndexToNPad(npad_index));
return;
}
connected_controllers[NPadIdToIndex(npad_id)] = {controller, true};
InitNewlyAddedControler(NPadIdToIndex(npad_id));
}
if (controller == NPadControllerType::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;
}
void Controller_NPad::ConnectNPad(u32 npad_id) {
connected_controllers[NPadIdToIndex(npad_id)].is_connected = true;
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::DisconnectNPad(u32 npad_id) {
connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;
const auto npad_index = NPadIdToIndex(npad_id);
connected_controllers[npad_index].is_connected = false;
Settings::values.players[npad_index].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;
styleset_changed_events[npad_index].writable->Signal();
}
void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
@ -599,8 +585,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;
}
@ -628,7 +614,6 @@ 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};
}
}

View file

@ -118,10 +118,11 @@ public:
std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
Vibration GetLastVibration() const;
void AddNewController(NPadControllerType controller);
void AddNewControllerAt(NPadControllerType controller, u32 npad_id);
// 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 SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
@ -141,6 +142,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);
@ -309,7 +312,7 @@ 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);

View file

@ -38,11 +38,9 @@
namespace Service::HID {
// Updating period for each HID device.
// TODO(ogniK): Find actual polling rate of hid
constexpr auto pad_update_ns = std::chrono::nanoseconds{1000000000 / 66};
[[maybe_unused]] constexpr auto accelerometer_update_ns =
std::chrono::nanoseconds{1000000000 / 100};
[[maybe_unused]] constexpr auto gyroscope_update_ticks = std::chrono::nanoseconds{1000000000 / 100};
// HID is polled every 15ms, this value was derived from
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet
constexpr auto pad_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.6Hz)
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
IAppletResource::IAppletResource(Core::System& system)
@ -845,8 +843,7 @@ void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto can_vibrate{rp.Pop<bool>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetVibrationEnabled(can_vibrate);
Settings::values.vibration_enabled = can_vibrate;
LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
@ -859,8 +856,7 @@ void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(
applet_resource->GetController<Controller_NPad>(HidController::NPad).IsVibrationEnabled());
rb.Push(Settings::values.vibration_enabled);
}
void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {

View file

@ -13,56 +13,6 @@
namespace Settings {
namespace NativeButton {
const std::array<const char*, NumButtons> mapping = {{
"button_a",
"button_b",
"button_x",
"button_y",
"button_lstick",
"button_rstick",
"button_l",
"button_r",
"button_zl",
"button_zr",
"button_plus",
"button_minus",
"button_dleft",
"button_dup",
"button_dright",
"button_ddown",
"button_lstick_left",
"button_lstick_up",
"button_lstick_right",
"button_lstick_down",
"button_rstick_left",
"button_rstick_up",
"button_rstick_right",
"button_rstick_down",
"button_sl",
"button_sr",
"button_home",
"button_screenshot",
}};
}
namespace NativeAnalog {
const std::array<const char*, NumAnalogs> mapping = {{
"lstick",
"rstick",
}};
}
namespace NativeMouseButton {
const std::array<const char*, NumMouseButtons> mapping = {{
"left",
"right",
"middle",
"forward",
"back",
}};
}
Values values = {};
bool configuring_global = true;

View file

@ -12,340 +12,10 @@
#include <string>
#include <vector>
#include "common/common_types.h"
#include "input_common/settings.h"
namespace Settings {
namespace NativeButton {
enum Values {
A,
B,
X,
Y,
LStick,
RStick,
L,
R,
ZL,
ZR,
Plus,
Minus,
DLeft,
DUp,
DRight,
DDown,
LStick_Left,
LStick_Up,
LStick_Right,
LStick_Down,
RStick_Left,
RStick_Up,
RStick_Right,
RStick_Down,
SL,
SR,
Home,
Screenshot,
NumButtons,
};
constexpr int BUTTON_HID_BEGIN = A;
constexpr int BUTTON_NS_BEGIN = Home;
constexpr int BUTTON_HID_END = BUTTON_NS_BEGIN;
constexpr int BUTTON_NS_END = NumButtons;
constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
extern const std::array<const char*, NumButtons> mapping;
} // namespace NativeButton
namespace NativeAnalog {
enum Values {
LStick,
RStick,
NumAnalogs,
};
constexpr int STICK_HID_BEGIN = LStick;
constexpr int STICK_HID_END = NumAnalogs;
constexpr int NUM_STICKS_HID = NumAnalogs;
extern const std::array<const char*, NumAnalogs> mapping;
} // namespace NativeAnalog
namespace NativeMouseButton {
enum Values {
Left,
Right,
Middle,
Forward,
Back,
NumMouseButtons,
};
constexpr int MOUSE_HID_BEGIN = Left;
constexpr int MOUSE_HID_END = NumMouseButtons;
constexpr int NUM_MOUSE_HID = NumMouseButtons;
extern const std::array<const char*, NumMouseButtons> mapping;
} // namespace NativeMouseButton
namespace NativeKeyboard {
enum Keys {
None,
Error,
A = 4,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
N1,
N2,
N3,
N4,
N5,
N6,
N7,
N8,
N9,
N0,
Enter,
Escape,
Backspace,
Tab,
Space,
Minus,
Equal,
LeftBrace,
RightBrace,
Backslash,
Tilde,
Semicolon,
Apostrophe,
Grave,
Comma,
Dot,
Slash,
CapsLockKey,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
SystemRequest,
ScrollLockKey,
Pause,
Insert,
Home,
PageUp,
Delete,
End,
PageDown,
Right,
Left,
Down,
Up,
NumLockKey,
KPSlash,
KPAsterisk,
KPMinus,
KPPlus,
KPEnter,
KP1,
KP2,
KP3,
KP4,
KP5,
KP6,
KP7,
KP8,
KP9,
KP0,
KPDot,
Key102,
Compose,
Power,
KPEqual,
F13,
F14,
F15,
F16,
F17,
F18,
F19,
F20,
F21,
F22,
F23,
F24,
Open,
Help,
Properties,
Front,
Stop,
Repeat,
Undo,
Cut,
Copy,
Paste,
Find,
Mute,
VolumeUp,
VolumeDown,
CapsLockActive,
NumLockActive,
ScrollLockActive,
KPComma,
KPLeftParenthesis,
KPRightParenthesis,
LeftControlKey = 0xE0,
LeftShiftKey,
LeftAltKey,
LeftMetaKey,
RightControlKey,
RightShiftKey,
RightAltKey,
RightMetaKey,
MediaPlayPause,
MediaStopCD,
MediaPrevious,
MediaNext,
MediaEject,
MediaVolumeUp,
MediaVolumeDown,
MediaMute,
MediaWebsite,
MediaBack,
MediaForward,
MediaStop,
MediaFind,
MediaScrollUp,
MediaScrollDown,
MediaEdit,
MediaSleep,
MediaCoffee,
MediaRefresh,
MediaCalculator,
NumKeyboardKeys,
};
static_assert(NumKeyboardKeys == 0xFC, "Incorrect number of keyboard keys.");
enum Modifiers {
LeftControl,
LeftShift,
LeftAlt,
LeftMeta,
RightControl,
RightShift,
RightAlt,
RightMeta,
CapsLock,
ScrollLock,
NumLock,
NumKeyboardMods,
};
constexpr int KEYBOARD_KEYS_HID_BEGIN = None;
constexpr int KEYBOARD_KEYS_HID_END = NumKeyboardKeys;
constexpr int NUM_KEYBOARD_KEYS_HID = NumKeyboardKeys;
constexpr int KEYBOARD_MODS_HID_BEGIN = LeftControl;
constexpr int KEYBOARD_MODS_HID_END = NumKeyboardMods;
constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
} // namespace NativeKeyboard
using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
enum class ControllerType {
ProController,
DualJoycon,
RightJoycon,
LeftJoycon,
};
struct PlayerInput {
bool connected;
ControllerType type;
ButtonsRaw buttons;
AnalogsRaw analogs;
u32 body_color_right;
u32 button_color_right;
u32 body_color_left;
u32 button_color_left;
};
struct TouchscreenInput {
bool enabled;
std::string device;
u32 finger;
u32 diameter_x;
u32 diameter_y;
u32 rotation_angle;
};
enum class RendererBackend {
OpenGL = 0,
Vulkan = 1,
@ -461,6 +131,8 @@ struct Values {
// Controls
std::array<PlayerInput, 10> players;
bool use_docked_mode;
bool mouse_enabled;
std::string mouse_device;
MouseButtonsRaw mouse_buttons;
@ -474,14 +146,15 @@ struct Values {
AnalogsRaw debug_pad_analogs;
std::string motion_device;
bool vibration_enabled;
TouchscreenInput touchscreen;
std::atomic_bool is_device_reload_pending{true};
std::string udp_input_address;
u16 udp_input_port;
u8 udp_pad_index;
bool use_docked_mode;
// Data Storage
bool use_virtual_sd;
bool gamecard_inserted;