Compare commits
1 Commits
system-con
...
motion
Author | SHA1 | Date | |
---|---|---|---|
4f5f4e1b15 |
@ -24,6 +24,7 @@ enum class InputType {
|
|||||||
Analog,
|
Analog,
|
||||||
Trigger,
|
Trigger,
|
||||||
Motion,
|
Motion,
|
||||||
|
VirtualMotion,
|
||||||
Touch,
|
Touch,
|
||||||
Color,
|
Color,
|
||||||
Vibration,
|
Vibration,
|
||||||
|
@ -159,8 +159,6 @@ add_library(core STATIC
|
|||||||
hid/irs_types.h
|
hid/irs_types.h
|
||||||
hid/motion_input.cpp
|
hid/motion_input.cpp
|
||||||
hid/motion_input.h
|
hid/motion_input.h
|
||||||
hid/system_controller.cpp
|
|
||||||
hid/system_controller.h
|
|
||||||
hle/api_version.h
|
hle/api_version.h
|
||||||
hle/ipc.h
|
hle/ipc.h
|
||||||
hle/kernel/board/nintendo/nx/k_memory_layout.cpp
|
hle/kernel/board/nintendo/nx/k_memory_layout.cpp
|
||||||
|
@ -46,26 +46,26 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac
|
|||||||
// Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
|
// Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
|
||||||
if (parameters.allow_pro_controller) {
|
if (parameters.allow_pro_controller) {
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
||||||
controller->Connect();
|
controller->Connect(true);
|
||||||
} else if (parameters.allow_dual_joycons) {
|
} else if (parameters.allow_dual_joycons) {
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
|
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
|
||||||
controller->Connect();
|
controller->Connect(true);
|
||||||
} else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {
|
} else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {
|
||||||
// Assign left joycons to even player indices and right joycons to odd player indices.
|
// Assign left joycons to even player indices and right joycons to odd player indices.
|
||||||
// We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and
|
// We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and
|
||||||
// a right Joycon for Player 2 in 2 Player Assist mode.
|
// a right Joycon for Player 2 in 2 Player Assist mode.
|
||||||
if (index % 2 == 0) {
|
if (index % 2 == 0) {
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft);
|
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft);
|
||||||
controller->Connect();
|
controller->Connect(true);
|
||||||
} else {
|
} else {
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight);
|
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight);
|
||||||
controller->Connect();
|
controller->Connect(true);
|
||||||
}
|
}
|
||||||
} else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
|
} else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
|
||||||
!Settings::values.use_docked_mode.GetValue()) {
|
!Settings::values.use_docked_mode.GetValue()) {
|
||||||
// We should *never* reach here under any normal circumstances.
|
// We should *never* reach here under any normal circumstances.
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
||||||
controller->Connect();
|
controller->Connect(true);
|
||||||
} else {
|
} else {
|
||||||
ASSERT_MSG(false, "Unable to add a new controller based on the given parameters!");
|
ASSERT_MSG(false, "Unable to add a new controller based on the given parameters!");
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,7 @@ void EmulatedController::ReloadFromSettings() {
|
|||||||
motion_params[index] = Common::ParamPackage(player.motions[index]);
|
motion_params[index] = Common::ParamPackage(player.motions[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
controller.color_values = {};
|
||||||
controller.colors_state.fullkey = {
|
controller.colors_state.fullkey = {
|
||||||
.body = GetNpadColor(player.body_color_left),
|
.body = GetNpadColor(player.body_color_left),
|
||||||
.button = GetNpadColor(player.button_color_left),
|
.button = GetNpadColor(player.button_color_left),
|
||||||
@ -536,18 +537,181 @@ void EmulatedController::UnloadInput() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::DisableInput() {
|
void EmulatedController::EnableConfiguration() {
|
||||||
npad_input_enabled = false;
|
is_configuring = true;
|
||||||
|
tmp_is_connected = is_connected;
|
||||||
|
tmp_npad_type = npad_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::EnableInput() {
|
void EmulatedController::DisableConfiguration() {
|
||||||
npad_input_enabled = true;
|
is_configuring = false;
|
||||||
|
|
||||||
// Get Joycon colors before turning on the controller
|
// Get Joycon colors before turning on the controller
|
||||||
for (const auto& color_device : color_devices) {
|
for (const auto& color_device : color_devices) {
|
||||||
color_device->ForceUpdate();
|
color_device->ForceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply temporary npad type to the real controller
|
||||||
|
if (tmp_npad_type != npad_type) {
|
||||||
|
if (is_connected) {
|
||||||
|
Disconnect();
|
||||||
|
}
|
||||||
|
SetNpadStyleIndex(tmp_npad_type);
|
||||||
|
original_npad_type = tmp_npad_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply temporary connected status to the real controller
|
||||||
|
if (tmp_is_connected != is_connected) {
|
||||||
|
if (tmp_is_connected) {
|
||||||
|
Connect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulatedController::EnableSystemButtons() {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
system_buttons_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulatedController::DisableSystemButtons() {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
system_buttons_enabled = false;
|
||||||
|
controller.home_button_state.raw = 0;
|
||||||
|
controller.capture_button_state.raw = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulatedController::ResetSystemButtons() {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
controller.home_button_state.home.Assign(false);
|
||||||
|
controller.capture_button_state.capture.Assign(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EmulatedController::IsConfiguring() const {
|
||||||
|
return is_configuring;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulatedController::SaveCurrentConfig() {
|
||||||
|
const auto player_index = NpadIdTypeToIndex(npad_id_type);
|
||||||
|
auto& player = Settings::values.players.GetValue()[player_index];
|
||||||
|
player.connected = is_connected;
|
||||||
|
player.controller_type = MapNPadToSettingsType(npad_type);
|
||||||
|
for (std::size_t index = 0; index < player.buttons.size(); ++index) {
|
||||||
|
player.buttons[index] = button_params[index].Serialize();
|
||||||
|
}
|
||||||
|
for (std::size_t index = 0; index < player.analogs.size(); ++index) {
|
||||||
|
player.analogs[index] = stick_params[index].Serialize();
|
||||||
|
}
|
||||||
|
for (std::size_t index = 0; index < player.motions.size(); ++index) {
|
||||||
|
player.motions[index] = motion_params[index].Serialize();
|
||||||
|
}
|
||||||
|
if (npad_id_type == NpadIdType::Player1) {
|
||||||
|
Settings::values.ringcon_analogs = ring_params[0].Serialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulatedController::RestoreConfig() {
|
||||||
|
if (!is_configuring) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ReloadFromSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices() const {
|
||||||
|
std::vector<Common::ParamPackage> devices;
|
||||||
|
for (const auto& param : button_params) {
|
||||||
|
if (!param.Has("engine")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto devices_it = std::find_if(
|
||||||
|
devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) {
|
||||||
|
return param.Get("engine", "") == param_.Get("engine", "") &&
|
||||||
|
param.Get("guid", "") == param_.Get("guid", "") &&
|
||||||
|
param.Get("port", 0) == param_.Get("port", 0) &&
|
||||||
|
param.Get("pad", 0) == param_.Get("pad", 0);
|
||||||
|
});
|
||||||
|
if (devices_it != devices.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& device = devices.emplace_back();
|
||||||
|
device.Set("engine", param.Get("engine", ""));
|
||||||
|
device.Set("guid", param.Get("guid", ""));
|
||||||
|
device.Set("port", param.Get("port", 0));
|
||||||
|
device.Set("pad", param.Get("pad", 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& param : stick_params) {
|
||||||
|
if (!param.Has("engine")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (param.Get("engine", "") == "analog_from_button") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto devices_it = std::find_if(
|
||||||
|
devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) {
|
||||||
|
return param.Get("engine", "") == param_.Get("engine", "") &&
|
||||||
|
param.Get("guid", "") == param_.Get("guid", "") &&
|
||||||
|
param.Get("port", 0) == param_.Get("port", 0) &&
|
||||||
|
param.Get("pad", 0) == param_.Get("pad", 0);
|
||||||
|
});
|
||||||
|
if (devices_it != devices.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& device = devices.emplace_back();
|
||||||
|
device.Set("engine", param.Get("engine", ""));
|
||||||
|
device.Set("guid", param.Get("guid", ""));
|
||||||
|
device.Set("port", param.Get("port", 0));
|
||||||
|
device.Set("pad", param.Get("pad", 0));
|
||||||
|
}
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::ParamPackage EmulatedController::GetButtonParam(std::size_t index) const {
|
||||||
|
if (index >= button_params.size()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return button_params[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::ParamPackage EmulatedController::GetStickParam(std::size_t index) const {
|
||||||
|
if (index >= stick_params.size()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return stick_params[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::ParamPackage EmulatedController::GetMotionParam(std::size_t index) const {
|
||||||
|
if (index >= motion_params.size()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return motion_params[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulatedController::SetButtonParam(std::size_t index, Common::ParamPackage param) {
|
||||||
|
if (index >= button_params.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
button_params[index] = std::move(param);
|
||||||
|
ReloadInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulatedController::SetStickParam(std::size_t index, Common::ParamPackage param) {
|
||||||
|
if (index >= stick_params.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stick_params[index] = std::move(param);
|
||||||
|
ReloadInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage param) {
|
||||||
|
if (index >= motion_params.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
motion_params[index] = std::move(param);
|
||||||
|
ReloadInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::StartMotionCalibration() {
|
void EmulatedController::StartMotionCalibration() {
|
||||||
@ -602,6 +766,16 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_configuring) {
|
||||||
|
controller.npad_button_state.raw = NpadButton::None;
|
||||||
|
controller.debug_pad_button_state.raw = 0;
|
||||||
|
controller.home_button_state.raw = 0;
|
||||||
|
controller.capture_button_state.raw = 0;
|
||||||
|
lock.unlock();
|
||||||
|
TriggerOnChange(ControllerTriggerType::Button, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// GC controllers have triggers not buttons
|
// GC controllers have triggers not buttons
|
||||||
if (npad_type == NpadStyleIndex::GameCube) {
|
if (npad_type == NpadStyleIndex::GameCube) {
|
||||||
if (index == Settings::NativeButton::ZR) {
|
if (index == Settings::NativeButton::ZR) {
|
||||||
@ -683,6 +857,18 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
|
|||||||
controller.npad_button_state.left_sr.Assign(current_status.value);
|
controller.npad_button_state.left_sr.Assign(current_status.value);
|
||||||
controller.npad_button_state.right_sr.Assign(current_status.value);
|
controller.npad_button_state.right_sr.Assign(current_status.value);
|
||||||
break;
|
break;
|
||||||
|
case Settings::NativeButton::Home:
|
||||||
|
if (!system_buttons_enabled) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
controller.home_button_state.home.Assign(current_status.value);
|
||||||
|
break;
|
||||||
|
case Settings::NativeButton::Screenshot:
|
||||||
|
if (!system_buttons_enabled) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
controller.capture_button_state.capture.Assign(current_status.value);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
@ -695,7 +881,7 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
|
|||||||
Connect();
|
Connect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TriggerOnChange(ControllerTriggerType::Button);
|
TriggerOnChange(ControllerTriggerType::Button, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
|
void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||||
@ -704,7 +890,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto trigger_guard =
|
auto trigger_guard =
|
||||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick); });
|
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); });
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
const auto stick_value = TransformToStick(callback);
|
const auto stick_value = TransformToStick(callback);
|
||||||
|
|
||||||
@ -725,6 +911,12 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
|
|||||||
controller.stick_values[index] = stick_value;
|
controller.stick_values[index] = stick_value;
|
||||||
controller.stick_values[index].uuid = uuid;
|
controller.stick_values[index].uuid = uuid;
|
||||||
|
|
||||||
|
if (is_configuring) {
|
||||||
|
controller.analog_stick_state.left = {};
|
||||||
|
controller.analog_stick_state.right = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const AnalogStickState stick{
|
const AnalogStickState stick{
|
||||||
.x = static_cast<s32>(controller.stick_values[index].x.value * HID_JOYSTICK_MAX),
|
.x = static_cast<s32>(controller.stick_values[index].x.value * HID_JOYSTICK_MAX),
|
||||||
.y = static_cast<s32>(controller.stick_values[index].y.value * HID_JOYSTICK_MAX),
|
.y = static_cast<s32>(controller.stick_values[index].y.value * HID_JOYSTICK_MAX),
|
||||||
@ -754,7 +946,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto trigger_guard =
|
auto trigger_guard =
|
||||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger); });
|
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); });
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
const auto trigger_value = TransformToTrigger(callback);
|
const auto trigger_value = TransformToTrigger(callback);
|
||||||
|
|
||||||
@ -768,6 +960,12 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
|
|||||||
controller.trigger_values[index] = trigger_value;
|
controller.trigger_values[index] = trigger_value;
|
||||||
controller.trigger_values[index].uuid = uuid;
|
controller.trigger_values[index].uuid = uuid;
|
||||||
|
|
||||||
|
if (is_configuring) {
|
||||||
|
controller.gc_trigger_state.left = 0;
|
||||||
|
controller.gc_trigger_state.right = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Only GC controllers have analog triggers
|
// Only GC controllers have analog triggers
|
||||||
if (npad_type != NpadStyleIndex::GameCube) {
|
if (npad_type != NpadStyleIndex::GameCube) {
|
||||||
trigger_guard.Cancel();
|
trigger_guard.Cancel();
|
||||||
@ -794,7 +992,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
|
|||||||
if (index >= controller.motion_values.size()) {
|
if (index >= controller.motion_values.size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion); });
|
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); });
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
auto& raw_status = controller.motion_values[index].raw_status;
|
auto& raw_status = controller.motion_values[index].raw_status;
|
||||||
auto& emulated = controller.motion_values[index].emulated;
|
auto& emulated = controller.motion_values[index].emulated;
|
||||||
@ -825,44 +1023,48 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
|
|||||||
|
|
||||||
void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback,
|
void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback,
|
||||||
std::size_t index) {
|
std::size_t index) {
|
||||||
if (index > RightIndex) {
|
if (index >= controller.color_values.size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto trigger_guard =
|
auto trigger_guard =
|
||||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color); });
|
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); });
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
const auto color_values = TransformToColor(callback);
|
controller.color_values[index] = TransformToColor(callback);
|
||||||
|
|
||||||
if (color_values.body == 0) {
|
if (is_configuring) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller.color_values[index].body == 0) {
|
||||||
trigger_guard.Cancel();
|
trigger_guard.Cancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
controller.colors_state.fullkey = {
|
controller.colors_state.fullkey = {
|
||||||
.body = GetNpadColor(color_values.body),
|
.body = GetNpadColor(controller.color_values[index].body),
|
||||||
.button = GetNpadColor(color_values.buttons),
|
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||||
};
|
};
|
||||||
if (npad_type == NpadStyleIndex::ProController) {
|
if (npad_type == NpadStyleIndex::ProController) {
|
||||||
controller.colors_state.left = {
|
controller.colors_state.left = {
|
||||||
.body = GetNpadColor(color_values.left_grip),
|
.body = GetNpadColor(controller.color_values[index].left_grip),
|
||||||
.button = GetNpadColor(color_values.buttons),
|
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||||
};
|
};
|
||||||
controller.colors_state.right = {
|
controller.colors_state.right = {
|
||||||
.body = GetNpadColor(color_values.right_grip),
|
.body = GetNpadColor(controller.color_values[index].right_grip),
|
||||||
.button = GetNpadColor(color_values.buttons),
|
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case LeftIndex:
|
case LeftIndex:
|
||||||
controller.colors_state.left = {
|
controller.colors_state.left = {
|
||||||
.body = GetNpadColor(color_values.body),
|
.body = GetNpadColor(controller.color_values[index].body),
|
||||||
.button = GetNpadColor(color_values.buttons),
|
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case RightIndex:
|
case RightIndex:
|
||||||
controller.colors_state.right = {
|
controller.colors_state.right = {
|
||||||
.body = GetNpadColor(color_values.body),
|
.body = GetNpadColor(controller.color_values[index].body),
|
||||||
.button = GetNpadColor(color_values.buttons),
|
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -871,17 +1073,21 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback
|
|||||||
|
|
||||||
void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback,
|
void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback,
|
||||||
std::size_t index) {
|
std::size_t index) {
|
||||||
if (index > DualIndex) {
|
if (index >= controller.battery_values.size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery); });
|
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); });
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
const auto battery_values = TransformToBattery(callback);
|
controller.battery_values[index] = TransformToBattery(callback);
|
||||||
|
|
||||||
|
if (is_configuring) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_charging = false;
|
bool is_charging = false;
|
||||||
bool is_powered = false;
|
bool is_powered = false;
|
||||||
NpadBatteryLevel battery_level = 0;
|
NpadBatteryLevel battery_level = 0;
|
||||||
switch (battery_values) {
|
switch (controller.battery_values[index]) {
|
||||||
case Common::Input::BatteryLevel::Charging:
|
case Common::Input::BatteryLevel::Charging:
|
||||||
is_charging = true;
|
is_charging = true;
|
||||||
is_powered = true;
|
is_powered = true;
|
||||||
@ -933,33 +1139,46 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) {
|
void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) {
|
||||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor); });
|
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); });
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
const auto camera_values = TransformToCamera(callback);
|
controller.camera_values = TransformToCamera(callback);
|
||||||
|
|
||||||
|
if (is_configuring) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
controller.camera_state.sample++;
|
controller.camera_state.sample++;
|
||||||
controller.camera_state.format =
|
controller.camera_state.format =
|
||||||
static_cast<Core::IrSensor::ImageTransferProcessorFormat>(camera_values.format);
|
static_cast<Core::IrSensor::ImageTransferProcessorFormat>(controller.camera_values.format);
|
||||||
controller.camera_state.data = camera_values.data;
|
controller.camera_state.data = controller.camera_values.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) {
|
void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) {
|
||||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController); });
|
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); });
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
const auto force_value = TransformToStick(callback);
|
const auto force_value = TransformToStick(callback);
|
||||||
|
|
||||||
|
controller.ring_analog_value = force_value.x;
|
||||||
|
|
||||||
|
if (is_configuring) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
controller.ring_analog_state.force = force_value.x.value;
|
controller.ring_analog_state.force = force_value.x.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
|
void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
|
||||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc); });
|
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); });
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
const auto nfc_values = TransformToNfc(callback);
|
controller.nfc_values = TransformToNfc(callback);
|
||||||
|
|
||||||
|
if (is_configuring) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
controller.nfc_state = {
|
controller.nfc_state = {
|
||||||
nfc_values.state,
|
controller.nfc_values.state,
|
||||||
nfc_values.data,
|
controller.nfc_values.data,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1190,9 +1409,10 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
|
|||||||
npad_type);
|
npad_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmulatedController::IsControllerFullkey() const {
|
bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
switch (npad_type) {
|
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||||
|
switch (type) {
|
||||||
case NpadStyleIndex::ProController:
|
case NpadStyleIndex::ProController:
|
||||||
case NpadStyleIndex::GameCube:
|
case NpadStyleIndex::GameCube:
|
||||||
case NpadStyleIndex::NES:
|
case NpadStyleIndex::NES:
|
||||||
@ -1205,9 +1425,10 @@ bool EmulatedController::IsControllerFullkey() const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmulatedController::IsControllerSupported() const {
|
bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
switch (npad_type) {
|
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||||
|
switch (type) {
|
||||||
case NpadStyleIndex::ProController:
|
case NpadStyleIndex::ProController:
|
||||||
return supported_style_tag.fullkey.As<bool>();
|
return supported_style_tag.fullkey.As<bool>();
|
||||||
case NpadStyleIndex::Handheld:
|
case NpadStyleIndex::Handheld:
|
||||||
@ -1235,15 +1456,20 @@ bool EmulatedController::IsControllerSupported() const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::Connect() {
|
void EmulatedController::Connect(bool use_temporary_value) {
|
||||||
if (!IsControllerSupported()) {
|
if (!IsControllerSupported(use_temporary_value)) {
|
||||||
LOG_ERROR(Service_HID, "Controller type {} is not supported", npad_type);
|
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||||
|
LOG_ERROR(Service_HID, "Controller type {} is not supported", type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto trigger_guard =
|
auto trigger_guard =
|
||||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected); });
|
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); });
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
|
if (is_configuring) {
|
||||||
|
tmp_is_connected = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_connected) {
|
if (is_connected) {
|
||||||
trigger_guard.Cancel();
|
trigger_guard.Cancel();
|
||||||
@ -1254,8 +1480,12 @@ void EmulatedController::Connect() {
|
|||||||
|
|
||||||
void EmulatedController::Disconnect() {
|
void EmulatedController::Disconnect() {
|
||||||
auto trigger_guard =
|
auto trigger_guard =
|
||||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected); });
|
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); });
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
|
if (is_configuring) {
|
||||||
|
tmp_is_connected = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_connected) {
|
if (!is_connected) {
|
||||||
trigger_guard.Cancel();
|
trigger_guard.Cancel();
|
||||||
@ -1264,8 +1494,11 @@ void EmulatedController::Disconnect() {
|
|||||||
is_connected = false;
|
is_connected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmulatedController::IsConnected() const {
|
bool EmulatedController::IsConnected(bool get_temporary_value) const {
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
|
if (get_temporary_value && is_configuring) {
|
||||||
|
return tmp_is_connected;
|
||||||
|
}
|
||||||
return is_connected;
|
return is_connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1275,14 +1508,27 @@ NpadIdType EmulatedController::GetNpadIdType() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const {
|
NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
if (get_temporary_value && is_configuring) {
|
||||||
|
return tmp_npad_type;
|
||||||
|
}
|
||||||
return npad_type;
|
return npad_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
|
void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
|
||||||
auto trigger_guard =
|
auto trigger_guard =
|
||||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type); });
|
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); });
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
|
|
||||||
|
if (is_configuring) {
|
||||||
|
if (tmp_npad_type == npad_type_) {
|
||||||
|
trigger_guard.Cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tmp_npad_type = npad_type_;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (npad_type == npad_type_) {
|
if (npad_type == npad_type_) {
|
||||||
trigger_guard.Cancel();
|
trigger_guard.Cancel();
|
||||||
return;
|
return;
|
||||||
@ -1322,23 +1568,87 @@ ButtonValues EmulatedController::GetButtonsValues() const {
|
|||||||
return controller.button_values;
|
return controller.button_values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SticksValues EmulatedController::GetSticksValues() const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
return controller.stick_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
TriggerValues EmulatedController::GetTriggersValues() const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
return controller.trigger_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
ControllerMotionValues EmulatedController::GetMotionValues() const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
return controller.motion_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorValues EmulatedController::GetColorsValues() const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
return controller.color_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
BatteryValues EmulatedController::GetBatteryValues() const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
return controller.battery_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
CameraValues EmulatedController::GetCameraValues() const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
return controller.camera_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
RingAnalogValue EmulatedController::GetRingSensorValues() const {
|
||||||
|
return controller.ring_analog_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
HomeButtonState EmulatedController::GetHomeButtons() const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
if (is_configuring) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return controller.home_button_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
CaptureButtonState EmulatedController::GetCaptureButtons() const {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
if (is_configuring) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return controller.capture_button_state;
|
||||||
|
}
|
||||||
|
|
||||||
NpadButtonState EmulatedController::GetNpadButtons() const {
|
NpadButtonState EmulatedController::GetNpadButtons() const {
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
|
if (is_configuring) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
return {controller.npad_button_state.raw & GetTurboButtonMask()};
|
return {controller.npad_button_state.raw & GetTurboButtonMask()};
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugPadButton EmulatedController::GetDebugPadButtons() const {
|
DebugPadButton EmulatedController::GetDebugPadButtons() const {
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
|
if (is_configuring) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
return controller.debug_pad_button_state;
|
return controller.debug_pad_button_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnalogSticks EmulatedController::GetSticks() const {
|
AnalogSticks EmulatedController::GetSticks() const {
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
|
|
||||||
|
if (is_configuring) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
return controller.analog_stick_state;
|
return controller.analog_stick_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
NpadGcTriggerState EmulatedController::GetTriggers() const {
|
NpadGcTriggerState EmulatedController::GetTriggers() const {
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
|
if (is_configuring) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
return controller.gc_trigger_state;
|
return controller.gc_trigger_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1363,7 +1673,6 @@ const CameraState& EmulatedController::GetCamera() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RingSensorForce EmulatedController::GetRingSensorForce() const {
|
RingSensorForce EmulatedController::GetRingSensorForce() const {
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return controller.ring_analog_state;
|
return controller.ring_analog_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1381,10 +1690,13 @@ NpadColor EmulatedController::GetNpadColor(u32 color) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatedController::TriggerOnChange(ControllerTriggerType type) {
|
void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
|
||||||
std::scoped_lock lock{callback_mutex};
|
std::scoped_lock lock{callback_mutex};
|
||||||
for (const auto& poller_pair : callback_list) {
|
for (const auto& poller_pair : callback_list) {
|
||||||
const ControllerUpdateCallback& poller = poller_pair.second;
|
const ControllerUpdateCallback& poller = poller_pair.second;
|
||||||
|
if (!is_npad_service_update && poller.is_npad_service) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (poller.on_change) {
|
if (poller.on_change) {
|
||||||
poller.on_change(type);
|
poller.on_change(type);
|
||||||
}
|
}
|
||||||
|
@ -126,8 +126,16 @@ struct ControllerStatus {
|
|||||||
SticksValues stick_values{};
|
SticksValues stick_values{};
|
||||||
ControllerMotionValues motion_values{};
|
ControllerMotionValues motion_values{};
|
||||||
TriggerValues trigger_values{};
|
TriggerValues trigger_values{};
|
||||||
|
ColorValues color_values{};
|
||||||
|
BatteryValues battery_values{};
|
||||||
|
VibrationValues vibration_values{};
|
||||||
|
CameraValues camera_values{};
|
||||||
|
RingAnalogValue ring_analog_value{};
|
||||||
|
NfcValues nfc_values{};
|
||||||
|
|
||||||
// Data for HID services
|
// Data for HID services
|
||||||
|
HomeButtonState home_button_state{};
|
||||||
|
CaptureButtonState capture_button_state{};
|
||||||
NpadButtonState npad_button_state{};
|
NpadButtonState npad_button_state{};
|
||||||
DebugPadButton debug_pad_button_state{};
|
DebugPadButton debug_pad_button_state{};
|
||||||
AnalogSticks analog_stick_state{};
|
AnalogSticks analog_stick_state{};
|
||||||
@ -159,6 +167,7 @@ enum class ControllerTriggerType {
|
|||||||
|
|
||||||
struct ControllerUpdateCallback {
|
struct ControllerUpdateCallback {
|
||||||
std::function<void(ControllerTriggerType)> on_change;
|
std::function<void(ControllerTriggerType)> on_change;
|
||||||
|
bool is_npad_service;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EmulatedController {
|
class EmulatedController {
|
||||||
@ -201,29 +210,43 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the connected status to true
|
* Sets the connected status to true
|
||||||
|
* @param use_temporary_value If true tmp_npad_type will be used
|
||||||
*/
|
*/
|
||||||
void Connect();
|
void Connect(bool use_temporary_value = false);
|
||||||
|
|
||||||
/// Sets the connected status to false
|
/// Sets the connected status to false
|
||||||
void Disconnect();
|
void Disconnect();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the emulated connected
|
* Is the emulated connected
|
||||||
|
* @param get_temporary_value If true tmp_is_connected will be returned
|
||||||
* @return true if the controller has the connected status
|
* @return true if the controller has the connected status
|
||||||
*/
|
*/
|
||||||
bool IsConnected() const;
|
bool IsConnected(bool get_temporary_value = false) const;
|
||||||
|
|
||||||
/// Removes all callbacks created from input devices
|
/// Removes all callbacks created from input devices
|
||||||
void UnloadInput();
|
void UnloadInput();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the emulated controller into idle mode
|
* Sets the emulated controller into configuring mode
|
||||||
* This prevents the modification of the HID state of the emulated controller by input commands
|
* This prevents the modification of the HID state of the emulated controller by input commands
|
||||||
*/
|
*/
|
||||||
void DisableInput();
|
void EnableConfiguration();
|
||||||
|
|
||||||
/// Returns the emulated controller into normal mode, allowing the modification of the HID state
|
/// Returns the emulated controller into normal mode, allowing the modification of the HID state
|
||||||
void EnableInput();
|
void DisableConfiguration();
|
||||||
|
|
||||||
|
/// Enables Home and Screenshot buttons
|
||||||
|
void EnableSystemButtons();
|
||||||
|
|
||||||
|
/// Disables Home and Screenshot buttons
|
||||||
|
void DisableSystemButtons();
|
||||||
|
|
||||||
|
/// Sets Home and Screenshot buttons to false
|
||||||
|
void ResetSystemButtons();
|
||||||
|
|
||||||
|
/// Returns true if the emulated controller is in configuring mode
|
||||||
|
bool IsConfiguring() const;
|
||||||
|
|
||||||
/// Reload all input devices
|
/// Reload all input devices
|
||||||
void ReloadInput();
|
void ReloadInput();
|
||||||
@ -231,9 +254,75 @@ public:
|
|||||||
/// Overrides current mapped devices with the stored configuration and reloads all input devices
|
/// Overrides current mapped devices with the stored configuration and reloads all input devices
|
||||||
void ReloadFromSettings();
|
void ReloadFromSettings();
|
||||||
|
|
||||||
|
/// Saves the current mapped configuration
|
||||||
|
void SaveCurrentConfig();
|
||||||
|
|
||||||
|
/// Reverts any mapped changes made that weren't saved
|
||||||
|
void RestoreConfig();
|
||||||
|
|
||||||
|
/// Returns a vector of mapped devices from the mapped button and stick parameters
|
||||||
|
std::vector<Common::ParamPackage> GetMappedDevices() const;
|
||||||
|
|
||||||
|
// Returns the current mapped button device
|
||||||
|
Common::ParamPackage GetButtonParam(std::size_t index) const;
|
||||||
|
|
||||||
|
// Returns the current mapped stick device
|
||||||
|
Common::ParamPackage GetStickParam(std::size_t index) const;
|
||||||
|
|
||||||
|
// Returns the current mapped motion device
|
||||||
|
Common::ParamPackage GetMotionParam(std::size_t index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current mapped button device
|
||||||
|
* @param param ParamPackage with controller data to be mapped
|
||||||
|
*/
|
||||||
|
void SetButtonParam(std::size_t index, Common::ParamPackage param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current mapped stick device
|
||||||
|
* @param param ParamPackage with controller data to be mapped
|
||||||
|
*/
|
||||||
|
void SetStickParam(std::size_t index, Common::ParamPackage param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current mapped motion device
|
||||||
|
* @param param ParamPackage with controller data to be mapped
|
||||||
|
*/
|
||||||
|
void SetMotionParam(std::size_t index, Common::ParamPackage param);
|
||||||
|
|
||||||
|
/// Auto calibrates the current motion devices
|
||||||
|
void StartMotionCalibration();
|
||||||
|
|
||||||
/// Returns the latest button status from the controller with parameters
|
/// Returns the latest button status from the controller with parameters
|
||||||
ButtonValues GetButtonsValues() const;
|
ButtonValues GetButtonsValues() const;
|
||||||
|
|
||||||
|
/// Returns the latest analog stick status from the controller with parameters
|
||||||
|
SticksValues GetSticksValues() const;
|
||||||
|
|
||||||
|
/// Returns the latest trigger status from the controller with parameters
|
||||||
|
TriggerValues GetTriggersValues() const;
|
||||||
|
|
||||||
|
/// Returns the latest motion status from the controller with parameters
|
||||||
|
ControllerMotionValues GetMotionValues() const;
|
||||||
|
|
||||||
|
/// Returns the latest color status from the controller with parameters
|
||||||
|
ColorValues GetColorsValues() const;
|
||||||
|
|
||||||
|
/// Returns the latest battery status from the controller with parameters
|
||||||
|
BatteryValues GetBatteryValues() const;
|
||||||
|
|
||||||
|
/// Returns the latest camera status from the controller with parameters
|
||||||
|
CameraValues GetCameraValues() const;
|
||||||
|
|
||||||
|
/// Returns the latest status of analog input from the ring sensor with parameters
|
||||||
|
RingAnalogValue GetRingSensorValues() const;
|
||||||
|
|
||||||
|
/// Returns the latest status of button input for the hid::HomeButton service
|
||||||
|
HomeButtonState GetHomeButtons() const;
|
||||||
|
|
||||||
|
/// Returns the latest status of button input for the hid::CaptureButton service
|
||||||
|
CaptureButtonState GetCaptureButtons() const;
|
||||||
|
|
||||||
/// Returns the latest status of button input for the hid::Npad service
|
/// Returns the latest status of button input for the hid::Npad service
|
||||||
NpadButtonState GetNpadButtons() const;
|
NpadButtonState GetNpadButtons() const;
|
||||||
|
|
||||||
@ -343,15 +432,17 @@ private:
|
|||||||
void LoadVirtualGamepadParams();
|
void LoadVirtualGamepadParams();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param use_temporary_value If true tmp_npad_type will be used
|
||||||
* @return true if the controller style is fullkey
|
* @return true if the controller style is fullkey
|
||||||
*/
|
*/
|
||||||
bool IsControllerFullkey() const;
|
bool IsControllerFullkey(bool use_temporary_value = false) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the current controller type against the supported_style_tag
|
* Checks the current controller type against the supported_style_tag
|
||||||
|
* @param use_temporary_value If true tmp_npad_type will be used
|
||||||
* @return true if the controller is supported
|
* @return true if the controller is supported
|
||||||
*/
|
*/
|
||||||
bool IsControllerSupported() const;
|
bool IsControllerSupported(bool use_temporary_value = false) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the button status of the controller
|
* Updates the button status of the controller
|
||||||
@ -426,8 +517,9 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Triggers a callback that something has changed on the controller status
|
* Triggers a callback that something has changed on the controller status
|
||||||
* @param type Input type of the event to trigger
|
* @param type Input type of the event to trigger
|
||||||
|
* @param is_service_update indicates if this event should only be sent to HID services
|
||||||
*/
|
*/
|
||||||
void TriggerOnChange(ControllerTriggerType type);
|
void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
|
||||||
|
|
||||||
NpadButton GetTurboButtonMask() const;
|
NpadButton GetTurboButtonMask() const;
|
||||||
|
|
||||||
@ -436,10 +528,15 @@ private:
|
|||||||
NpadStyleIndex original_npad_type{NpadStyleIndex::None};
|
NpadStyleIndex original_npad_type{NpadStyleIndex::None};
|
||||||
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
||||||
bool is_connected{false};
|
bool is_connected{false};
|
||||||
bool npad_input_enabled{true};
|
bool is_configuring{false};
|
||||||
|
bool system_buttons_enabled{true};
|
||||||
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
|
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
|
||||||
u32 turbo_button_state{0};
|
u32 turbo_button_state{0};
|
||||||
|
|
||||||
|
// Temporary values to avoid doing changes while the controller is in configuring mode
|
||||||
|
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
|
||||||
|
bool tmp_is_connected{false};
|
||||||
|
|
||||||
ButtonParams button_params;
|
ButtonParams button_params;
|
||||||
StickParams stick_params;
|
StickParams stick_params;
|
||||||
ControllerMotionParams motion_params;
|
ControllerMotionParams motion_params;
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include "core/hid/emulated_controller.h"
|
#include "core/hid/emulated_controller.h"
|
||||||
#include "core/hid/emulated_devices.h"
|
#include "core/hid/emulated_devices.h"
|
||||||
#include "core/hid/hid_core.h"
|
#include "core/hid/hid_core.h"
|
||||||
#include "core/hid/system_controller.h"
|
|
||||||
|
|
||||||
namespace Core::HID {
|
namespace Core::HID {
|
||||||
|
|
||||||
@ -21,16 +20,6 @@ HIDCore::HIDCore()
|
|||||||
player_8{std::make_unique<EmulatedController>(NpadIdType::Player8)},
|
player_8{std::make_unique<EmulatedController>(NpadIdType::Player8)},
|
||||||
other{std::make_unique<EmulatedController>(NpadIdType::Other)},
|
other{std::make_unique<EmulatedController>(NpadIdType::Other)},
|
||||||
handheld{std::make_unique<EmulatedController>(NpadIdType::Handheld)},
|
handheld{std::make_unique<EmulatedController>(NpadIdType::Handheld)},
|
||||||
system_player_1{std::make_unique<SystemController>(NpadIdType::Player1)},
|
|
||||||
system_player_2{std::make_unique<SystemController>(NpadIdType::Player2)},
|
|
||||||
system_player_3{std::make_unique<SystemController>(NpadIdType::Player3)},
|
|
||||||
system_player_4{std::make_unique<SystemController>(NpadIdType::Player4)},
|
|
||||||
system_player_5{std::make_unique<SystemController>(NpadIdType::Player5)},
|
|
||||||
system_player_6{std::make_unique<SystemController>(NpadIdType::Player6)},
|
|
||||||
system_player_7{std::make_unique<SystemController>(NpadIdType::Player7)},
|
|
||||||
system_player_8{std::make_unique<SystemController>(NpadIdType::Player8)},
|
|
||||||
system_other{std::make_unique<SystemController>(NpadIdType::Other)},
|
|
||||||
system_handheld{std::make_unique<SystemController>(NpadIdType::Handheld)},
|
|
||||||
console{std::make_unique<EmulatedConsole>()}, devices{std::make_unique<EmulatedDevices>()} {}
|
console{std::make_unique<EmulatedConsole>()}, devices{std::make_unique<EmulatedDevices>()} {}
|
||||||
|
|
||||||
HIDCore::~HIDCore() = default;
|
HIDCore::~HIDCore() = default;
|
||||||
@ -92,65 +81,6 @@ const EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemController* HIDCore::GetSystemController(NpadIdType npad_id_type) {
|
|
||||||
switch (npad_id_type) {
|
|
||||||
case NpadIdType::Player1:
|
|
||||||
return system_player_1.get();
|
|
||||||
case NpadIdType::Player2:
|
|
||||||
return system_player_2.get();
|
|
||||||
case NpadIdType::Player3:
|
|
||||||
return system_player_3.get();
|
|
||||||
case NpadIdType::Player4:
|
|
||||||
return system_player_4.get();
|
|
||||||
case NpadIdType::Player5:
|
|
||||||
return system_player_5.get();
|
|
||||||
case NpadIdType::Player6:
|
|
||||||
return system_player_6.get();
|
|
||||||
case NpadIdType::Player7:
|
|
||||||
return system_player_7.get();
|
|
||||||
case NpadIdType::Player8:
|
|
||||||
return system_player_8.get();
|
|
||||||
case NpadIdType::Other:
|
|
||||||
return system_other.get();
|
|
||||||
case NpadIdType::Handheld:
|
|
||||||
return system_handheld.get();
|
|
||||||
case NpadIdType::Invalid:
|
|
||||||
default:
|
|
||||||
ASSERT_MSG(false, "Invalid NpadIdType={}", npad_id_type);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const SystemController* HIDCore::GetSystemController(NpadIdType npad_id_type) const {
|
|
||||||
switch (npad_id_type) {
|
|
||||||
case NpadIdType::Player1:
|
|
||||||
return system_player_1.get();
|
|
||||||
case NpadIdType::Player2:
|
|
||||||
return system_player_2.get();
|
|
||||||
case NpadIdType::Player3:
|
|
||||||
return system_player_3.get();
|
|
||||||
case NpadIdType::Player4:
|
|
||||||
return system_player_4.get();
|
|
||||||
case NpadIdType::Player5:
|
|
||||||
return system_player_5.get();
|
|
||||||
case NpadIdType::Player6:
|
|
||||||
return system_player_6.get();
|
|
||||||
case NpadIdType::Player7:
|
|
||||||
return system_player_7.get();
|
|
||||||
case NpadIdType::Player8:
|
|
||||||
return system_player_8.get();
|
|
||||||
case NpadIdType::Other:
|
|
||||||
return system_other.get();
|
|
||||||
case NpadIdType::Handheld:
|
|
||||||
return system_handheld.get();
|
|
||||||
case NpadIdType::Invalid:
|
|
||||||
default:
|
|
||||||
ASSERT_MSG(false, "Invalid NpadIdType={}", npad_id_type);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EmulatedConsole* HIDCore::GetEmulatedConsole() {
|
EmulatedConsole* HIDCore::GetEmulatedConsole() {
|
||||||
return console.get();
|
return console.get();
|
||||||
}
|
}
|
||||||
@ -177,16 +107,16 @@ const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t inde
|
|||||||
|
|
||||||
void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) {
|
void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) {
|
||||||
supported_style_tag.raw = style_tag.raw;
|
supported_style_tag.raw = style_tag.raw;
|
||||||
system_player_1->SetSupportedNpadStyleTag(supported_style_tag);
|
player_1->SetSupportedNpadStyleTag(supported_style_tag);
|
||||||
system_player_2->SetSupportedNpadStyleTag(supported_style_tag);
|
player_2->SetSupportedNpadStyleTag(supported_style_tag);
|
||||||
system_player_3->SetSupportedNpadStyleTag(supported_style_tag);
|
player_3->SetSupportedNpadStyleTag(supported_style_tag);
|
||||||
system_player_4->SetSupportedNpadStyleTag(supported_style_tag);
|
player_4->SetSupportedNpadStyleTag(supported_style_tag);
|
||||||
system_player_5->SetSupportedNpadStyleTag(supported_style_tag);
|
player_5->SetSupportedNpadStyleTag(supported_style_tag);
|
||||||
system_player_6->SetSupportedNpadStyleTag(supported_style_tag);
|
player_6->SetSupportedNpadStyleTag(supported_style_tag);
|
||||||
system_player_7->SetSupportedNpadStyleTag(supported_style_tag);
|
player_7->SetSupportedNpadStyleTag(supported_style_tag);
|
||||||
system_player_8->SetSupportedNpadStyleTag(supported_style_tag);
|
player_8->SetSupportedNpadStyleTag(supported_style_tag);
|
||||||
system_other->SetSupportedNpadStyleTag(supported_style_tag);
|
other->SetSupportedNpadStyleTag(supported_style_tag);
|
||||||
system_handheld->SetSupportedNpadStyleTag(supported_style_tag);
|
handheld->SetSupportedNpadStyleTag(supported_style_tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
NpadStyleTag HIDCore::GetSupportedStyleTag() const {
|
NpadStyleTag HIDCore::GetSupportedStyleTag() const {
|
||||||
@ -225,57 +155,57 @@ NpadIdType HIDCore::GetFirstDisconnectedNpadId() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HIDCore::EnableAllControllerConfiguration() {
|
void HIDCore::EnableAllControllerConfiguration() {
|
||||||
system_player_1->EnableConfiguration();
|
player_1->EnableConfiguration();
|
||||||
system_player_2->EnableConfiguration();
|
player_2->EnableConfiguration();
|
||||||
system_player_3->EnableConfiguration();
|
player_3->EnableConfiguration();
|
||||||
system_player_4->EnableConfiguration();
|
player_4->EnableConfiguration();
|
||||||
system_player_5->EnableConfiguration();
|
player_5->EnableConfiguration();
|
||||||
system_player_6->EnableConfiguration();
|
player_6->EnableConfiguration();
|
||||||
system_player_7->EnableConfiguration();
|
player_7->EnableConfiguration();
|
||||||
system_player_8->EnableConfiguration();
|
player_8->EnableConfiguration();
|
||||||
system_other->EnableConfiguration();
|
other->EnableConfiguration();
|
||||||
system_handheld->EnableConfiguration();
|
handheld->EnableConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HIDCore::DisableAllControllerConfiguration() {
|
void HIDCore::DisableAllControllerConfiguration() {
|
||||||
system_player_1->DisableConfiguration();
|
player_1->DisableConfiguration();
|
||||||
system_player_2->DisableConfiguration();
|
player_2->DisableConfiguration();
|
||||||
system_player_3->DisableConfiguration();
|
player_3->DisableConfiguration();
|
||||||
system_player_4->DisableConfiguration();
|
player_4->DisableConfiguration();
|
||||||
system_player_5->DisableConfiguration();
|
player_5->DisableConfiguration();
|
||||||
system_player_6->DisableConfiguration();
|
player_6->DisableConfiguration();
|
||||||
system_player_7->DisableConfiguration();
|
player_7->DisableConfiguration();
|
||||||
system_player_8->DisableConfiguration();
|
player_8->DisableConfiguration();
|
||||||
system_other->DisableConfiguration();
|
other->DisableConfiguration();
|
||||||
system_handheld->DisableConfiguration();
|
handheld->DisableConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HIDCore::ReloadInputDevices() {
|
void HIDCore::ReloadInputDevices() {
|
||||||
system_player_1->ReloadFromSettings();
|
player_1->ReloadFromSettings();
|
||||||
system_player_2->ReloadFromSettings();
|
player_2->ReloadFromSettings();
|
||||||
system_player_3->ReloadFromSettings();
|
player_3->ReloadFromSettings();
|
||||||
system_player_4->ReloadFromSettings();
|
player_4->ReloadFromSettings();
|
||||||
system_player_5->ReloadFromSettings();
|
player_5->ReloadFromSettings();
|
||||||
system_player_6->ReloadFromSettings();
|
player_6->ReloadFromSettings();
|
||||||
system_player_7->ReloadFromSettings();
|
player_7->ReloadFromSettings();
|
||||||
system_player_8->ReloadFromSettings();
|
player_8->ReloadFromSettings();
|
||||||
system_other->ReloadFromSettings();
|
other->ReloadFromSettings();
|
||||||
system_handheld->ReloadFromSettings();
|
handheld->ReloadFromSettings();
|
||||||
console->ReloadFromSettings();
|
console->ReloadFromSettings();
|
||||||
devices->ReloadFromSettings();
|
devices->ReloadFromSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HIDCore::UnloadInputDevices() {
|
void HIDCore::UnloadInputDevices() {
|
||||||
system_player_1->UnloadInput();
|
player_1->UnloadInput();
|
||||||
system_player_2->UnloadInput();
|
player_2->UnloadInput();
|
||||||
system_player_3->UnloadInput();
|
player_3->UnloadInput();
|
||||||
system_player_4->UnloadInput();
|
player_4->UnloadInput();
|
||||||
system_player_5->UnloadInput();
|
player_5->UnloadInput();
|
||||||
system_player_6->UnloadInput();
|
player_6->UnloadInput();
|
||||||
system_player_7->UnloadInput();
|
player_7->UnloadInput();
|
||||||
system_player_8->UnloadInput();
|
player_8->UnloadInput();
|
||||||
system_other->UnloadInput();
|
other->UnloadInput();
|
||||||
system_handheld->UnloadInput();
|
handheld->UnloadInput();
|
||||||
console->UnloadInput();
|
console->UnloadInput();
|
||||||
devices->UnloadInput();
|
devices->UnloadInput();
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ namespace Core::HID {
|
|||||||
class EmulatedConsole;
|
class EmulatedConsole;
|
||||||
class EmulatedController;
|
class EmulatedController;
|
||||||
class EmulatedDevices;
|
class EmulatedDevices;
|
||||||
class SystemController;
|
|
||||||
} // namespace Core::HID
|
} // namespace Core::HID
|
||||||
|
|
||||||
namespace Core::HID {
|
namespace Core::HID {
|
||||||
@ -31,12 +30,6 @@ public:
|
|||||||
EmulatedController* GetEmulatedControllerByIndex(std::size_t index);
|
EmulatedController* GetEmulatedControllerByIndex(std::size_t index);
|
||||||
const EmulatedController* GetEmulatedControllerByIndex(std::size_t index) const;
|
const EmulatedController* GetEmulatedControllerByIndex(std::size_t index) const;
|
||||||
|
|
||||||
SystemController* GetSystemController(NpadIdType npad_id_type);
|
|
||||||
const SystemController* GetSystemController(NpadIdType npad_id_type) const;
|
|
||||||
|
|
||||||
SystemController* GetSystemControllerByIndex(std::size_t index);
|
|
||||||
const SystemController* GetSystemControllerByIndex(std::size_t index) const;
|
|
||||||
|
|
||||||
EmulatedConsole* GetEmulatedConsole();
|
EmulatedConsole* GetEmulatedConsole();
|
||||||
const EmulatedConsole* GetEmulatedConsole() const;
|
const EmulatedConsole* GetEmulatedConsole() const;
|
||||||
|
|
||||||
@ -83,16 +76,6 @@ private:
|
|||||||
std::unique_ptr<EmulatedController> handheld;
|
std::unique_ptr<EmulatedController> handheld;
|
||||||
std::unique_ptr<EmulatedConsole> console;
|
std::unique_ptr<EmulatedConsole> console;
|
||||||
std::unique_ptr<EmulatedDevices> devices;
|
std::unique_ptr<EmulatedDevices> devices;
|
||||||
std::unique_ptr<SystemController> system_player_1;
|
|
||||||
std::unique_ptr<SystemController> system_player_2;
|
|
||||||
std::unique_ptr<SystemController> system_player_3;
|
|
||||||
std::unique_ptr<SystemController> system_player_4;
|
|
||||||
std::unique_ptr<SystemController> system_player_5;
|
|
||||||
std::unique_ptr<SystemController> system_player_6;
|
|
||||||
std::unique_ptr<SystemController> system_player_7;
|
|
||||||
std::unique_ptr<SystemController> system_player_8;
|
|
||||||
std::unique_ptr<SystemController> system_other;
|
|
||||||
std::unique_ptr<SystemController> system_handheld;
|
|
||||||
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
#include "common/input.h"
|
#include "common/input.h"
|
||||||
|
#include "common/math_util.h"
|
||||||
|
#include "common/quaternion.h"
|
||||||
#include "core/hid/input_converter.h"
|
#include "core/hid/input_converter.h"
|
||||||
|
|
||||||
namespace Core::HID {
|
namespace Core::HID {
|
||||||
@ -81,7 +83,7 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu
|
|||||||
Common::Input::MotionStatus status{};
|
Common::Input::MotionStatus status{};
|
||||||
switch (callback.type) {
|
switch (callback.type) {
|
||||||
case Common::Input::InputType::Button: {
|
case Common::Input::InputType::Button: {
|
||||||
Common::Input::AnalogProperties properties{
|
const Common::Input::AnalogProperties properties{
|
||||||
.deadzone = 0.0f,
|
.deadzone = 0.0f,
|
||||||
.range = 1.0f,
|
.range = 1.0f,
|
||||||
.offset = 0.0f,
|
.offset = 0.0f,
|
||||||
@ -93,31 +95,18 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu
|
|||||||
.raw_value = 0.0f,
|
.raw_value = 0.0f,
|
||||||
.properties = properties,
|
.properties = properties,
|
||||||
};
|
};
|
||||||
status.accel.y = {
|
status.delta_timestamp = 5000;
|
||||||
.value = 0.0f,
|
status.force_update = true;
|
||||||
.raw_value = 0.0f,
|
status.accel.x = default_analog_status;
|
||||||
.properties = properties,
|
status.accel.y = default_analog_status;
|
||||||
};
|
|
||||||
status.accel.z = {
|
status.accel.z = {
|
||||||
.value = 0.0f,
|
.value = 0.0f,
|
||||||
.raw_value = -1.0f,
|
.raw_value = -1.0f,
|
||||||
.properties = properties,
|
.properties = properties,
|
||||||
};
|
};
|
||||||
status.gyro.x = {
|
status.gyro.x = default_analog_status;
|
||||||
.value = 0.0f,
|
status.gyro.y = default_analog_status;
|
||||||
.raw_value = 0.0f,
|
status.gyro.z = default_analog_status;
|
||||||
.properties = properties,
|
|
||||||
};
|
|
||||||
status.gyro.y = {
|
|
||||||
.value = 0.0f,
|
|
||||||
.raw_value = 0.0f,
|
|
||||||
.properties = properties,
|
|
||||||
};
|
|
||||||
status.gyro.z = {
|
|
||||||
.value = 0.0f,
|
|
||||||
.raw_value = 0.0f,
|
|
||||||
.properties = properties,
|
|
||||||
};
|
|
||||||
if (TransformToButton(callback).value) {
|
if (TransformToButton(callback).value) {
|
||||||
std::random_device device;
|
std::random_device device;
|
||||||
std::mt19937 gen(device());
|
std::mt19937 gen(device());
|
||||||
@ -134,6 +123,9 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu
|
|||||||
case Common::Input::InputType::Motion:
|
case Common::Input::InputType::Motion:
|
||||||
status = callback.motion_status;
|
status = callback.motion_status;
|
||||||
break;
|
break;
|
||||||
|
case Common::Input::InputType::VirtualMotion:
|
||||||
|
status = GetVirtualMotion(callback.motion_status);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR(Input, "Conversion from type {} to motion not implemented", callback.type);
|
LOG_ERROR(Input, "Conversion from type {} to motion not implemented", callback.type);
|
||||||
break;
|
break;
|
||||||
@ -437,4 +429,32 @@ void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Common::Input::MotionStatus GetVirtualMotion(Common::Input::MotionStatus input_data,
|
||||||
|
Common::Vec3f last_giro) {
|
||||||
|
Common::Input::MotionStatus motion_status = input_data;
|
||||||
|
|
||||||
|
// Axis data is stored in the gyro value
|
||||||
|
float wx = input_data.gyro.x.raw_value;
|
||||||
|
float wy = input_data.gyro.y.raw_value;
|
||||||
|
|
||||||
|
float rotX = (wy * 2 - 1.0f) * 135.0f; // up/down best
|
||||||
|
float rotY = (wx * 2 - 1.0f) * -180.0f; // left/right
|
||||||
|
float rotZ = input_data.gyro.y.raw_value * 14.0f + m_lastGyroRotation.z;
|
||||||
|
|
||||||
|
Common::Vec3f rotation(rotX - m_lastGyroRotation.x, (rotY - m_lastGyroRotation.y) * 15.0f,
|
||||||
|
rotZ - m_lastGyroRotation.z);
|
||||||
|
|
||||||
|
rotation.x = std::min(1.0f, std::max(-1.0f, rotation.x / 360.0f));
|
||||||
|
rotation.y = std::min(1.0f, std::max(-1.0f, rotation.y / 360.0f));
|
||||||
|
rotation.z = std::min(1.0f, std::max(-1.0f, rotation.z / 360.0f));
|
||||||
|
|
||||||
|
motion_status.gyro.x.raw_value = rotation.x;
|
||||||
|
motion_status.gyro.y.raw_value = rotation.y;
|
||||||
|
motion_status.gyro.z.raw_value = rotation.z;
|
||||||
|
|
||||||
|
motion_status.accel.x.raw_value = 0.0f;
|
||||||
|
motion_status.accel.y.raw_value = 0.0f;
|
||||||
|
motion_status.accel.z.raw_value = -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Core::HID
|
} // namespace Core::HID
|
||||||
|
@ -116,4 +116,21 @@ void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value);
|
|||||||
void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y,
|
void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y,
|
||||||
bool clamp_value);
|
bool clamp_value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts raw stick data into a valid stick value
|
||||||
|
* @param analog_x raw analog data and properties for the x-axis
|
||||||
|
* @param analog_y raw analog data and properties for the y-axis
|
||||||
|
* @param clamp_value bool that determines if the value needs to be clamped into the unit circle.
|
||||||
|
*/
|
||||||
|
void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y,
|
||||||
|
bool clamp_value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the accelerometer value needed to reach the axis position as if it was a pointer to a screen
|
||||||
|
*
|
||||||
|
* @param input_data Motion status containing the position of all 3 axis
|
||||||
|
* @return Motion status with accelerometer data
|
||||||
|
*/
|
||||||
|
Common::Input::MotionStatus GetVirtualMotion(Common::Input::MotionStatus input_data);
|
||||||
|
|
||||||
} // namespace Core::HID
|
} // namespace Core::HID
|
||||||
|
@ -1,860 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <common/scope_exit.h>
|
|
||||||
|
|
||||||
#include "common/polyfill_ranges.h"
|
|
||||||
#include "common/thread.h"
|
|
||||||
#include "core/hid/system_controller.h"
|
|
||||||
#include "core/hid/input_converter.h"
|
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
|
|
||||||
constexpr s32 HID_TRIGGER_MAX = 0x7fff;
|
|
||||||
|
|
||||||
SystemController::SystemController(NpadIdType npad_id_type_) : npad_id_type(npad_id_type_) {}
|
|
||||||
|
|
||||||
SystemController::~SystemController() = default;
|
|
||||||
|
|
||||||
NpadStyleIndex SystemController::MapSettingsTypeToNPad(Settings::ControllerType type) {
|
|
||||||
switch (type) {
|
|
||||||
case Settings::ControllerType::ProController:
|
|
||||||
return NpadStyleIndex::ProController;
|
|
||||||
case Settings::ControllerType::DualJoyconDetached:
|
|
||||||
return NpadStyleIndex::JoyconDual;
|
|
||||||
case Settings::ControllerType::LeftJoycon:
|
|
||||||
return NpadStyleIndex::JoyconLeft;
|
|
||||||
case Settings::ControllerType::RightJoycon:
|
|
||||||
return NpadStyleIndex::JoyconRight;
|
|
||||||
case Settings::ControllerType::Handheld:
|
|
||||||
return NpadStyleIndex::Handheld;
|
|
||||||
case Settings::ControllerType::GameCube:
|
|
||||||
return NpadStyleIndex::GameCube;
|
|
||||||
case Settings::ControllerType::Pokeball:
|
|
||||||
return NpadStyleIndex::Pokeball;
|
|
||||||
case Settings::ControllerType::NES:
|
|
||||||
return NpadStyleIndex::NES;
|
|
||||||
case Settings::ControllerType::SNES:
|
|
||||||
return NpadStyleIndex::SNES;
|
|
||||||
case Settings::ControllerType::N64:
|
|
||||||
return NpadStyleIndex::N64;
|
|
||||||
case Settings::ControllerType::SegaGenesis:
|
|
||||||
return NpadStyleIndex::SegaGenesis;
|
|
||||||
default:
|
|
||||||
return NpadStyleIndex::ProController;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::ControllerType SystemController::MapNPadToSettingsType(NpadStyleIndex type) {
|
|
||||||
switch (type) {
|
|
||||||
case NpadStyleIndex::ProController:
|
|
||||||
return Settings::ControllerType::ProController;
|
|
||||||
case NpadStyleIndex::JoyconDual:
|
|
||||||
return Settings::ControllerType::DualJoyconDetached;
|
|
||||||
case NpadStyleIndex::JoyconLeft:
|
|
||||||
return Settings::ControllerType::LeftJoycon;
|
|
||||||
case NpadStyleIndex::JoyconRight:
|
|
||||||
return Settings::ControllerType::RightJoycon;
|
|
||||||
case NpadStyleIndex::Handheld:
|
|
||||||
return Settings::ControllerType::Handheld;
|
|
||||||
case NpadStyleIndex::GameCube:
|
|
||||||
return Settings::ControllerType::GameCube;
|
|
||||||
case NpadStyleIndex::Pokeball:
|
|
||||||
return Settings::ControllerType::Pokeball;
|
|
||||||
case NpadStyleIndex::NES:
|
|
||||||
return Settings::ControllerType::NES;
|
|
||||||
case NpadStyleIndex::SNES:
|
|
||||||
return Settings::ControllerType::SNES;
|
|
||||||
case NpadStyleIndex::N64:
|
|
||||||
return Settings::ControllerType::N64;
|
|
||||||
case NpadStyleIndex::SegaGenesis:
|
|
||||||
return Settings::ControllerType::SegaGenesis;
|
|
||||||
default:
|
|
||||||
return Settings::ControllerType::ProController;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::ReloadFromSettings() {
|
|
||||||
const auto player_index = NpadIdTypeToIndex(npad_id_type);
|
|
||||||
const auto& player = Settings::values.players.GetValue()[player_index];
|
|
||||||
|
|
||||||
for (std::size_t index = 0; index < player.buttons.size(); ++index) {
|
|
||||||
button_params[index] = Common::ParamPackage(player.buttons[index]);
|
|
||||||
}
|
|
||||||
for (std::size_t index = 0; index < player.analogs.size(); ++index) {
|
|
||||||
stick_params[index] = Common::ParamPackage(player.analogs[index]);
|
|
||||||
}
|
|
||||||
for (std::size_t index = 0; index < player.motions.size(); ++index) {
|
|
||||||
motion_params[index] = Common::ParamPackage(player.motions[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ring_params[0] = Common::ParamPackage(Settings::values.ringcon_analogs);
|
|
||||||
|
|
||||||
// Other or debug controller should always be a pro controller
|
|
||||||
if (npad_id_type != NpadIdType::Other) {
|
|
||||||
SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
|
|
||||||
original_npad_type = npad_type;
|
|
||||||
} else {
|
|
||||||
SetNpadStyleIndex(NpadStyleIndex::ProController);
|
|
||||||
original_npad_type = npad_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
Disconnect();
|
|
||||||
if (player.connected) {
|
|
||||||
Connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReloadInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::LoadDevices() {
|
|
||||||
// TODO(german77): Use more buttons to detect the correct device
|
|
||||||
const auto left_joycon = button_params[Settings::NativeButton::DRight];
|
|
||||||
const auto right_joycon = button_params[Settings::NativeButton::A];
|
|
||||||
|
|
||||||
// Triggers for GC controllers
|
|
||||||
trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL];
|
|
||||||
trigger_params[RightIndex] = button_params[Settings::NativeButton::ZR];
|
|
||||||
|
|
||||||
std::ranges::transform(button_params, button_devices.begin(), Common::Input::CreateInputDevice);
|
|
||||||
std::ranges::transform(stick_params, stick_devices.begin(), Common::Input::CreateInputDevice);
|
|
||||||
std::ranges::transform(motion_params, motion_devices.begin(), Common::Input::CreateInputDevice);
|
|
||||||
std::ranges::transform(trigger_params, trigger_devices.begin(),
|
|
||||||
Common::Input::CreateInputDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::ReloadInput() {
|
|
||||||
// If you load any device here add the equivalent to the UnloadInput() function
|
|
||||||
LoadDevices();
|
|
||||||
for (std::size_t index = 0; index < button_devices.size(); ++index) {
|
|
||||||
if (!button_devices[index]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto uuid = Common::UUID{button_params[index].Get("guid", "")};
|
|
||||||
button_devices[index]->SetCallback({
|
|
||||||
.on_change =
|
|
||||||
[this, index, uuid](const Common::Input::CallbackStatus& callback) {
|
|
||||||
SetButton(callback, index, uuid);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
button_devices[index]->ForceUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t index = 0; index < stick_devices.size(); ++index) {
|
|
||||||
if (!stick_devices[index]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto uuid = Common::UUID{stick_params[index].Get("guid", "")};
|
|
||||||
stick_devices[index]->SetCallback({
|
|
||||||
.on_change =
|
|
||||||
[this, index, uuid](const Common::Input::CallbackStatus& callback) {
|
|
||||||
SetStick(callback, index, uuid);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
stick_devices[index]->ForceUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t index = 0; index < trigger_devices.size(); ++index) {
|
|
||||||
if (!trigger_devices[index]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto uuid = Common::UUID{trigger_params[index].Get("guid", "")};
|
|
||||||
trigger_devices[index]->SetCallback({
|
|
||||||
.on_change =
|
|
||||||
[this, index, uuid](const Common::Input::CallbackStatus& callback) {
|
|
||||||
SetTrigger(callback, index, uuid);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
trigger_devices[index]->ForceUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::UnloadInput() {
|
|
||||||
for (auto& button : button_devices) {
|
|
||||||
button.reset();
|
|
||||||
}
|
|
||||||
for (auto& stick : stick_devices) {
|
|
||||||
stick.reset();
|
|
||||||
}
|
|
||||||
for (auto& motion : motion_devices) {
|
|
||||||
motion.reset();
|
|
||||||
}
|
|
||||||
for (auto& trigger : trigger_devices) {
|
|
||||||
trigger.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::EnableConfiguration() {
|
|
||||||
is_configuring = true;
|
|
||||||
tmp_is_connected = is_connected;
|
|
||||||
tmp_npad_type = npad_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::DisableConfiguration() {
|
|
||||||
is_configuring = false;
|
|
||||||
|
|
||||||
// Apply temporary npad type to the real controller
|
|
||||||
if (tmp_npad_type != npad_type) {
|
|
||||||
if (is_connected) {
|
|
||||||
Disconnect();
|
|
||||||
}
|
|
||||||
SetNpadStyleIndex(tmp_npad_type);
|
|
||||||
original_npad_type = tmp_npad_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply temporary connected status to the real controller
|
|
||||||
if (tmp_is_connected != is_connected) {
|
|
||||||
if (tmp_is_connected) {
|
|
||||||
Connect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::EnableSystemButtons() {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
system_buttons_enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::DisableSystemButtons() {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
system_buttons_enabled = false;
|
|
||||||
controller.home_button_state.raw = 0;
|
|
||||||
controller.capture_button_state.raw = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::ResetSystemButtons() {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
controller.home_button_state.home.Assign(false);
|
|
||||||
controller.capture_button_state.capture.Assign(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SystemController::IsConfiguring() const {
|
|
||||||
return is_configuring;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::SaveCurrentConfig() {
|
|
||||||
const auto player_index = NpadIdTypeToIndex(npad_id_type);
|
|
||||||
auto& player = Settings::values.players.GetValue()[player_index];
|
|
||||||
player.connected = is_connected;
|
|
||||||
player.controller_type = MapNPadToSettingsType(npad_type);
|
|
||||||
for (std::size_t index = 0; index < player.buttons.size(); ++index) {
|
|
||||||
player.buttons[index] = button_params[index].Serialize();
|
|
||||||
}
|
|
||||||
for (std::size_t index = 0; index < player.analogs.size(); ++index) {
|
|
||||||
player.analogs[index] = stick_params[index].Serialize();
|
|
||||||
}
|
|
||||||
for (std::size_t index = 0; index < player.motions.size(); ++index) {
|
|
||||||
player.motions[index] = motion_params[index].Serialize();
|
|
||||||
}
|
|
||||||
if (npad_id_type == NpadIdType::Player1) {
|
|
||||||
Settings::values.ringcon_analogs = ring_params[0].Serialize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::RestoreConfig() {
|
|
||||||
if (!is_configuring) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ReloadFromSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Common::ParamPackage> SystemController::GetMappedDevices() const {
|
|
||||||
std::vector<Common::ParamPackage> devices;
|
|
||||||
for (const auto& param : button_params) {
|
|
||||||
if (!param.Has("engine")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto devices_it = std::find_if(
|
|
||||||
devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) {
|
|
||||||
return param.Get("engine", "") == param_.Get("engine", "") &&
|
|
||||||
param.Get("guid", "") == param_.Get("guid", "") &&
|
|
||||||
param.Get("port", 0) == param_.Get("port", 0) &&
|
|
||||||
param.Get("pad", 0) == param_.Get("pad", 0);
|
|
||||||
});
|
|
||||||
if (devices_it != devices.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& device = devices.emplace_back();
|
|
||||||
device.Set("engine", param.Get("engine", ""));
|
|
||||||
device.Set("guid", param.Get("guid", ""));
|
|
||||||
device.Set("port", param.Get("port", 0));
|
|
||||||
device.Set("pad", param.Get("pad", 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& param : stick_params) {
|
|
||||||
if (!param.Has("engine")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (param.Get("engine", "") == "analog_from_button") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto devices_it = std::find_if(
|
|
||||||
devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) {
|
|
||||||
return param.Get("engine", "") == param_.Get("engine", "") &&
|
|
||||||
param.Get("guid", "") == param_.Get("guid", "") &&
|
|
||||||
param.Get("port", 0) == param_.Get("port", 0) &&
|
|
||||||
param.Get("pad", 0) == param_.Get("pad", 0);
|
|
||||||
});
|
|
||||||
if (devices_it != devices.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& device = devices.emplace_back();
|
|
||||||
device.Set("engine", param.Get("engine", ""));
|
|
||||||
device.Set("guid", param.Get("guid", ""));
|
|
||||||
device.Set("port", param.Get("port", 0));
|
|
||||||
device.Set("pad", param.Get("pad", 0));
|
|
||||||
}
|
|
||||||
return devices;
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::ParamPackage SystemController::GetButtonParam(std::size_t index) const {
|
|
||||||
if (index >= button_params.size()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return button_params[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::ParamPackage SystemController::GetStickParam(std::size_t index) const {
|
|
||||||
if (index >= stick_params.size()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return stick_params[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::ParamPackage SystemController::GetMotionParam(std::size_t index) const {
|
|
||||||
if (index >= motion_params.size()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return motion_params[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::SetButtonParam(std::size_t index, Common::ParamPackage param) {
|
|
||||||
if (index >= button_params.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
button_params[index] = std::move(param);
|
|
||||||
ReloadInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::SetStickParam(std::size_t index, Common::ParamPackage param) {
|
|
||||||
if (index >= stick_params.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
stick_params[index] = std::move(param);
|
|
||||||
ReloadInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::SetMotionParam(std::size_t index, Common::ParamPackage param) {
|
|
||||||
if (index >= motion_params.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
motion_params[index] = std::move(param);
|
|
||||||
ReloadInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
|
|
||||||
Common::UUID uuid) {
|
|
||||||
if (index >= controller.button_values.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::unique_lock lock{mutex};
|
|
||||||
bool value_changed = false;
|
|
||||||
const auto new_status = TransformToButton(callback);
|
|
||||||
auto& current_status = controller.button_values[index];
|
|
||||||
|
|
||||||
// Only read button values that have the same uuid or are pressed once
|
|
||||||
if (current_status.uuid != uuid) {
|
|
||||||
if (!new_status.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current_status.toggle = new_status.toggle;
|
|
||||||
current_status.turbo = new_status.turbo;
|
|
||||||
current_status.uuid = uuid;
|
|
||||||
|
|
||||||
// Update button status with current
|
|
||||||
if (!current_status.toggle) {
|
|
||||||
current_status.locked = false;
|
|
||||||
if (current_status.value != new_status.value) {
|
|
||||||
current_status.value = new_status.value;
|
|
||||||
value_changed = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Toggle button and lock status
|
|
||||||
if (new_status.value && !current_status.locked) {
|
|
||||||
current_status.locked = true;
|
|
||||||
current_status.value = !current_status.value;
|
|
||||||
value_changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlock button ready for next press
|
|
||||||
if (!new_status.value && current_status.locked) {
|
|
||||||
current_status.locked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value_changed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_configuring) {
|
|
||||||
controller.npad_button_state.raw = NpadButton::None;
|
|
||||||
controller.home_button_state.raw = 0;
|
|
||||||
controller.capture_button_state.raw = 0;
|
|
||||||
lock.unlock();
|
|
||||||
TriggerOnChange(ControllerTriggerType::Button, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GC controllers have triggers not buttons
|
|
||||||
if (npad_type == NpadStyleIndex::GameCube) {
|
|
||||||
if (index == Settings::NativeButton::ZR) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (index == Settings::NativeButton::ZL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (index) {
|
|
||||||
case Settings::NativeButton::A:
|
|
||||||
controller.npad_button_state.a.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::B:
|
|
||||||
controller.npad_button_state.b.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::X:
|
|
||||||
controller.npad_button_state.x.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::Y:
|
|
||||||
controller.npad_button_state.y.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::LStick:
|
|
||||||
controller.npad_button_state.stick_l.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::RStick:
|
|
||||||
controller.npad_button_state.stick_r.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::L:
|
|
||||||
controller.npad_button_state.l.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::R:
|
|
||||||
controller.npad_button_state.r.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::ZL:
|
|
||||||
controller.npad_button_state.zl.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::ZR:
|
|
||||||
controller.npad_button_state.zr.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::Plus:
|
|
||||||
controller.npad_button_state.plus.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::Minus:
|
|
||||||
controller.npad_button_state.minus.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::DLeft:
|
|
||||||
controller.npad_button_state.left.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::DUp:
|
|
||||||
controller.npad_button_state.up.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::DRight:
|
|
||||||
controller.npad_button_state.right.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::DDown:
|
|
||||||
controller.npad_button_state.down.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::SL:
|
|
||||||
controller.npad_button_state.left_sl.Assign(current_status.value);
|
|
||||||
controller.npad_button_state.right_sl.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::SR:
|
|
||||||
controller.npad_button_state.left_sr.Assign(current_status.value);
|
|
||||||
controller.npad_button_state.right_sr.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::Home:
|
|
||||||
if (!system_buttons_enabled) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
controller.home_button_state.home.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeButton::Screenshot:
|
|
||||||
if (!system_buttons_enabled) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
controller.capture_button_state.capture.Assign(current_status.value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
if (!is_connected) {
|
|
||||||
if (npad_id_type == NpadIdType::Player1 && npad_type != NpadStyleIndex::Handheld) {
|
|
||||||
Connect();
|
|
||||||
}
|
|
||||||
if (npad_id_type == NpadIdType::Handheld && npad_type == NpadStyleIndex::Handheld) {
|
|
||||||
Connect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TriggerOnChange(ControllerTriggerType::Button, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
|
|
||||||
Common::UUID uuid) {
|
|
||||||
if (index >= controller.stick_values.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto trigger_guard =
|
|
||||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); });
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
const auto stick_value = TransformToStick(callback);
|
|
||||||
|
|
||||||
// Only read stick values that have the same uuid or are over the threshold to avoid flapping
|
|
||||||
if (controller.stick_values[index].uuid != uuid) {
|
|
||||||
if (!stick_value.down && !stick_value.up && !stick_value.left &&
|
|
||||||
!stick_value.right) {
|
|
||||||
trigger_guard.Cancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.stick_values[index] = stick_value;
|
|
||||||
controller.stick_values[index].uuid = uuid;
|
|
||||||
|
|
||||||
if (is_configuring) {
|
|
||||||
controller.analog_stick_state.left = {};
|
|
||||||
controller.analog_stick_state.right = {};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AnalogStickState stick{
|
|
||||||
.x = static_cast<s32>(controller.stick_values[index].x.value * HID_JOYSTICK_MAX),
|
|
||||||
.y = static_cast<s32>(controller.stick_values[index].y.value * HID_JOYSTICK_MAX),
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (index) {
|
|
||||||
case Settings::NativeAnalog::LStick:
|
|
||||||
controller.analog_stick_state.left = stick;
|
|
||||||
controller.npad_button_state.stick_l_left.Assign(controller.stick_values[index].left);
|
|
||||||
controller.npad_button_state.stick_l_up.Assign(controller.stick_values[index].up);
|
|
||||||
controller.npad_button_state.stick_l_right.Assign(controller.stick_values[index].right);
|
|
||||||
controller.npad_button_state.stick_l_down.Assign(controller.stick_values[index].down);
|
|
||||||
break;
|
|
||||||
case Settings::NativeAnalog::RStick:
|
|
||||||
controller.analog_stick_state.right = stick;
|
|
||||||
controller.npad_button_state.stick_r_left.Assign(controller.stick_values[index].left);
|
|
||||||
controller.npad_button_state.stick_r_up.Assign(controller.stick_values[index].up);
|
|
||||||
controller.npad_button_state.stick_r_right.Assign(controller.stick_values[index].right);
|
|
||||||
controller.npad_button_state.stick_r_down.Assign(controller.stick_values[index].down);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::SetTrigger(const Common::Input::CallbackStatus& callback,
|
|
||||||
std::size_t index, Common::UUID uuid) {
|
|
||||||
if (index >= controller.trigger_values.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto trigger_guard =
|
|
||||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); });
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
const auto trigger_value = TransformToTrigger(callback);
|
|
||||||
|
|
||||||
// Only read trigger values that have the same uuid or are pressed once
|
|
||||||
if (controller.trigger_values[index].uuid != uuid) {
|
|
||||||
if (!trigger_value.pressed.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.trigger_values[index] = trigger_value;
|
|
||||||
controller.trigger_values[index].uuid = uuid;
|
|
||||||
|
|
||||||
if (is_configuring) {
|
|
||||||
controller.gc_trigger_state.left = 0;
|
|
||||||
controller.gc_trigger_state.right = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only GC controllers have analog triggers
|
|
||||||
if (npad_type != NpadStyleIndex::GameCube) {
|
|
||||||
trigger_guard.Cancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& trigger = controller.trigger_values[index];
|
|
||||||
|
|
||||||
switch (index) {
|
|
||||||
case Settings::NativeTrigger::LTrigger:
|
|
||||||
controller.gc_trigger_state.left = static_cast<s32>(trigger.analog.value * HID_TRIGGER_MAX);
|
|
||||||
controller.npad_button_state.zl.Assign(trigger.pressed.value);
|
|
||||||
break;
|
|
||||||
case Settings::NativeTrigger::RTrigger:
|
|
||||||
controller.gc_trigger_state.right =
|
|
||||||
static_cast<s32>(trigger.analog.value * HID_TRIGGER_MAX);
|
|
||||||
controller.npad_button_state.zr.Assign(trigger.pressed.value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) {
|
|
||||||
supported_style_tag = supported_styles;
|
|
||||||
if (!is_connected) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to reconnect with the original type
|
|
||||||
if (npad_type != original_npad_type) {
|
|
||||||
Disconnect();
|
|
||||||
const auto current_npad_type = npad_type;
|
|
||||||
SetNpadStyleIndex(original_npad_type);
|
|
||||||
if (IsControllerSupported()) {
|
|
||||||
Connect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SetNpadStyleIndex(current_npad_type);
|
|
||||||
Connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsControllerSupported()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Disconnect();
|
|
||||||
|
|
||||||
// Fallback Fullkey controllers to Pro controllers
|
|
||||||
if (IsControllerFullkey() && supported_style_tag.fullkey) {
|
|
||||||
LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
|
|
||||||
SetNpadStyleIndex(NpadStyleIndex::ProController);
|
|
||||||
Connect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback Dual joycon controllers to Pro controllers
|
|
||||||
if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) {
|
|
||||||
LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
|
|
||||||
SetNpadStyleIndex(NpadStyleIndex::ProController);
|
|
||||||
Connect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback Pro controllers to Dual joycon
|
|
||||||
if (npad_type == NpadStyleIndex::ProController && supported_style_tag.joycon_dual) {
|
|
||||||
LOG_WARNING(Service_HID, "Reconnecting controller type {} as Dual Joycons", npad_type);
|
|
||||||
SetNpadStyleIndex(NpadStyleIndex::JoyconDual);
|
|
||||||
Connect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller",
|
|
||||||
npad_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SystemController::IsControllerFullkey(bool use_temporary_value) const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
|
||||||
switch (type) {
|
|
||||||
case NpadStyleIndex::ProController:
|
|
||||||
case NpadStyleIndex::GameCube:
|
|
||||||
case NpadStyleIndex::NES:
|
|
||||||
case NpadStyleIndex::SNES:
|
|
||||||
case NpadStyleIndex::N64:
|
|
||||||
case NpadStyleIndex::SegaGenesis:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SystemController::IsControllerSupported(bool use_temporary_value) const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
|
||||||
switch (type) {
|
|
||||||
case NpadStyleIndex::ProController:
|
|
||||||
return supported_style_tag.fullkey.As<bool>();
|
|
||||||
case NpadStyleIndex::Handheld:
|
|
||||||
return supported_style_tag.handheld.As<bool>();
|
|
||||||
case NpadStyleIndex::JoyconDual:
|
|
||||||
return supported_style_tag.joycon_dual.As<bool>();
|
|
||||||
case NpadStyleIndex::JoyconLeft:
|
|
||||||
return supported_style_tag.joycon_left.As<bool>();
|
|
||||||
case NpadStyleIndex::JoyconRight:
|
|
||||||
return supported_style_tag.joycon_right.As<bool>();
|
|
||||||
case NpadStyleIndex::GameCube:
|
|
||||||
return supported_style_tag.gamecube.As<bool>();
|
|
||||||
case NpadStyleIndex::Pokeball:
|
|
||||||
return supported_style_tag.palma.As<bool>();
|
|
||||||
case NpadStyleIndex::NES:
|
|
||||||
return supported_style_tag.lark.As<bool>();
|
|
||||||
case NpadStyleIndex::SNES:
|
|
||||||
return supported_style_tag.lucia.As<bool>();
|
|
||||||
case NpadStyleIndex::N64:
|
|
||||||
return supported_style_tag.lagoon.As<bool>();
|
|
||||||
case NpadStyleIndex::SegaGenesis:
|
|
||||||
return supported_style_tag.lager.As<bool>();
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::Connect(bool use_temporary_value) {
|
|
||||||
if (!IsControllerSupported(use_temporary_value)) {
|
|
||||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
|
||||||
LOG_ERROR(Service_HID, "Controller type {} is not supported", type);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto trigger_guard =
|
|
||||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); });
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (is_configuring) {
|
|
||||||
tmp_is_connected = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_connected) {
|
|
||||||
trigger_guard.Cancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
is_connected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::Disconnect() {
|
|
||||||
auto trigger_guard =
|
|
||||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); });
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (is_configuring) {
|
|
||||||
tmp_is_connected = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_connected) {
|
|
||||||
trigger_guard.Cancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
is_connected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SystemController::IsConnected(bool get_temporary_value) const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (get_temporary_value && is_configuring) {
|
|
||||||
return tmp_is_connected;
|
|
||||||
}
|
|
||||||
return is_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
NpadIdType SystemController::GetNpadIdType() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return npad_id_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
NpadStyleIndex SystemController::GetNpadStyleIndex(bool get_temporary_value) const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (get_temporary_value && is_configuring) {
|
|
||||||
return tmp_npad_type;
|
|
||||||
}
|
|
||||||
return npad_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
|
|
||||||
auto trigger_guard =
|
|
||||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); });
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
|
|
||||||
if (is_configuring) {
|
|
||||||
if (tmp_npad_type == npad_type_) {
|
|
||||||
trigger_guard.Cancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tmp_npad_type = npad_type_;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (npad_type == npad_type_) {
|
|
||||||
trigger_guard.Cancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (is_connected) {
|
|
||||||
LOG_WARNING(Service_HID, "Controller {} type changed while it's connected",
|
|
||||||
NpadIdTypeToIndex(npad_id_type));
|
|
||||||
}
|
|
||||||
npad_type = npad_type_;
|
|
||||||
}
|
|
||||||
|
|
||||||
ButtonValues SystemController::GetButtonsValues() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return controller.button_values;
|
|
||||||
}
|
|
||||||
|
|
||||||
SticksValues SystemController::GetSticksValues() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return controller.stick_values;
|
|
||||||
}
|
|
||||||
|
|
||||||
TriggerValues SystemController::GetTriggersValues() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return controller.trigger_values;
|
|
||||||
}
|
|
||||||
|
|
||||||
HomeButtonState SystemController::GetHomeButtons() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return controller.home_button_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
CaptureButtonState SystemController::GetCaptureButtons() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return controller.capture_button_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
NpadButtonState SystemController::GetNpadButtons() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return controller.npad_button_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnalogSticks SystemController::GetSticks() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return controller.analog_stick_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
NpadGcTriggerState SystemController::GetTriggers() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return controller.gc_trigger_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
|
|
||||||
std::scoped_lock lock{callback_mutex};
|
|
||||||
for (const auto& poller_pair : callback_list) {
|
|
||||||
const ControllerUpdateCallback& poller = poller_pair.second;
|
|
||||||
if (!is_npad_service_update && poller.is_npad_service) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (poller.on_change) {
|
|
||||||
poller.on_change(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int SystemController::SetCallback(ControllerUpdateCallback update_callback) {
|
|
||||||
std::scoped_lock lock{callback_mutex};
|
|
||||||
callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
|
|
||||||
return last_callback_key++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemController::DeleteCallback(int key) {
|
|
||||||
std::scoped_lock lock{callback_mutex};
|
|
||||||
const auto& iterator = callback_list.find(key);
|
|
||||||
if (iterator == callback_list.end()) {
|
|
||||||
LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback_list.erase(iterator);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Core::HID
|
|
@ -1,330 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/input.h"
|
|
||||||
#include "common/param_package.h"
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "common/vector_math.h"
|
|
||||||
#include "core/hid/hid_types.h"
|
|
||||||
#include "core/hid/irs_types.h"
|
|
||||||
#include "core/hid/motion_input.h"
|
|
||||||
|
|
||||||
namespace Core::HID {
|
|
||||||
const std::size_t max_emulated_controllers = 2;
|
|
||||||
const std::size_t output_devices_size = 4;
|
|
||||||
struct ControllerMotionInfo {
|
|
||||||
Common::Input::MotionStatus raw_status{};
|
|
||||||
MotionInput emulated{};
|
|
||||||
};
|
|
||||||
|
|
||||||
using ButtonDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeButton::NumButtons>;
|
|
||||||
using StickDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeAnalog::NumAnalogs>;
|
|
||||||
using ControllerMotionDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMotion::NumMotions>;
|
|
||||||
using TriggerDevices =
|
|
||||||
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>;
|
|
||||||
|
|
||||||
using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
|
|
||||||
using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
|
|
||||||
using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>;
|
|
||||||
using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>;
|
|
||||||
using RingAnalogParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
|
||||||
|
|
||||||
using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>;
|
|
||||||
using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>;
|
|
||||||
using TriggerValues =
|
|
||||||
std::array<Common::Input::TriggerStatus, Settings::NativeTrigger::NumTriggers>;
|
|
||||||
|
|
||||||
struct AnalogSticks {
|
|
||||||
AnalogStickState left{};
|
|
||||||
AnalogStickState right{};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum EmulatedDeviceIndex : u8 {
|
|
||||||
LeftIndex,
|
|
||||||
RightIndex,
|
|
||||||
DualIndex,
|
|
||||||
AllDevices,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ControllerStatus {
|
|
||||||
// Data from input_common
|
|
||||||
ButtonValues button_values{};
|
|
||||||
SticksValues stick_values{};
|
|
||||||
TriggerValues trigger_values{};
|
|
||||||
|
|
||||||
// Data for HID services
|
|
||||||
HomeButtonState home_button_state{};
|
|
||||||
CaptureButtonState capture_button_state{};
|
|
||||||
NpadButtonState npad_button_state{};
|
|
||||||
AnalogSticks analog_stick_state{};
|
|
||||||
NpadGcTriggerState gc_trigger_state{};
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ControllerTriggerType {
|
|
||||||
Button,
|
|
||||||
Stick,
|
|
||||||
Trigger,
|
|
||||||
Connected,
|
|
||||||
Disconnected,
|
|
||||||
Type,
|
|
||||||
All,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ControllerUpdateCallback {
|
|
||||||
std::function<void(ControllerTriggerType)> on_change;
|
|
||||||
bool is_npad_service;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SystemController {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Contains all input data (buttons, joysticks, vibration, and motion) within this controller.
|
|
||||||
* @param npad_id_type npad id type for this specific controller
|
|
||||||
*/
|
|
||||||
explicit SystemController(NpadIdType npad_id_type_);
|
|
||||||
~SystemController();
|
|
||||||
|
|
||||||
YUZU_NON_COPYABLE(SystemController);
|
|
||||||
YUZU_NON_MOVEABLE(SystemController);
|
|
||||||
|
|
||||||
/// Converts the controller type from settings to npad type
|
|
||||||
static NpadStyleIndex MapSettingsTypeToNPad(Settings::ControllerType type);
|
|
||||||
|
|
||||||
/// Converts npad type to the equivalent of controller type from settings
|
|
||||||
static Settings::ControllerType MapNPadToSettingsType(NpadStyleIndex type);
|
|
||||||
|
|
||||||
/// Gets the NpadIdType for this controller
|
|
||||||
NpadIdType GetNpadIdType() const;
|
|
||||||
|
|
||||||
/// Sets the NpadStyleIndex for this controller
|
|
||||||
void SetNpadStyleIndex(NpadStyleIndex npad_type_);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the NpadStyleIndex for this controller
|
|
||||||
* @param get_temporary_value If true tmp_npad_type will be returned
|
|
||||||
* @return NpadStyleIndex set on the controller
|
|
||||||
*/
|
|
||||||
NpadStyleIndex GetNpadStyleIndex(bool get_temporary_value = false) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the supported controller types. Disconnects the controller if current type is not
|
|
||||||
* supported
|
|
||||||
* @param supported_styles bitflag with supported types
|
|
||||||
*/
|
|
||||||
void SetSupportedNpadStyleTag(NpadStyleTag supported_styles);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the connected status to true
|
|
||||||
* @param use_temporary_value If true tmp_npad_type will be used
|
|
||||||
*/
|
|
||||||
void Connect(bool use_temporary_value = false);
|
|
||||||
|
|
||||||
/// Sets the connected status to false
|
|
||||||
void Disconnect();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is the emulated connected
|
|
||||||
* @param get_temporary_value If true tmp_is_connected will be returned
|
|
||||||
* @return true if the controller has the connected status
|
|
||||||
*/
|
|
||||||
bool IsConnected(bool get_temporary_value = false) const;
|
|
||||||
|
|
||||||
/// Removes all callbacks created from input devices
|
|
||||||
void UnloadInput();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the emulated controller into configuring mode
|
|
||||||
* This prevents the modification of the HID state of the emulated controller by input commands
|
|
||||||
*/
|
|
||||||
void EnableConfiguration();
|
|
||||||
|
|
||||||
/// Returns the emulated controller into normal mode, allowing the modification of the HID state
|
|
||||||
void DisableConfiguration();
|
|
||||||
|
|
||||||
/// Enables Home and Screenshot buttons
|
|
||||||
void EnableSystemButtons();
|
|
||||||
|
|
||||||
/// Disables Home and Screenshot buttons
|
|
||||||
void DisableSystemButtons();
|
|
||||||
|
|
||||||
/// Sets Home and Screenshot buttons to false
|
|
||||||
void ResetSystemButtons();
|
|
||||||
|
|
||||||
/// Returns true if the emulated controller is in configuring mode
|
|
||||||
bool IsConfiguring() const;
|
|
||||||
|
|
||||||
/// Reload all input devices
|
|
||||||
void ReloadInput();
|
|
||||||
|
|
||||||
/// Overrides current mapped devices with the stored configuration and reloads all input devices
|
|
||||||
void ReloadFromSettings();
|
|
||||||
|
|
||||||
/// Saves the current mapped configuration
|
|
||||||
void SaveCurrentConfig();
|
|
||||||
|
|
||||||
/// Reverts any mapped changes made that weren't saved
|
|
||||||
void RestoreConfig();
|
|
||||||
|
|
||||||
/// Returns a vector of mapped devices from the mapped button and stick parameters
|
|
||||||
std::vector<Common::ParamPackage> GetMappedDevices() const;
|
|
||||||
|
|
||||||
// Returns the current mapped button device
|
|
||||||
Common::ParamPackage GetButtonParam(std::size_t index) const;
|
|
||||||
|
|
||||||
// Returns the current mapped stick device
|
|
||||||
Common::ParamPackage GetStickParam(std::size_t index) const;
|
|
||||||
|
|
||||||
// Returns the current mapped motion device
|
|
||||||
Common::ParamPackage GetMotionParam(std::size_t index) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the current mapped button device
|
|
||||||
* @param param ParamPackage with controller data to be mapped
|
|
||||||
*/
|
|
||||||
void SetButtonParam(std::size_t index, Common::ParamPackage param);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the current mapped stick device
|
|
||||||
* @param param ParamPackage with controller data to be mapped
|
|
||||||
*/
|
|
||||||
void SetStickParam(std::size_t index, Common::ParamPackage param);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the current mapped motion device
|
|
||||||
* @param param ParamPackage with controller data to be mapped
|
|
||||||
*/
|
|
||||||
void SetMotionParam(std::size_t index, Common::ParamPackage param);
|
|
||||||
|
|
||||||
/// Returns the latest button status from the controller with parameters
|
|
||||||
ButtonValues GetButtonsValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest analog stick status from the controller with parameters
|
|
||||||
SticksValues GetSticksValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest trigger status from the controller with parameters
|
|
||||||
TriggerValues GetTriggersValues() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of button input for the hid::HomeButton service
|
|
||||||
HomeButtonState GetHomeButtons() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of button input for the hid::CaptureButton service
|
|
||||||
CaptureButtonState GetCaptureButtons() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of button input for the hid::Npad service
|
|
||||||
NpadButtonState GetNpadButtons() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of stick input from the mouse
|
|
||||||
AnalogSticks GetSticks() const;
|
|
||||||
|
|
||||||
/// Returns the latest status of trigger input from the mouse
|
|
||||||
NpadGcTriggerState GetTriggers() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a callback to the list of events
|
|
||||||
* @param update_callback A ConsoleUpdateCallback that will be triggered
|
|
||||||
* @return an unique key corresponding to the callback index in the list
|
|
||||||
*/
|
|
||||||
int SetCallback(ControllerUpdateCallback update_callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a callback from the list stopping any future events to this object
|
|
||||||
* @param key Key corresponding to the callback index in the list
|
|
||||||
*/
|
|
||||||
void DeleteCallback(int key);
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// creates input devices from params
|
|
||||||
void LoadDevices();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param use_temporary_value If true tmp_npad_type will be used
|
|
||||||
* @return true if the controller style is fullkey
|
|
||||||
*/
|
|
||||||
bool IsControllerFullkey(bool use_temporary_value = false) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the current controller type against the supported_style_tag
|
|
||||||
* @param use_temporary_value If true tmp_npad_type will be used
|
|
||||||
* @return true if the controller is supported
|
|
||||||
*/
|
|
||||||
bool IsControllerSupported(bool use_temporary_value = false) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the button status of the controller
|
|
||||||
* @param callback A CallbackStatus containing the button status
|
|
||||||
* @param index Button ID of the to be updated
|
|
||||||
*/
|
|
||||||
void SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
|
|
||||||
Common::UUID uuid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the analog stick status of the controller
|
|
||||||
* @param callback A CallbackStatus containing the analog stick status
|
|
||||||
* @param index stick ID of the to be updated
|
|
||||||
*/
|
|
||||||
void SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
|
|
||||||
Common::UUID uuid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the trigger status of the controller
|
|
||||||
* @param callback A CallbackStatus containing the trigger status
|
|
||||||
* @param index trigger ID of the to be updated
|
|
||||||
*/
|
|
||||||
void SetTrigger(const Common::Input::CallbackStatus& callback, std::size_t index,
|
|
||||||
Common::UUID uuid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers a callback that something has changed on the controller status
|
|
||||||
* @param type Input type of the event to trigger
|
|
||||||
* @param is_service_update indicates if this event should only be sent to HID services
|
|
||||||
*/
|
|
||||||
void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
|
|
||||||
|
|
||||||
const NpadIdType npad_id_type;
|
|
||||||
NpadStyleIndex npad_type{NpadStyleIndex::None};
|
|
||||||
NpadStyleIndex original_npad_type{NpadStyleIndex::None};
|
|
||||||
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
|
||||||
bool is_connected{false};
|
|
||||||
bool is_configuring{false};
|
|
||||||
bool system_buttons_enabled{true};
|
|
||||||
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
|
|
||||||
|
|
||||||
// Temporary values to avoid doing changes while the controller is in configuring mode
|
|
||||||
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
|
|
||||||
bool tmp_is_connected{false};
|
|
||||||
|
|
||||||
ButtonParams button_params;
|
|
||||||
StickParams stick_params;
|
|
||||||
TriggerParams trigger_params;
|
|
||||||
ControllerMotionParams motion_params;
|
|
||||||
RingAnalogParams ring_params;
|
|
||||||
|
|
||||||
ButtonDevices button_devices;
|
|
||||||
StickDevices stick_devices;
|
|
||||||
ControllerMotionDevices motion_devices;
|
|
||||||
TriggerDevices trigger_devices;
|
|
||||||
|
|
||||||
mutable std::mutex mutex;
|
|
||||||
mutable std::mutex callback_mutex;
|
|
||||||
std::unordered_map<int, ControllerUpdateCallback> callback_list;
|
|
||||||
int last_callback_key = 0;
|
|
||||||
|
|
||||||
// Stores the current status of all controller input
|
|
||||||
ControllerStatus controller;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Core::HID
|
|
@ -24,6 +24,7 @@ ClusteringProcessor::ClusteringProcessor(Core::HID::HIDCore& hid_core_,
|
|||||||
|
|
||||||
Core::HID::ControllerUpdateCallback engine_callback{
|
Core::HID::ControllerUpdateCallback engine_callback{
|
||||||
.on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); },
|
.on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); },
|
||||||
|
.is_npad_service = true,
|
||||||
};
|
};
|
||||||
callback_key = npad_device->SetCallback(engine_callback);
|
callback_key = npad_device->SetCallback(engine_callback);
|
||||||
}
|
}
|
||||||
|
@ -674,7 +674,7 @@ public:
|
|||||||
|
|
||||||
void ForceUpdate() override {
|
void ForceUpdate() override {
|
||||||
const Common::Input::CallbackStatus status{
|
const Common::Input::CallbackStatus status{
|
||||||
.type = Common::Input::InputType::Motion,
|
.type = Common::Input::InputType::VirtualMotion,
|
||||||
.motion_status = GetStatus(),
|
.motion_status = GetStatus(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -686,7 +686,7 @@ public:
|
|||||||
|
|
||||||
void OnChange() {
|
void OnChange() {
|
||||||
const Common::Input::CallbackStatus status{
|
const Common::Input::CallbackStatus status{
|
||||||
.type = Common::Input::InputType::Motion,
|
.type = Common::Input::InputType::VirtualMotion,
|
||||||
.motion_status = GetStatus(),
|
.motion_status = GetStatus(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1039,21 +1039,28 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateColorDevice(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateMotionDevice(
|
std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateMotionDevice(
|
||||||
Common::ParamPackage params) {
|
const Common::ParamPackage& params) {
|
||||||
const PadIdentifier identifier = {
|
const PadIdentifier identifier = {
|
||||||
.guid = Common::UUID{params.Get("guid", "")},
|
.guid = Common::UUID{params.Get("guid", "")},
|
||||||
.port = static_cast<std::size_t>(params.Get("port", 0)),
|
.port = static_cast<std::size_t>(params.Get("port", 0)),
|
||||||
.pad = static_cast<std::size_t>(params.Get("pad", 0)),
|
.pad = static_cast<std::size_t>(params.Get("pad", 0)),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (params.Has("motion")) {
|
const auto motion_sensor = params.Get("motion", 0);
|
||||||
const auto motion_sensor = params.Get("motion", 0);
|
const auto gyro_threshold = params.Get("threshold", 0.007f);
|
||||||
const auto gyro_threshold = params.Get("threshold", 0.007f);
|
input_engine->PreSetController(identifier);
|
||||||
input_engine->PreSetController(identifier);
|
input_engine->PreSetMotion(identifier, motion_sensor);
|
||||||
input_engine->PreSetMotion(identifier, motion_sensor);
|
return std::make_unique<InputFromMotion>(identifier, motion_sensor, gyro_threshold,
|
||||||
return std::make_unique<InputFromMotion>(identifier, motion_sensor, gyro_threshold,
|
input_engine.get());
|
||||||
input_engine.get());
|
}
|
||||||
}
|
|
||||||
|
std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateVirtualMotionDevice(
|
||||||
|
const Common::ParamPackage& params) {
|
||||||
|
const PadIdentifier identifier = {
|
||||||
|
.guid = Common::UUID{params.Get("guid", "")},
|
||||||
|
.port = static_cast<std::size_t>(params.Get("port", 0)),
|
||||||
|
.pad = static_cast<std::size_t>(params.Get("pad", 0)),
|
||||||
|
};
|
||||||
|
|
||||||
const auto deadzone = std::clamp(params.Get("deadzone", 0.15f), 0.0f, 1.0f);
|
const auto deadzone = std::clamp(params.Get("deadzone", 0.15f), 0.0f, 1.0f);
|
||||||
const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f);
|
const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f);
|
||||||
@ -1147,7 +1154,7 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::Create(
|
|||||||
return CreateHatButtonDevice(params);
|
return CreateHatButtonDevice(params);
|
||||||
}
|
}
|
||||||
if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) {
|
if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) {
|
||||||
return CreateMotionDevice(params);
|
return CreateVirtualMotionDevice(params);
|
||||||
}
|
}
|
||||||
if (params.Has("motion")) {
|
if (params.Has("motion")) {
|
||||||
return CreateMotionDevice(params);
|
return CreateMotionDevice(params);
|
||||||
|
@ -204,6 +204,19 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Creates a motion device from the parameters given.
|
* Creates a motion device from the parameters given.
|
||||||
* @param params contains parameters for creating the device:
|
* @param params contains parameters for creating the device:
|
||||||
|
* - "motion": index of the motion sensor
|
||||||
|
* - "threshold": gyro deadzone to avoid drifting
|
||||||
|
* - "guid": text string for identifying controllers
|
||||||
|
* - "port": port of the connected device
|
||||||
|
* - "pad": slot of the connected controller
|
||||||
|
* @returns a unique input device with the parameters specified
|
||||||
|
*/
|
||||||
|
std::unique_ptr<Common::Input::InputDevice> CreateMotionDevice(
|
||||||
|
const Common::ParamPackage& params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a virtual motion device from the parameters given.
|
||||||
|
* @param params contains parameters for creating the device:
|
||||||
* - "axis_x": the controller horizontal axis id to bind with the input
|
* - "axis_x": the controller horizontal axis id to bind with the input
|
||||||
* - "axis_y": the controller vertical axis id to bind with the input
|
* - "axis_y": the controller vertical axis id to bind with the input
|
||||||
* - "axis_z": the controller forward axis id to bind with the input
|
* - "axis_z": the controller forward axis id to bind with the input
|
||||||
@ -220,7 +233,8 @@ private:
|
|||||||
* - "pad": slot of the connected controller
|
* - "pad": slot of the connected controller
|
||||||
* @returns a unique input device with the parameters specified
|
* @returns a unique input device with the parameters specified
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<Common::Input::InputDevice> CreateMotionDevice(Common::ParamPackage params);
|
std::unique_ptr<Common::Input::InputDevice> CreateVirtualMotionDevice(
|
||||||
|
const Common::ParamPackage& params);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a camera device from the parameters given.
|
* Creates a camera device from the parameters given.
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "core/hid/system_controller.h"
|
#include "core/hid/emulated_controller.h"
|
||||||
#include "core/hid/hid_core.h"
|
#include "core/hid/hid_core.h"
|
||||||
|
|
||||||
#include "ui_configure_hotkeys.h"
|
#include "ui_configure_hotkeys.h"
|
||||||
@ -42,7 +42,7 @@ ConfigureHotkeys::ConfigureHotkeys(Core::HID::HIDCore& hid_core, QWidget* parent
|
|||||||
&ConfigureHotkeys::RestoreDefaults);
|
&ConfigureHotkeys::RestoreDefaults);
|
||||||
connect(ui->button_clear_all, &QPushButton::clicked, this, &ConfigureHotkeys::ClearAll);
|
connect(ui->button_clear_all, &QPushButton::clicked, this, &ConfigureHotkeys::ClearAll);
|
||||||
|
|
||||||
controller = hid_core.GetSystemController(Core::HID::NpadIdType::Player1);
|
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||||
|
|
||||||
connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); });
|
connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); });
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ class ParamPackage;
|
|||||||
|
|
||||||
namespace Core::HID {
|
namespace Core::HID {
|
||||||
class HIDCore;
|
class HIDCore;
|
||||||
class SystemController;
|
class EmulatedController;
|
||||||
enum class NpadButton : u64;
|
enum class NpadButton : u64;
|
||||||
} // namespace Core::HID
|
} // namespace Core::HID
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ private:
|
|||||||
|
|
||||||
void SetPollingResult(Core::HID::NpadButton button, bool cancel);
|
void SetPollingResult(Core::HID::NpadButton button, bool cancel);
|
||||||
QString GetButtonCombinationName(Core::HID::NpadButton button, bool home, bool capture) const;
|
QString GetButtonCombinationName(Core::HID::NpadButton button, bool home, bool capture) const;
|
||||||
Core::HID::SystemController* controller;
|
Core::HID::EmulatedController* controller;
|
||||||
std::unique_ptr<QTimer> timeout_timer;
|
std::unique_ptr<QTimer> timeout_timer;
|
||||||
std::unique_ptr<QTimer> poll_timer;
|
std::unique_ptr<QTimer> poll_timer;
|
||||||
std::optional<std::function<void(Core::HID::NpadButton, bool)>> input_setter;
|
std::optional<std::function<void(Core::HID::NpadButton, bool)>> input_setter;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/param_package.h"
|
#include "common/param_package.h"
|
||||||
#include "core/hid/system_controller.h"
|
#include "core/hid/emulated_controller.h"
|
||||||
#include "core/hid/hid_core.h"
|
#include "core/hid/hid_core.h"
|
||||||
#include "core/hid/hid_types.h"
|
#include "core/hid/hid_types.h"
|
||||||
#include "input_common/drivers/keyboard.h"
|
#include "input_common/drivers/keyboard.h"
|
||||||
@ -297,24 +297,24 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
timeout_timer(std::make_unique<QTimer>()),
|
timeout_timer(std::make_unique<QTimer>()),
|
||||||
poll_timer(std::make_unique<QTimer>()), bottom_row{bottom_row_}, hid_core{hid_core_} {
|
poll_timer(std::make_unique<QTimer>()), bottom_row{bottom_row_}, hid_core{hid_core_} {
|
||||||
if (player_index == 0) {
|
if (player_index == 0) {
|
||||||
auto* system_controller_p1 =
|
auto* emulated_controller_p1 =
|
||||||
hid_core.GetSystemController(Core::HID::NpadIdType::Player1);
|
hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||||
auto* system_controller_handheld =
|
auto* emulated_controller_handheld =
|
||||||
hid_core.GetSystemController(Core::HID::NpadIdType::Handheld);
|
hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||||
system_controller_p1->SaveCurrentConfig();
|
emulated_controller_p1->SaveCurrentConfig();
|
||||||
system_controller_p1->EnableConfiguration();
|
emulated_controller_p1->EnableConfiguration();
|
||||||
system_controller_handheld->SaveCurrentConfig();
|
emulated_controller_handheld->SaveCurrentConfig();
|
||||||
system_controller_handheld->EnableConfiguration();
|
emulated_controller_handheld->EnableConfiguration();
|
||||||
if (system_controller_handheld->IsConnected(true)) {
|
if (emulated_controller_handheld->IsConnected(true)) {
|
||||||
system_controller_p1->Disconnect();
|
emulated_controller_p1->Disconnect();
|
||||||
system_controller = system_controller_handheld;
|
emulated_controller = emulated_controller_handheld;
|
||||||
} else {
|
} else {
|
||||||
system_controller = system_controller_p1;
|
emulated_controller = emulated_controller_p1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
system_controller = hid_core.GetSystemControllerByIndex(player_index);
|
emulated_controller = hid_core.GetEmulatedControllerByIndex(player_index);
|
||||||
system_controller->SaveCurrentConfig();
|
emulated_controller->SaveCurrentConfig();
|
||||||
system_controller->EnableConfiguration();
|
emulated_controller->EnableConfiguration();
|
||||||
}
|
}
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
@ -357,7 +357,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup};
|
analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup};
|
||||||
analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange};
|
analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange};
|
||||||
|
|
||||||
ui->controllerFrame->SetController(system_controller->GetNpadIdType());
|
ui->controllerFrame->SetController(emulated_controller);
|
||||||
|
|
||||||
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
|
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
|
||||||
auto* const button = button_map[button_id];
|
auto* const button = button_map[button_id];
|
||||||
@ -370,7 +370,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
HandleClick(
|
HandleClick(
|
||||||
button, button_id,
|
button, button_id,
|
||||||
[=, this](const Common::ParamPackage& params) {
|
[=, this](const Common::ParamPackage& params) {
|
||||||
system_controller->SetButtonParam(button_id, params);
|
emulated_controller->SetButtonParam(button_id, params);
|
||||||
},
|
},
|
||||||
InputCommon::Polling::InputType::Button);
|
InputCommon::Polling::InputType::Button);
|
||||||
});
|
});
|
||||||
@ -379,9 +379,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
connect(button, &QPushButton::customContextMenuRequested,
|
connect(button, &QPushButton::customContextMenuRequested,
|
||||||
[=, this](const QPoint& menu_location) {
|
[=, this](const QPoint& menu_location) {
|
||||||
QMenu context_menu;
|
QMenu context_menu;
|
||||||
Common::ParamPackage param = system_controller->GetButtonParam(button_id);
|
Common::ParamPackage param = emulated_controller->GetButtonParam(button_id);
|
||||||
context_menu.addAction(tr("Clear"), [&] {
|
context_menu.addAction(tr("Clear"), [&] {
|
||||||
system_controller->SetButtonParam(button_id, {});
|
emulated_controller->SetButtonParam(button_id, {});
|
||||||
button_map[button_id]->setText(tr("[not set]"));
|
button_map[button_id]->setText(tr("[not set]"));
|
||||||
});
|
});
|
||||||
if (param.Has("code") || param.Has("button") || param.Has("hat")) {
|
if (param.Has("code") || param.Has("button") || param.Has("hat")) {
|
||||||
@ -389,19 +389,19 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
const bool invert_value = !param.Get("inverted", false);
|
const bool invert_value = !param.Get("inverted", false);
|
||||||
param.Set("inverted", invert_value);
|
param.Set("inverted", invert_value);
|
||||||
button_map[button_id]->setText(ButtonToText(param));
|
button_map[button_id]->setText(ButtonToText(param));
|
||||||
system_controller->SetButtonParam(button_id, param);
|
emulated_controller->SetButtonParam(button_id, param);
|
||||||
});
|
});
|
||||||
context_menu.addAction(tr("Toggle button"), [&] {
|
context_menu.addAction(tr("Toggle button"), [&] {
|
||||||
const bool toggle_value = !param.Get("toggle", false);
|
const bool toggle_value = !param.Get("toggle", false);
|
||||||
param.Set("toggle", toggle_value);
|
param.Set("toggle", toggle_value);
|
||||||
button_map[button_id]->setText(ButtonToText(param));
|
button_map[button_id]->setText(ButtonToText(param));
|
||||||
system_controller->SetButtonParam(button_id, param);
|
emulated_controller->SetButtonParam(button_id, param);
|
||||||
});
|
});
|
||||||
context_menu.addAction(tr("Turbo button"), [&] {
|
context_menu.addAction(tr("Turbo button"), [&] {
|
||||||
const bool turbo_value = !param.Get("turbo", false);
|
const bool turbo_value = !param.Get("turbo", false);
|
||||||
param.Set("turbo", turbo_value);
|
param.Set("turbo", turbo_value);
|
||||||
button_map[button_id]->setText(ButtonToText(param));
|
button_map[button_id]->setText(ButtonToText(param));
|
||||||
system_controller->SetButtonParam(button_id, param);
|
emulated_controller->SetButtonParam(button_id, param);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (param.Has("axis")) {
|
if (param.Has("axis")) {
|
||||||
@ -409,13 +409,13 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
const bool toggle_value = !(param.Get("invert", "+") == "-");
|
const bool toggle_value = !(param.Get("invert", "+") == "-");
|
||||||
param.Set("invert", toggle_value ? "-" : "+");
|
param.Set("invert", toggle_value ? "-" : "+");
|
||||||
button_map[button_id]->setText(ButtonToText(param));
|
button_map[button_id]->setText(ButtonToText(param));
|
||||||
system_controller->SetButtonParam(button_id, param);
|
emulated_controller->SetButtonParam(button_id, param);
|
||||||
});
|
});
|
||||||
context_menu.addAction(tr("Invert button"), [&] {
|
context_menu.addAction(tr("Invert button"), [&] {
|
||||||
const bool invert_value = !param.Get("inverted", false);
|
const bool invert_value = !param.Get("inverted", false);
|
||||||
param.Set("inverted", invert_value);
|
param.Set("inverted", invert_value);
|
||||||
button_map[button_id]->setText(ButtonToText(param));
|
button_map[button_id]->setText(ButtonToText(param));
|
||||||
system_controller->SetButtonParam(button_id, param);
|
emulated_controller->SetButtonParam(button_id, param);
|
||||||
});
|
});
|
||||||
context_menu.addAction(tr("Set threshold"), [&] {
|
context_menu.addAction(tr("Set threshold"), [&] {
|
||||||
const int button_threshold =
|
const int button_threshold =
|
||||||
@ -431,13 +431,13 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
if (button_id == Settings::NativeButton::ZR) {
|
if (button_id == Settings::NativeButton::ZR) {
|
||||||
ui->sliderZRThreshold->setValue(new_threshold);
|
ui->sliderZRThreshold->setValue(new_threshold);
|
||||||
}
|
}
|
||||||
system_controller->SetButtonParam(button_id, param);
|
emulated_controller->SetButtonParam(button_id, param);
|
||||||
});
|
});
|
||||||
context_menu.addAction(tr("Toggle axis"), [&] {
|
context_menu.addAction(tr("Toggle axis"), [&] {
|
||||||
const bool toggle_value = !param.Get("toggle", false);
|
const bool toggle_value = !param.Get("toggle", false);
|
||||||
param.Set("toggle", toggle_value);
|
param.Set("toggle", toggle_value);
|
||||||
button_map[button_id]->setText(ButtonToText(param));
|
button_map[button_id]->setText(ButtonToText(param));
|
||||||
system_controller->SetButtonParam(button_id, param);
|
emulated_controller->SetButtonParam(button_id, param);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
|
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
|
||||||
@ -454,7 +454,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
HandleClick(
|
HandleClick(
|
||||||
button, motion_id,
|
button, motion_id,
|
||||||
[=, this](const Common::ParamPackage& params) {
|
[=, this](const Common::ParamPackage& params) {
|
||||||
system_controller->SetMotionParam(motion_id, params);
|
emulated_controller->SetMotionParam(motion_id, params);
|
||||||
},
|
},
|
||||||
InputCommon::Polling::InputType::Motion);
|
InputCommon::Polling::InputType::Motion);
|
||||||
});
|
});
|
||||||
@ -464,9 +464,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
connect(button, &QPushButton::customContextMenuRequested,
|
connect(button, &QPushButton::customContextMenuRequested,
|
||||||
[=, this](const QPoint& menu_location) {
|
[=, this](const QPoint& menu_location) {
|
||||||
QMenu context_menu;
|
QMenu context_menu;
|
||||||
Common::ParamPackage param = system_controller->GetMotionParam(motion_id);
|
Common::ParamPackage param = emulated_controller->GetMotionParam(motion_id);
|
||||||
context_menu.addAction(tr("Clear"), [&] {
|
context_menu.addAction(tr("Clear"), [&] {
|
||||||
system_controller->SetMotionParam(motion_id, {});
|
emulated_controller->SetMotionParam(motion_id, {});
|
||||||
motion_map[motion_id]->setText(tr("[not set]"));
|
motion_map[motion_id]->setText(tr("[not set]"));
|
||||||
});
|
});
|
||||||
if (param.Has("motion")) {
|
if (param.Has("motion")) {
|
||||||
@ -477,7 +477,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
this, tr("Set threshold"), tr("Choose a value between 0% and 100%"),
|
this, tr("Set threshold"), tr("Choose a value between 0% and 100%"),
|
||||||
gyro_threshold, 0, 100);
|
gyro_threshold, 0, 100);
|
||||||
param.Set("threshold", new_threshold / 1000.0f);
|
param.Set("threshold", new_threshold / 1000.0f);
|
||||||
system_controller->SetMotionParam(motion_id, param);
|
emulated_controller->SetMotionParam(motion_id, param);
|
||||||
});
|
});
|
||||||
context_menu.addAction(tr("Calibrate sensor"), [&] {
|
context_menu.addAction(tr("Calibrate sensor"), [&] {
|
||||||
emulated_controller->StartMotionCalibration();
|
emulated_controller->StartMotionCalibration();
|
||||||
@ -489,21 +489,21 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
|
|
||||||
connect(ui->sliderZLThreshold, &QSlider::valueChanged, [=, this] {
|
connect(ui->sliderZLThreshold, &QSlider::valueChanged, [=, this] {
|
||||||
Common::ParamPackage param =
|
Common::ParamPackage param =
|
||||||
system_controller->GetButtonParam(Settings::NativeButton::ZL);
|
emulated_controller->GetButtonParam(Settings::NativeButton::ZL);
|
||||||
if (param.Has("threshold")) {
|
if (param.Has("threshold")) {
|
||||||
const auto slider_value = ui->sliderZLThreshold->value();
|
const auto slider_value = ui->sliderZLThreshold->value();
|
||||||
param.Set("threshold", slider_value / 100.0f);
|
param.Set("threshold", slider_value / 100.0f);
|
||||||
system_controller->SetButtonParam(Settings::NativeButton::ZL, param);
|
emulated_controller->SetButtonParam(Settings::NativeButton::ZL, param);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ui->sliderZRThreshold, &QSlider::valueChanged, [=, this] {
|
connect(ui->sliderZRThreshold, &QSlider::valueChanged, [=, this] {
|
||||||
Common::ParamPackage param =
|
Common::ParamPackage param =
|
||||||
system_controller->GetButtonParam(Settings::NativeButton::ZR);
|
emulated_controller->GetButtonParam(Settings::NativeButton::ZR);
|
||||||
if (param.Has("threshold")) {
|
if (param.Has("threshold")) {
|
||||||
const auto slider_value = ui->sliderZRThreshold->value();
|
const auto slider_value = ui->sliderZRThreshold->value();
|
||||||
param.Set("threshold", slider_value / 100.0f);
|
param.Set("threshold", slider_value / 100.0f);
|
||||||
system_controller->SetButtonParam(Settings::NativeButton::ZR, param);
|
emulated_controller->SetButtonParam(Settings::NativeButton::ZR, param);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -531,7 +531,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
HandleClick(
|
HandleClick(
|
||||||
analog_map_buttons[analog_id][sub_button_id], analog_id,
|
analog_map_buttons[analog_id][sub_button_id], analog_id,
|
||||||
[=, this](const Common::ParamPackage& params) {
|
[=, this](const Common::ParamPackage& params) {
|
||||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||||
SetAnalogParam(params, param, analog_sub_buttons[sub_button_id]);
|
SetAnalogParam(params, param, analog_sub_buttons[sub_button_id]);
|
||||||
// Correct axis direction for inverted sticks
|
// Correct axis direction for inverted sticks
|
||||||
if (input_subsystem->IsStickInverted(param)) {
|
if (input_subsystem->IsStickInverted(param)) {
|
||||||
@ -552,7 +552,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
system_controller->SetStickParam(analog_id, param);
|
emulated_controller->SetStickParam(analog_id, param);
|
||||||
},
|
},
|
||||||
InputCommon::Polling::InputType::Stick);
|
InputCommon::Polling::InputType::Stick);
|
||||||
});
|
});
|
||||||
@ -562,10 +562,10 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
connect(analog_button, &QPushButton::customContextMenuRequested,
|
connect(analog_button, &QPushButton::customContextMenuRequested,
|
||||||
[=, this](const QPoint& menu_location) {
|
[=, this](const QPoint& menu_location) {
|
||||||
QMenu context_menu;
|
QMenu context_menu;
|
||||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||||
context_menu.addAction(tr("Clear"), [&] {
|
context_menu.addAction(tr("Clear"), [&] {
|
||||||
if (param.Get("engine", "") != "analog_from_button") {
|
if (param.Get("engine", "") != "analog_from_button") {
|
||||||
system_controller->SetStickParam(analog_id, {});
|
emulated_controller->SetStickParam(analog_id, {});
|
||||||
for (auto button : analog_map_buttons[analog_id]) {
|
for (auto button : analog_map_buttons[analog_id]) {
|
||||||
button->setText(tr("[not set]"));
|
button->setText(tr("[not set]"));
|
||||||
}
|
}
|
||||||
@ -585,12 +585,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
param.Erase("right");
|
param.Erase("right");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
system_controller->SetStickParam(analog_id, param);
|
emulated_controller->SetStickParam(analog_id, param);
|
||||||
analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
|
analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
|
||||||
});
|
});
|
||||||
context_menu.addAction(tr("Center axis"), [&] {
|
context_menu.addAction(tr("Center axis"), [&] {
|
||||||
const auto stick_value =
|
const auto stick_value =
|
||||||
system_controller->GetSticksValues()[analog_id];
|
emulated_controller->GetSticksValues()[analog_id];
|
||||||
const float offset_x = stick_value.x.properties.offset;
|
const float offset_x = stick_value.x.properties.offset;
|
||||||
const float offset_y = stick_value.y.properties.offset;
|
const float offset_y = stick_value.y.properties.offset;
|
||||||
float raw_value_x = stick_value.x.raw_value;
|
float raw_value_x = stick_value.x.raw_value;
|
||||||
@ -612,20 +612,20 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
}
|
}
|
||||||
param.Set("offset_x", -raw_value_x + offset_x);
|
param.Set("offset_x", -raw_value_x + offset_x);
|
||||||
param.Set("offset_y", -raw_value_y + offset_y);
|
param.Set("offset_y", -raw_value_y + offset_y);
|
||||||
system_controller->SetStickParam(analog_id, param);
|
emulated_controller->SetStickParam(analog_id, param);
|
||||||
});
|
});
|
||||||
context_menu.addAction(tr("Invert axis"), [&] {
|
context_menu.addAction(tr("Invert axis"), [&] {
|
||||||
if (sub_button_id == 2 || sub_button_id == 3) {
|
if (sub_button_id == 2 || sub_button_id == 3) {
|
||||||
const bool invert_value = param.Get("invert_x", "+") == "-";
|
const bool invert_value = param.Get("invert_x", "+") == "-";
|
||||||
const std::string invert_str = invert_value ? "+" : "-";
|
const std::string invert_str = invert_value ? "+" : "-";
|
||||||
param.Set("invert_x", invert_str);
|
param.Set("invert_x", invert_str);
|
||||||
system_controller->SetStickParam(analog_id, param);
|
emulated_controller->SetStickParam(analog_id, param);
|
||||||
}
|
}
|
||||||
if (sub_button_id == 0 || sub_button_id == 1) {
|
if (sub_button_id == 0 || sub_button_id == 1) {
|
||||||
const bool invert_value = param.Get("invert_y", "+") == "-";
|
const bool invert_value = param.Get("invert_y", "+") == "-";
|
||||||
const std::string invert_str = invert_value ? "+" : "-";
|
const std::string invert_str = invert_value ? "+" : "-";
|
||||||
param.Set("invert_y", invert_str);
|
param.Set("invert_y", invert_str);
|
||||||
system_controller->SetStickParam(analog_id, param);
|
emulated_controller->SetStickParam(analog_id, param);
|
||||||
}
|
}
|
||||||
for (int analog_sub_button_id = 0;
|
for (int analog_sub_button_id = 0;
|
||||||
analog_sub_button_id < ANALOG_SUB_BUTTONS_NUM;
|
analog_sub_button_id < ANALOG_SUB_BUTTONS_NUM;
|
||||||
@ -644,9 +644,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
HandleClick(
|
HandleClick(
|
||||||
analog_map_modifier_button[analog_id], analog_id,
|
analog_map_modifier_button[analog_id], analog_id,
|
||||||
[=, this](const Common::ParamPackage& params) {
|
[=, this](const Common::ParamPackage& params) {
|
||||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||||
param.Set("modifier", params.Serialize());
|
param.Set("modifier", params.Serialize());
|
||||||
system_controller->SetStickParam(analog_id, param);
|
emulated_controller->SetStickParam(analog_id, param);
|
||||||
},
|
},
|
||||||
InputCommon::Polling::InputType::Button);
|
InputCommon::Polling::InputType::Button);
|
||||||
});
|
});
|
||||||
@ -657,11 +657,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
analog_map_modifier_button[analog_id], &QPushButton::customContextMenuRequested,
|
analog_map_modifier_button[analog_id], &QPushButton::customContextMenuRequested,
|
||||||
[=, this](const QPoint& menu_location) {
|
[=, this](const QPoint& menu_location) {
|
||||||
QMenu context_menu;
|
QMenu context_menu;
|
||||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||||
context_menu.addAction(tr("Clear"), [&] {
|
context_menu.addAction(tr("Clear"), [&] {
|
||||||
param.Set("modifier", "");
|
param.Set("modifier", "");
|
||||||
analog_map_modifier_button[analog_id]->setText(tr("[not set]"));
|
analog_map_modifier_button[analog_id]->setText(tr("[not set]"));
|
||||||
system_controller->SetStickParam(analog_id, param);
|
emulated_controller->SetStickParam(analog_id, param);
|
||||||
});
|
});
|
||||||
context_menu.addAction(tr("Toggle button"), [&] {
|
context_menu.addAction(tr("Toggle button"), [&] {
|
||||||
Common::ParamPackage modifier_param =
|
Common::ParamPackage modifier_param =
|
||||||
@ -670,7 +670,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
modifier_param.Set("toggle", toggle_value);
|
modifier_param.Set("toggle", toggle_value);
|
||||||
param.Set("modifier", modifier_param.Serialize());
|
param.Set("modifier", modifier_param.Serialize());
|
||||||
analog_map_modifier_button[analog_id]->setText(ButtonToText(modifier_param));
|
analog_map_modifier_button[analog_id]->setText(ButtonToText(modifier_param));
|
||||||
system_controller->SetStickParam(analog_id, param);
|
emulated_controller->SetStickParam(analog_id, param);
|
||||||
});
|
});
|
||||||
context_menu.addAction(tr("Invert button"), [&] {
|
context_menu.addAction(tr("Invert button"), [&] {
|
||||||
Common::ParamPackage modifier_param =
|
Common::ParamPackage modifier_param =
|
||||||
@ -679,7 +679,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
modifier_param.Set("inverted", invert_value);
|
modifier_param.Set("inverted", invert_value);
|
||||||
param.Set("modifier", modifier_param.Serialize());
|
param.Set("modifier", modifier_param.Serialize());
|
||||||
analog_map_modifier_button[analog_id]->setText(ButtonToText(modifier_param));
|
analog_map_modifier_button[analog_id]->setText(ButtonToText(modifier_param));
|
||||||
system_controller->SetStickParam(analog_id, param);
|
emulated_controller->SetStickParam(analog_id, param);
|
||||||
});
|
});
|
||||||
context_menu.exec(
|
context_menu.exec(
|
||||||
analog_map_modifier_button[analog_id]->mapToGlobal(menu_location));
|
analog_map_modifier_button[analog_id]->mapToGlobal(menu_location));
|
||||||
@ -687,27 +687,27 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
|
|
||||||
connect(analog_map_range_spinbox[analog_id], qOverload<int>(&QSpinBox::valueChanged),
|
connect(analog_map_range_spinbox[analog_id], qOverload<int>(&QSpinBox::valueChanged),
|
||||||
[=, this] {
|
[=, this] {
|
||||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||||
const auto spinbox_value = analog_map_range_spinbox[analog_id]->value();
|
const auto spinbox_value = analog_map_range_spinbox[analog_id]->value();
|
||||||
param.Set("range", spinbox_value / 100.0f);
|
param.Set("range", spinbox_value / 100.0f);
|
||||||
system_controller->SetStickParam(analog_id, param);
|
emulated_controller->SetStickParam(analog_id, param);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] {
|
connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] {
|
||||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||||
const auto slider_value = analog_map_deadzone_slider[analog_id]->value();
|
const auto slider_value = analog_map_deadzone_slider[analog_id]->value();
|
||||||
analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value));
|
analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value));
|
||||||
param.Set("deadzone", slider_value / 100.0f);
|
param.Set("deadzone", slider_value / 100.0f);
|
||||||
system_controller->SetStickParam(analog_id, param);
|
emulated_controller->SetStickParam(analog_id, param);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] {
|
connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] {
|
||||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||||
const auto slider_value = analog_map_modifier_slider[analog_id]->value();
|
const auto slider_value = analog_map_modifier_slider[analog_id]->value();
|
||||||
analog_map_modifier_label[analog_id]->setText(
|
analog_map_modifier_label[analog_id]->setText(
|
||||||
tr("Modifier Range: %1%").arg(slider_value));
|
tr("Modifier Range: %1%").arg(slider_value));
|
||||||
param.Set("modifier_scale", slider_value / 100.0f);
|
param.Set("modifier_scale", slider_value / 100.0f);
|
||||||
system_controller->SetStickParam(analog_id, param);
|
emulated_controller->SetStickParam(analog_id, param);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -749,28 +749,28 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
|
GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
|
||||||
|
|
||||||
if (player_index == 0) {
|
if (player_index == 0) {
|
||||||
auto* system_controller_p1 =
|
auto* emulated_controller_p1 =
|
||||||
hid_core.GetSystemController(Core::HID::NpadIdType::Player1);
|
hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||||
auto* system_controller_handheld =
|
auto* emulated_controller_handheld =
|
||||||
hid_core.GetSystemController(Core::HID::NpadIdType::Handheld);
|
hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||||
bool is_connected = system_controller->IsConnected(true);
|
bool is_connected = emulated_controller->IsConnected(true);
|
||||||
|
|
||||||
system_controller_p1->SetNpadStyleIndex(type);
|
emulated_controller_p1->SetNpadStyleIndex(type);
|
||||||
system_controller_handheld->SetNpadStyleIndex(type);
|
emulated_controller_handheld->SetNpadStyleIndex(type);
|
||||||
if (is_connected) {
|
if (is_connected) {
|
||||||
if (type == Core::HID::NpadStyleIndex::Handheld) {
|
if (type == Core::HID::NpadStyleIndex::Handheld) {
|
||||||
system_controller_p1->Disconnect();
|
emulated_controller_p1->Disconnect();
|
||||||
system_controller_handheld->Connect(true);
|
emulated_controller_handheld->Connect(true);
|
||||||
system_controller = system_controller_handheld;
|
emulated_controller = emulated_controller_handheld;
|
||||||
} else {
|
} else {
|
||||||
system_controller_handheld->Disconnect();
|
emulated_controller_handheld->Disconnect();
|
||||||
system_controller_p1->Connect(true);
|
emulated_controller_p1->Connect(true);
|
||||||
system_controller = system_controller_p1;
|
emulated_controller = emulated_controller_p1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ui->controllerFrame->SetController(system_controller->GetNpadIdType());
|
ui->controllerFrame->SetController(emulated_controller);
|
||||||
}
|
}
|
||||||
system_controller->SetNpadStyleIndex(type);
|
emulated_controller->SetNpadStyleIndex(type);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this,
|
connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this,
|
||||||
@ -806,33 +806,34 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||||||
|
|
||||||
ConfigureInputPlayer::~ConfigureInputPlayer() {
|
ConfigureInputPlayer::~ConfigureInputPlayer() {
|
||||||
if (player_index == 0) {
|
if (player_index == 0) {
|
||||||
auto* system_controller_p1 =
|
auto* emulated_controller_p1 =
|
||||||
hid_core.GetSystemController(Core::HID::NpadIdType::Player1);
|
hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||||
auto* system_controller_handheld =
|
auto* emulated_controller_handheld =
|
||||||
hid_core.GetSystemController(Core::HID::NpadIdType::Handheld);
|
hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||||
system_controller_p1->DisableConfiguration();
|
emulated_controller_p1->DisableConfiguration();
|
||||||
system_controller_handheld->DisableConfiguration();
|
emulated_controller_handheld->DisableConfiguration();
|
||||||
} else {
|
} else {
|
||||||
system_controller->DisableConfiguration();
|
emulated_controller->DisableConfiguration();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureInputPlayer::ApplyConfiguration() {
|
void ConfigureInputPlayer::ApplyConfiguration() {
|
||||||
if (player_index == 0) {
|
if (player_index == 0) {
|
||||||
auto* system_controller_p1 = hid_core.GetSystemController(Core::HID::NpadIdType::Player1);
|
auto* emulated_controller_p1 =
|
||||||
auto* system_controller_handheld =
|
hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||||
hid_core.GetSystemController(Core::HID::NpadIdType::Handheld);
|
auto* emulated_controller_handheld =
|
||||||
system_controller_p1->DisableConfiguration();
|
hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||||
system_controller_p1->SaveCurrentConfig();
|
emulated_controller_p1->DisableConfiguration();
|
||||||
system_controller_p1->EnableConfiguration();
|
emulated_controller_p1->SaveCurrentConfig();
|
||||||
system_controller_handheld->DisableConfiguration();
|
emulated_controller_p1->EnableConfiguration();
|
||||||
system_controller_handheld->SaveCurrentConfig();
|
emulated_controller_handheld->DisableConfiguration();
|
||||||
system_controller_handheld->EnableConfiguration();
|
emulated_controller_handheld->SaveCurrentConfig();
|
||||||
|
emulated_controller_handheld->EnableConfiguration();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
system_controller->DisableConfiguration();
|
emulated_controller->DisableConfiguration();
|
||||||
system_controller->SaveCurrentConfig();
|
emulated_controller->SaveCurrentConfig();
|
||||||
system_controller->EnableConfiguration();
|
emulated_controller->EnableConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureInputPlayer::showEvent(QShowEvent* event) {
|
void ConfigureInputPlayer::showEvent(QShowEvent* event) {
|
||||||
@ -857,7 +858,7 @@ void ConfigureInputPlayer::RetranslateUI() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureInputPlayer::LoadConfiguration() {
|
void ConfigureInputPlayer::LoadConfiguration() {
|
||||||
system_controller->ReloadFromSettings();
|
emulated_controller->ReloadFromSettings();
|
||||||
|
|
||||||
UpdateUI();
|
UpdateUI();
|
||||||
UpdateInputDeviceCombobox();
|
UpdateInputDeviceCombobox();
|
||||||
@ -867,17 +868,17 @@ void ConfigureInputPlayer::LoadConfiguration() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int comboBoxIndex =
|
const int comboBoxIndex =
|
||||||
GetIndexFromControllerType(system_controller->GetNpadStyleIndex(true));
|
GetIndexFromControllerType(emulated_controller->GetNpadStyleIndex(true));
|
||||||
ui->comboControllerType->setCurrentIndex(comboBoxIndex);
|
ui->comboControllerType->setCurrentIndex(comboBoxIndex);
|
||||||
ui->groupConnectedController->setChecked(system_controller->IsConnected(true));
|
ui->groupConnectedController->setChecked(emulated_controller->IsConnected(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureInputPlayer::ConnectPlayer(bool connected) {
|
void ConfigureInputPlayer::ConnectPlayer(bool connected) {
|
||||||
ui->groupConnectedController->setChecked(connected);
|
ui->groupConnectedController->setChecked(connected);
|
||||||
if (connected) {
|
if (connected) {
|
||||||
system_controller->Connect(true);
|
emulated_controller->Connect(true);
|
||||||
} else {
|
} else {
|
||||||
system_controller->Disconnect();
|
emulated_controller->Disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -888,7 +889,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto devices = system_controller->GetMappedDevices();
|
const auto devices = emulated_controller->GetMappedDevices();
|
||||||
UpdateInputDevices();
|
UpdateInputDevices();
|
||||||
|
|
||||||
if (devices.empty()) {
|
if (devices.empty()) {
|
||||||
@ -967,7 +968,7 @@ void ConfigureInputPlayer::ClearAll() {
|
|||||||
if (button == nullptr) {
|
if (button == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
system_controller->SetButtonParam(button_id, {});
|
emulated_controller->SetButtonParam(button_id, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
|
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
|
||||||
@ -976,7 +977,7 @@ void ConfigureInputPlayer::ClearAll() {
|
|||||||
if (analog_button == nullptr) {
|
if (analog_button == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
system_controller->SetStickParam(analog_id, {});
|
emulated_controller->SetStickParam(analog_id, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -985,7 +986,7 @@ void ConfigureInputPlayer::ClearAll() {
|
|||||||
if (motion_button == nullptr) {
|
if (motion_button == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
system_controller->SetMotionParam(motion_id, {});
|
emulated_controller->SetMotionParam(motion_id, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateUI();
|
UpdateUI();
|
||||||
@ -994,31 +995,31 @@ void ConfigureInputPlayer::ClearAll() {
|
|||||||
|
|
||||||
void ConfigureInputPlayer::UpdateUI() {
|
void ConfigureInputPlayer::UpdateUI() {
|
||||||
for (int button = 0; button < Settings::NativeButton::NumButtons; ++button) {
|
for (int button = 0; button < Settings::NativeButton::NumButtons; ++button) {
|
||||||
const Common::ParamPackage param = system_controller->GetButtonParam(button);
|
const Common::ParamPackage param = emulated_controller->GetButtonParam(button);
|
||||||
button_map[button]->setText(ButtonToText(param));
|
button_map[button]->setText(ButtonToText(param));
|
||||||
}
|
}
|
||||||
|
|
||||||
const Common::ParamPackage ZL_param =
|
const Common::ParamPackage ZL_param =
|
||||||
system_controller->GetButtonParam(Settings::NativeButton::ZL);
|
emulated_controller->GetButtonParam(Settings::NativeButton::ZL);
|
||||||
if (ZL_param.Has("threshold")) {
|
if (ZL_param.Has("threshold")) {
|
||||||
const int button_threshold = static_cast<int>(ZL_param.Get("threshold", 0.5f) * 100.0f);
|
const int button_threshold = static_cast<int>(ZL_param.Get("threshold", 0.5f) * 100.0f);
|
||||||
ui->sliderZLThreshold->setValue(button_threshold);
|
ui->sliderZLThreshold->setValue(button_threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Common::ParamPackage ZR_param =
|
const Common::ParamPackage ZR_param =
|
||||||
system_controller->GetButtonParam(Settings::NativeButton::ZR);
|
emulated_controller->GetButtonParam(Settings::NativeButton::ZR);
|
||||||
if (ZR_param.Has("threshold")) {
|
if (ZR_param.Has("threshold")) {
|
||||||
const int button_threshold = static_cast<int>(ZR_param.Get("threshold", 0.5f) * 100.0f);
|
const int button_threshold = static_cast<int>(ZR_param.Get("threshold", 0.5f) * 100.0f);
|
||||||
ui->sliderZRThreshold->setValue(button_threshold);
|
ui->sliderZRThreshold->setValue(button_threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
|
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
|
||||||
const Common::ParamPackage param = system_controller->GetMotionParam(motion_id);
|
const Common::ParamPackage param = emulated_controller->GetMotionParam(motion_id);
|
||||||
motion_map[motion_id]->setText(ButtonToText(param));
|
motion_map[motion_id]->setText(ButtonToText(param));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
|
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
|
||||||
const Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
const Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||||
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
|
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
|
||||||
auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
|
auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
|
||||||
|
|
||||||
@ -1346,7 +1347,7 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
|||||||
if (button == nullptr) {
|
if (button == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
system_controller->SetButtonParam(button_id, {});
|
emulated_controller->SetButtonParam(button_id, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
|
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
|
||||||
@ -1355,7 +1356,7 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
|||||||
if (analog_button == nullptr) {
|
if (analog_button == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
system_controller->SetStickParam(analog_id, {});
|
emulated_controller->SetStickParam(analog_id, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1364,13 +1365,13 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
|||||||
if (motion_button == nullptr) {
|
if (motion_button == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
system_controller->SetMotionParam(motion_id, {});
|
emulated_controller->SetMotionParam(motion_id, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset keyboard or mouse bindings
|
// Reset keyboard or mouse bindings
|
||||||
if (ui->comboDevices->currentIndex() == 1 || ui->comboDevices->currentIndex() == 2) {
|
if (ui->comboDevices->currentIndex() == 1 || ui->comboDevices->currentIndex() == 2) {
|
||||||
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
|
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
|
||||||
system_controller->SetButtonParam(
|
emulated_controller->SetButtonParam(
|
||||||
button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam(
|
button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam(
|
||||||
Config::default_buttons[button_id])});
|
Config::default_buttons[button_id])});
|
||||||
}
|
}
|
||||||
@ -1384,11 +1385,11 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
|||||||
|
|
||||||
analog_param.Set("modifier", InputCommon::GenerateKeyboardParam(
|
analog_param.Set("modifier", InputCommon::GenerateKeyboardParam(
|
||||||
Config::default_stick_mod[analog_id]));
|
Config::default_stick_mod[analog_id]));
|
||||||
system_controller->SetStickParam(analog_id, analog_param);
|
emulated_controller->SetStickParam(analog_id, analog_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
|
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
|
||||||
system_controller->SetMotionParam(
|
emulated_controller->SetMotionParam(
|
||||||
motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam(
|
motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam(
|
||||||
Config::default_motions[motion_id])});
|
Config::default_motions[motion_id])});
|
||||||
}
|
}
|
||||||
@ -1408,15 +1409,15 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
|||||||
|
|
||||||
for (const auto& button_mapping : button_mappings) {
|
for (const auto& button_mapping : button_mappings) {
|
||||||
const std::size_t index = button_mapping.first;
|
const std::size_t index = button_mapping.first;
|
||||||
system_controller->SetButtonParam(index, button_mapping.second);
|
emulated_controller->SetButtonParam(index, button_mapping.second);
|
||||||
}
|
}
|
||||||
for (const auto& analog_mapping : analog_mappings) {
|
for (const auto& analog_mapping : analog_mappings) {
|
||||||
const std::size_t index = analog_mapping.first;
|
const std::size_t index = analog_mapping.first;
|
||||||
system_controller->SetStickParam(index, analog_mapping.second);
|
emulated_controller->SetStickParam(index, analog_mapping.second);
|
||||||
}
|
}
|
||||||
for (const auto& motion_mapping : motion_mappings) {
|
for (const auto& motion_mapping : motion_mappings) {
|
||||||
const std::size_t index = motion_mapping.first;
|
const std::size_t index = motion_mapping.first;
|
||||||
system_controller->SetMotionParam(index, motion_mapping.second);
|
emulated_controller->SetMotionParam(index, motion_mapping.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateUI();
|
UpdateUI();
|
||||||
@ -1608,7 +1609,7 @@ void ConfigureInputPlayer::SaveProfile() {
|
|||||||
ApplyConfiguration();
|
ApplyConfiguration();
|
||||||
|
|
||||||
// When we're in handheld mode, only the handheld emulated controller bindings are updated
|
// When we're in handheld mode, only the handheld emulated controller bindings are updated
|
||||||
const bool is_handheld = player_index == 0 && system_controller->GetNpadIdType() ==
|
const bool is_handheld = player_index == 0 && emulated_controller->GetNpadIdType() ==
|
||||||
Core::HID::NpadIdType::Handheld;
|
Core::HID::NpadIdType::Handheld;
|
||||||
const auto profile_player_index = is_handheld ? HANDHELD_INDEX : player_index;
|
const auto profile_player_index = is_handheld ? HANDHELD_INDEX : player_index;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ class ConfigureInputPlayer;
|
|||||||
|
|
||||||
namespace Core::HID {
|
namespace Core::HID {
|
||||||
class HIDCore;
|
class HIDCore;
|
||||||
class SystemController;
|
class EmulatedController;
|
||||||
enum class NpadStyleIndex : u8;
|
enum class NpadStyleIndex : u8;
|
||||||
} // namespace Core::HID
|
} // namespace Core::HID
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ private:
|
|||||||
/// This will be the the setting function when an input is awaiting configuration.
|
/// This will be the the setting function when an input is awaiting configuration.
|
||||||
std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
|
std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
|
||||||
|
|
||||||
Core::HID::SystemController* system_controller;
|
Core::HID::EmulatedController* emulated_controller;
|
||||||
|
|
||||||
static constexpr int ANALOG_SUB_BUTTONS_NUM = 4;
|
static constexpr int ANALOG_SUB_BUTTONS_NUM = 4;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user