split controller
This commit is contained in:
parent
238e46ec93
commit
896670345e
|
@ -159,6 +159,8 @@ add_library(core STATIC
|
|||
hid/irs_types.h
|
||||
hid/motion_input.cpp
|
||||
hid/motion_input.h
|
||||
hid/system_controller.cpp
|
||||
hid/system_controller.h
|
||||
hle/api_version.h
|
||||
hle/ipc.h
|
||||
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
|
||||
if (parameters.allow_pro_controller) {
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
||||
controller->Connect(true);
|
||||
controller->Connect();
|
||||
} else if (parameters.allow_dual_joycons) {
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
|
||||
controller->Connect(true);
|
||||
controller->Connect();
|
||||
} else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {
|
||||
// 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
|
||||
// a right Joycon for Player 2 in 2 Player Assist mode.
|
||||
if (index % 2 == 0) {
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft);
|
||||
controller->Connect(true);
|
||||
controller->Connect();
|
||||
} else {
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight);
|
||||
controller->Connect(true);
|
||||
controller->Connect();
|
||||
}
|
||||
} else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
|
||||
!Settings::values.use_docked_mode.GetValue()) {
|
||||
// We should *never* reach here under any normal circumstances.
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
||||
controller->Connect(true);
|
||||
controller->Connect();
|
||||
} else {
|
||||
ASSERT_MSG(false, "Unable to add a new controller based on the given parameters!");
|
||||
}
|
||||
|
|
|
@ -95,7 +95,6 @@ void EmulatedController::ReloadFromSettings() {
|
|||
motion_params[index] = Common::ParamPackage(player.motions[index]);
|
||||
}
|
||||
|
||||
controller.color_values = {};
|
||||
controller.colors_state.fullkey = {
|
||||
.body = GetNpadColor(player.body_color_left),
|
||||
.button = GetNpadColor(player.button_color_left),
|
||||
|
@ -537,181 +536,18 @@ void EmulatedController::UnloadInput() {
|
|||
}
|
||||
}
|
||||
|
||||
void EmulatedController::EnableConfiguration() {
|
||||
is_configuring = true;
|
||||
tmp_is_connected = is_connected;
|
||||
tmp_npad_type = npad_type;
|
||||
void EmulatedController::DisableInput() {
|
||||
npad_input_enabled = false;
|
||||
}
|
||||
|
||||
void EmulatedController::DisableConfiguration() {
|
||||
is_configuring = false;
|
||||
void EmulatedController::EnableInput() {
|
||||
npad_input_enabled = true;
|
||||
|
||||
// Get Joycon colors before turning on the controller
|
||||
for (const auto& color_device : color_devices) {
|
||||
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() {
|
||||
|
@ -766,16 +602,6 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
|
|||
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
|
||||
if (npad_type == NpadStyleIndex::GameCube) {
|
||||
if (index == Settings::NativeButton::ZR) {
|
||||
|
@ -857,18 +683,6 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
|
|||
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();
|
||||
|
@ -881,7 +695,7 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
|
|||
Connect();
|
||||
}
|
||||
}
|
||||
TriggerOnChange(ControllerTriggerType::Button, true);
|
||||
TriggerOnChange(ControllerTriggerType::Button);
|
||||
}
|
||||
|
||||
void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
|
@ -890,7 +704,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
|
|||
return;
|
||||
}
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); });
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick); });
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto stick_value = TransformToStick(callback);
|
||||
|
||||
|
@ -911,12 +725,6 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
|
|||
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),
|
||||
|
@ -946,7 +754,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
|
|||
return;
|
||||
}
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); });
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger); });
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto trigger_value = TransformToTrigger(callback);
|
||||
|
||||
|
@ -960,12 +768,6 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
|
|||
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();
|
||||
|
@ -992,7 +794,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
|
|||
if (index >= controller.motion_values.size()) {
|
||||
return;
|
||||
}
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); });
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion); });
|
||||
std::scoped_lock lock{mutex};
|
||||
auto& raw_status = controller.motion_values[index].raw_status;
|
||||
auto& emulated = controller.motion_values[index].emulated;
|
||||
|
@ -1023,48 +825,44 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
|
|||
|
||||
void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index >= controller.color_values.size()) {
|
||||
if (index > RightIndex) {
|
||||
return;
|
||||
}
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); });
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color); });
|
||||
std::scoped_lock lock{mutex};
|
||||
controller.color_values[index] = TransformToColor(callback);
|
||||
const auto color_values = TransformToColor(callback);
|
||||
|
||||
if (is_configuring) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (controller.color_values[index].body == 0) {
|
||||
if (color_values.body == 0) {
|
||||
trigger_guard.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
controller.colors_state.fullkey = {
|
||||
.body = GetNpadColor(controller.color_values[index].body),
|
||||
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||
.body = GetNpadColor(color_values.body),
|
||||
.button = GetNpadColor(color_values.buttons),
|
||||
};
|
||||
if (npad_type == NpadStyleIndex::ProController) {
|
||||
controller.colors_state.left = {
|
||||
.body = GetNpadColor(controller.color_values[index].left_grip),
|
||||
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||
.body = GetNpadColor(color_values.left_grip),
|
||||
.button = GetNpadColor(color_values.buttons),
|
||||
};
|
||||
controller.colors_state.right = {
|
||||
.body = GetNpadColor(controller.color_values[index].right_grip),
|
||||
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||
.body = GetNpadColor(color_values.right_grip),
|
||||
.button = GetNpadColor(color_values.buttons),
|
||||
};
|
||||
} else {
|
||||
switch (index) {
|
||||
case LeftIndex:
|
||||
controller.colors_state.left = {
|
||||
.body = GetNpadColor(controller.color_values[index].body),
|
||||
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||
.body = GetNpadColor(color_values.body),
|
||||
.button = GetNpadColor(color_values.buttons),
|
||||
};
|
||||
break;
|
||||
case RightIndex:
|
||||
controller.colors_state.right = {
|
||||
.body = GetNpadColor(controller.color_values[index].body),
|
||||
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||
.body = GetNpadColor(color_values.body),
|
||||
.button = GetNpadColor(color_values.buttons),
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
@ -1073,21 +871,17 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback
|
|||
|
||||
void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index >= controller.battery_values.size()) {
|
||||
if (index > DualIndex) {
|
||||
return;
|
||||
}
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); });
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery); });
|
||||
std::scoped_lock lock{mutex};
|
||||
controller.battery_values[index] = TransformToBattery(callback);
|
||||
|
||||
if (is_configuring) {
|
||||
return;
|
||||
}
|
||||
const auto battery_values = TransformToBattery(callback);
|
||||
|
||||
bool is_charging = false;
|
||||
bool is_powered = false;
|
||||
NpadBatteryLevel battery_level = 0;
|
||||
switch (controller.battery_values[index]) {
|
||||
switch (battery_values) {
|
||||
case Common::Input::BatteryLevel::Charging:
|
||||
is_charging = true;
|
||||
is_powered = true;
|
||||
|
@ -1139,46 +933,33 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
|
|||
}
|
||||
|
||||
void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) {
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); });
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor); });
|
||||
std::scoped_lock lock{mutex};
|
||||
controller.camera_values = TransformToCamera(callback);
|
||||
const auto camera_values = TransformToCamera(callback);
|
||||
|
||||
if (is_configuring) {
|
||||
return;
|
||||
}
|
||||
|
||||
controller.camera_state.sample++;
|
||||
controller.camera_state.format =
|
||||
static_cast<Core::IrSensor::ImageTransferProcessorFormat>(controller.camera_values.format);
|
||||
controller.camera_state.data = controller.camera_values.data;
|
||||
static_cast<Core::IrSensor::ImageTransferProcessorFormat>(camera_values.format);
|
||||
controller.camera_state.data = camera_values.data;
|
||||
}
|
||||
|
||||
void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) {
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); });
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController); });
|
||||
std::scoped_lock lock{mutex};
|
||||
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;
|
||||
}
|
||||
|
||||
void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); });
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc); });
|
||||
std::scoped_lock lock{mutex};
|
||||
controller.nfc_values = TransformToNfc(callback);
|
||||
|
||||
if (is_configuring) {
|
||||
return;
|
||||
}
|
||||
const auto nfc_values = TransformToNfc(callback);
|
||||
|
||||
controller.nfc_state = {
|
||||
controller.nfc_values.state,
|
||||
controller.nfc_values.data,
|
||||
nfc_values.state,
|
||||
nfc_values.data,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1409,10 +1190,9 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
|
|||
npad_type);
|
||||
}
|
||||
|
||||
bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
|
||||
bool EmulatedController::IsControllerFullkey() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||
switch (type) {
|
||||
switch (npad_type) {
|
||||
case NpadStyleIndex::ProController:
|
||||
case NpadStyleIndex::GameCube:
|
||||
case NpadStyleIndex::NES:
|
||||
|
@ -1425,10 +1205,9 @@ bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
|
|||
}
|
||||
}
|
||||
|
||||
bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
|
||||
bool EmulatedController::IsControllerSupported() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||
switch (type) {
|
||||
switch (npad_type) {
|
||||
case NpadStyleIndex::ProController:
|
||||
return supported_style_tag.fullkey.As<bool>();
|
||||
case NpadStyleIndex::Handheld:
|
||||
|
@ -1456,20 +1235,15 @@ bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
|
|||
}
|
||||
}
|
||||
|
||||
void EmulatedController::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);
|
||||
void EmulatedController::Connect() {
|
||||
if (!IsControllerSupported()) {
|
||||
LOG_ERROR(Service_HID, "Controller type {} is not supported", npad_type);
|
||||
return;
|
||||
}
|
||||
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); });
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected); });
|
||||
std::scoped_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
tmp_is_connected = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_connected) {
|
||||
trigger_guard.Cancel();
|
||||
|
@ -1480,12 +1254,8 @@ void EmulatedController::Connect(bool use_temporary_value) {
|
|||
|
||||
void EmulatedController::Disconnect() {
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); });
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected); });
|
||||
std::scoped_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
tmp_is_connected = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_connected) {
|
||||
trigger_guard.Cancel();
|
||||
|
@ -1494,11 +1264,8 @@ void EmulatedController::Disconnect() {
|
|||
is_connected = false;
|
||||
}
|
||||
|
||||
bool EmulatedController::IsConnected(bool get_temporary_value) const {
|
||||
bool EmulatedController::IsConnected() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (get_temporary_value && is_configuring) {
|
||||
return tmp_is_connected;
|
||||
}
|
||||
return is_connected;
|
||||
}
|
||||
|
||||
|
@ -1508,27 +1275,14 @@ NpadIdType EmulatedController::GetNpadIdType() 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;
|
||||
}
|
||||
|
||||
void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); });
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type); });
|
||||
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;
|
||||
|
@ -1568,87 +1322,23 @@ ButtonValues EmulatedController::GetButtonsValues() const {
|
|||
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 {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
return {};
|
||||
}
|
||||
return {controller.npad_button_state.raw & GetTurboButtonMask()};
|
||||
}
|
||||
|
||||
DebugPadButton EmulatedController::GetDebugPadButtons() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
return {};
|
||||
}
|
||||
return controller.debug_pad_button_state;
|
||||
}
|
||||
|
||||
AnalogSticks EmulatedController::GetSticks() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
if (is_configuring) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return controller.analog_stick_state;
|
||||
}
|
||||
|
||||
NpadGcTriggerState EmulatedController::GetTriggers() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
return {};
|
||||
}
|
||||
return controller.gc_trigger_state;
|
||||
}
|
||||
|
||||
|
@ -1673,6 +1363,7 @@ const CameraState& EmulatedController::GetCamera() const {
|
|||
}
|
||||
|
||||
RingSensorForce EmulatedController::GetRingSensorForce() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.ring_analog_state;
|
||||
}
|
||||
|
||||
|
@ -1690,13 +1381,10 @@ NpadColor EmulatedController::GetNpadColor(u32 color) {
|
|||
};
|
||||
}
|
||||
|
||||
void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
|
||||
void EmulatedController::TriggerOnChange(ControllerTriggerType type) {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -126,16 +126,8 @@ struct ControllerStatus {
|
|||
SticksValues stick_values{};
|
||||
ControllerMotionValues motion_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
|
||||
HomeButtonState home_button_state{};
|
||||
CaptureButtonState capture_button_state{};
|
||||
NpadButtonState npad_button_state{};
|
||||
DebugPadButton debug_pad_button_state{};
|
||||
AnalogSticks analog_stick_state{};
|
||||
|
@ -167,7 +159,6 @@ enum class ControllerTriggerType {
|
|||
|
||||
struct ControllerUpdateCallback {
|
||||
std::function<void(ControllerTriggerType)> on_change;
|
||||
bool is_npad_service;
|
||||
};
|
||||
|
||||
class EmulatedController {
|
||||
|
@ -210,43 +201,29 @@ public:
|
|||
|
||||
/**
|
||||
* 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);
|
||||
void Connect();
|
||||
|
||||
/// 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;
|
||||
bool IsConnected() const;
|
||||
|
||||
/// Removes all callbacks created from input devices
|
||||
void UnloadInput();
|
||||
|
||||
/**
|
||||
* Sets the emulated controller into configuring mode
|
||||
* Sets the emulated controller into idle mode
|
||||
* This prevents the modification of the HID state of the emulated controller by input commands
|
||||
*/
|
||||
void EnableConfiguration();
|
||||
void DisableInput();
|
||||
|
||||
/// 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;
|
||||
void EnableInput();
|
||||
|
||||
/// Reload all input devices
|
||||
void ReloadInput();
|
||||
|
@ -254,75 +231,9 @@ public:
|
|||
/// 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);
|
||||
|
||||
/// Auto calibrates the current motion devices
|
||||
void StartMotionCalibration();
|
||||
|
||||
/// 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 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
|
||||
NpadButtonState GetNpadButtons() const;
|
||||
|
||||
|
@ -432,17 +343,15 @@ private:
|
|||
void LoadVirtualGamepadParams();
|
||||
|
||||
/**
|
||||
* @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;
|
||||
bool IsControllerFullkey() 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;
|
||||
bool IsControllerSupported() const;
|
||||
|
||||
/**
|
||||
* Updates the button status of the controller
|
||||
|
@ -517,9 +426,8 @@ private:
|
|||
/**
|
||||
* 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);
|
||||
void TriggerOnChange(ControllerTriggerType type);
|
||||
|
||||
NpadButton GetTurboButtonMask() const;
|
||||
|
||||
|
@ -528,15 +436,10 @@ private:
|
|||
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};
|
||||
bool npad_input_enabled{true};
|
||||
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
|
||||
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;
|
||||
StickParams stick_params;
|
||||
ControllerMotionParams motion_params;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/emulated_devices.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hid/system_controller.h"
|
||||
|
||||
namespace Core::HID {
|
||||
|
||||
|
@ -20,6 +21,16 @@ HIDCore::HIDCore()
|
|||
player_8{std::make_unique<EmulatedController>(NpadIdType::Player8)},
|
||||
other{std::make_unique<EmulatedController>(NpadIdType::Other)},
|
||||
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>()} {}
|
||||
|
||||
HIDCore::~HIDCore() = default;
|
||||
|
@ -81,6 +92,65 @@ const EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type
|
|||
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() {
|
||||
return console.get();
|
||||
}
|
||||
|
@ -107,16 +177,16 @@ const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t inde
|
|||
|
||||
void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) {
|
||||
supported_style_tag.raw = style_tag.raw;
|
||||
player_1->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_2->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_3->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_4->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_5->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_6->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_7->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_8->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
other->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
handheld->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
system_player_1->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
system_player_2->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
system_player_3->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
system_player_4->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
system_player_5->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
system_player_6->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
system_player_7->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
system_player_8->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
system_other->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
system_handheld->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
}
|
||||
|
||||
NpadStyleTag HIDCore::GetSupportedStyleTag() const {
|
||||
|
@ -155,57 +225,57 @@ NpadIdType HIDCore::GetFirstDisconnectedNpadId() const {
|
|||
}
|
||||
|
||||
void HIDCore::EnableAllControllerConfiguration() {
|
||||
player_1->EnableConfiguration();
|
||||
player_2->EnableConfiguration();
|
||||
player_3->EnableConfiguration();
|
||||
player_4->EnableConfiguration();
|
||||
player_5->EnableConfiguration();
|
||||
player_6->EnableConfiguration();
|
||||
player_7->EnableConfiguration();
|
||||
player_8->EnableConfiguration();
|
||||
other->EnableConfiguration();
|
||||
handheld->EnableConfiguration();
|
||||
system_player_1->EnableConfiguration();
|
||||
system_player_2->EnableConfiguration();
|
||||
system_player_3->EnableConfiguration();
|
||||
system_player_4->EnableConfiguration();
|
||||
system_player_5->EnableConfiguration();
|
||||
system_player_6->EnableConfiguration();
|
||||
system_player_7->EnableConfiguration();
|
||||
system_player_8->EnableConfiguration();
|
||||
system_other->EnableConfiguration();
|
||||
system_handheld->EnableConfiguration();
|
||||
}
|
||||
|
||||
void HIDCore::DisableAllControllerConfiguration() {
|
||||
player_1->DisableConfiguration();
|
||||
player_2->DisableConfiguration();
|
||||
player_3->DisableConfiguration();
|
||||
player_4->DisableConfiguration();
|
||||
player_5->DisableConfiguration();
|
||||
player_6->DisableConfiguration();
|
||||
player_7->DisableConfiguration();
|
||||
player_8->DisableConfiguration();
|
||||
other->DisableConfiguration();
|
||||
handheld->DisableConfiguration();
|
||||
system_player_1->DisableConfiguration();
|
||||
system_player_2->DisableConfiguration();
|
||||
system_player_3->DisableConfiguration();
|
||||
system_player_4->DisableConfiguration();
|
||||
system_player_5->DisableConfiguration();
|
||||
system_player_6->DisableConfiguration();
|
||||
system_player_7->DisableConfiguration();
|
||||
system_player_8->DisableConfiguration();
|
||||
system_other->DisableConfiguration();
|
||||
system_handheld->DisableConfiguration();
|
||||
}
|
||||
|
||||
void HIDCore::ReloadInputDevices() {
|
||||
player_1->ReloadFromSettings();
|
||||
player_2->ReloadFromSettings();
|
||||
player_3->ReloadFromSettings();
|
||||
player_4->ReloadFromSettings();
|
||||
player_5->ReloadFromSettings();
|
||||
player_6->ReloadFromSettings();
|
||||
player_7->ReloadFromSettings();
|
||||
player_8->ReloadFromSettings();
|
||||
other->ReloadFromSettings();
|
||||
handheld->ReloadFromSettings();
|
||||
system_player_1->ReloadFromSettings();
|
||||
system_player_2->ReloadFromSettings();
|
||||
system_player_3->ReloadFromSettings();
|
||||
system_player_4->ReloadFromSettings();
|
||||
system_player_5->ReloadFromSettings();
|
||||
system_player_6->ReloadFromSettings();
|
||||
system_player_7->ReloadFromSettings();
|
||||
system_player_8->ReloadFromSettings();
|
||||
system_other->ReloadFromSettings();
|
||||
system_handheld->ReloadFromSettings();
|
||||
console->ReloadFromSettings();
|
||||
devices->ReloadFromSettings();
|
||||
}
|
||||
|
||||
void HIDCore::UnloadInputDevices() {
|
||||
player_1->UnloadInput();
|
||||
player_2->UnloadInput();
|
||||
player_3->UnloadInput();
|
||||
player_4->UnloadInput();
|
||||
player_5->UnloadInput();
|
||||
player_6->UnloadInput();
|
||||
player_7->UnloadInput();
|
||||
player_8->UnloadInput();
|
||||
other->UnloadInput();
|
||||
handheld->UnloadInput();
|
||||
system_player_1->UnloadInput();
|
||||
system_player_2->UnloadInput();
|
||||
system_player_3->UnloadInput();
|
||||
system_player_4->UnloadInput();
|
||||
system_player_5->UnloadInput();
|
||||
system_player_6->UnloadInput();
|
||||
system_player_7->UnloadInput();
|
||||
system_player_8->UnloadInput();
|
||||
system_other->UnloadInput();
|
||||
system_handheld->UnloadInput();
|
||||
console->UnloadInput();
|
||||
devices->UnloadInput();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Core::HID {
|
|||
class EmulatedConsole;
|
||||
class EmulatedController;
|
||||
class EmulatedDevices;
|
||||
class SystemController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Core::HID {
|
||||
|
@ -30,6 +31,12 @@ public:
|
|||
EmulatedController* GetEmulatedControllerByIndex(std::size_t index);
|
||||
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();
|
||||
const EmulatedConsole* GetEmulatedConsole() const;
|
||||
|
||||
|
@ -76,6 +83,16 @@ private:
|
|||
std::unique_ptr<EmulatedController> handheld;
|
||||
std::unique_ptr<EmulatedConsole> console;
|
||||
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};
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,860 @@
|
|||
// 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
|
|
@ -0,0 +1,330 @@
|
|||
// 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,7 +24,6 @@ ClusteringProcessor::ClusteringProcessor(Core::HID::HIDCore& hid_core_,
|
|||
|
||||
Core::HID::ControllerUpdateCallback engine_callback{
|
||||
.on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); },
|
||||
.is_npad_service = true,
|
||||
};
|
||||
callback_key = npad_device->SetCallback(engine_callback);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <QStandardItemModel>
|
||||
#include <QTimer>
|
||||
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/system_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
|
||||
#include "ui_configure_hotkeys.h"
|
||||
|
@ -42,7 +42,7 @@ ConfigureHotkeys::ConfigureHotkeys(Core::HID::HIDCore& hid_core, QWidget* parent
|
|||
&ConfigureHotkeys::RestoreDefaults);
|
||||
connect(ui->button_clear_all, &QPushButton::clicked, this, &ConfigureHotkeys::ClearAll);
|
||||
|
||||
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||
controller = hid_core.GetSystemController(Core::HID::NpadIdType::Player1);
|
||||
|
||||
connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); });
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ class ParamPackage;
|
|||
|
||||
namespace Core::HID {
|
||||
class HIDCore;
|
||||
class EmulatedController;
|
||||
class SystemController;
|
||||
enum class NpadButton : u64;
|
||||
} // namespace Core::HID
|
||||
|
||||
|
@ -60,7 +60,7 @@ private:
|
|||
|
||||
void SetPollingResult(Core::HID::NpadButton button, bool cancel);
|
||||
QString GetButtonCombinationName(Core::HID::NpadButton button, bool home, bool capture) const;
|
||||
Core::HID::EmulatedController* controller;
|
||||
Core::HID::SystemController* controller;
|
||||
std::unique_ptr<QTimer> timeout_timer;
|
||||
std::unique_ptr<QTimer> poll_timer;
|
||||
std::optional<std::function<void(Core::HID::NpadButton, bool)>> input_setter;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <QTimer>
|
||||
#include "common/assert.h"
|
||||
#include "common/param_package.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/system_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hid/hid_types.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>()),
|
||||
poll_timer(std::make_unique<QTimer>()), bottom_row{bottom_row_}, hid_core{hid_core_} {
|
||||
if (player_index == 0) {
|
||||
auto* emulated_controller_p1 =
|
||||
hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||
auto* emulated_controller_handheld =
|
||||
hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||
emulated_controller_p1->SaveCurrentConfig();
|
||||
emulated_controller_p1->EnableConfiguration();
|
||||
emulated_controller_handheld->SaveCurrentConfig();
|
||||
emulated_controller_handheld->EnableConfiguration();
|
||||
if (emulated_controller_handheld->IsConnected(true)) {
|
||||
emulated_controller_p1->Disconnect();
|
||||
emulated_controller = emulated_controller_handheld;
|
||||
auto* system_controller_p1 =
|
||||
hid_core.GetSystemController(Core::HID::NpadIdType::Player1);
|
||||
auto* system_controller_handheld =
|
||||
hid_core.GetSystemController(Core::HID::NpadIdType::Handheld);
|
||||
system_controller_p1->SaveCurrentConfig();
|
||||
system_controller_p1->EnableConfiguration();
|
||||
system_controller_handheld->SaveCurrentConfig();
|
||||
system_controller_handheld->EnableConfiguration();
|
||||
if (system_controller_handheld->IsConnected(true)) {
|
||||
system_controller_p1->Disconnect();
|
||||
system_controller = system_controller_handheld;
|
||||
} else {
|
||||
emulated_controller = emulated_controller_p1;
|
||||
system_controller = system_controller_p1;
|
||||
}
|
||||
} else {
|
||||
emulated_controller = hid_core.GetEmulatedControllerByIndex(player_index);
|
||||
emulated_controller->SaveCurrentConfig();
|
||||
emulated_controller->EnableConfiguration();
|
||||
system_controller = hid_core.GetSystemControllerByIndex(player_index);
|
||||
system_controller->SaveCurrentConfig();
|
||||
system_controller->EnableConfiguration();
|
||||
}
|
||||
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_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange};
|
||||
|
||||
ui->controllerFrame->SetController(emulated_controller);
|
||||
ui->controllerFrame->SetController(system_controller->GetNpadIdType());
|
||||
|
||||
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
|
||||
auto* const button = button_map[button_id];
|
||||
|
@ -370,7 +370,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
HandleClick(
|
||||
button, button_id,
|
||||
[=, this](const Common::ParamPackage& params) {
|
||||
emulated_controller->SetButtonParam(button_id, params);
|
||||
system_controller->SetButtonParam(button_id, params);
|
||||
},
|
||||
InputCommon::Polling::InputType::Button);
|
||||
});
|
||||
|
@ -379,9 +379,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
connect(button, &QPushButton::customContextMenuRequested,
|
||||
[=, this](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
Common::ParamPackage param = emulated_controller->GetButtonParam(button_id);
|
||||
Common::ParamPackage param = system_controller->GetButtonParam(button_id);
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
emulated_controller->SetButtonParam(button_id, {});
|
||||
system_controller->SetButtonParam(button_id, {});
|
||||
button_map[button_id]->setText(tr("[not set]"));
|
||||
});
|
||||
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);
|
||||
param.Set("inverted", invert_value);
|
||||
button_map[button_id]->setText(ButtonToText(param));
|
||||
emulated_controller->SetButtonParam(button_id, param);
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
});
|
||||
context_menu.addAction(tr("Toggle button"), [&] {
|
||||
const bool toggle_value = !param.Get("toggle", false);
|
||||
param.Set("toggle", toggle_value);
|
||||
button_map[button_id]->setText(ButtonToText(param));
|
||||
emulated_controller->SetButtonParam(button_id, param);
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
});
|
||||
context_menu.addAction(tr("Turbo button"), [&] {
|
||||
const bool turbo_value = !param.Get("turbo", false);
|
||||
param.Set("turbo", turbo_value);
|
||||
button_map[button_id]->setText(ButtonToText(param));
|
||||
emulated_controller->SetButtonParam(button_id, param);
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
});
|
||||
}
|
||||
if (param.Has("axis")) {
|
||||
|
@ -409,13 +409,13 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
const bool toggle_value = !(param.Get("invert", "+") == "-");
|
||||
param.Set("invert", toggle_value ? "-" : "+");
|
||||
button_map[button_id]->setText(ButtonToText(param));
|
||||
emulated_controller->SetButtonParam(button_id, param);
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
});
|
||||
context_menu.addAction(tr("Invert button"), [&] {
|
||||
const bool invert_value = !param.Get("inverted", false);
|
||||
param.Set("inverted", invert_value);
|
||||
button_map[button_id]->setText(ButtonToText(param));
|
||||
emulated_controller->SetButtonParam(button_id, param);
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
});
|
||||
context_menu.addAction(tr("Set threshold"), [&] {
|
||||
const int button_threshold =
|
||||
|
@ -431,13 +431,13 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
if (button_id == Settings::NativeButton::ZR) {
|
||||
ui->sliderZRThreshold->setValue(new_threshold);
|
||||
}
|
||||
emulated_controller->SetButtonParam(button_id, param);
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
});
|
||||
context_menu.addAction(tr("Toggle axis"), [&] {
|
||||
const bool toggle_value = !param.Get("toggle", false);
|
||||
param.Set("toggle", toggle_value);
|
||||
button_map[button_id]->setText(ButtonToText(param));
|
||||
emulated_controller->SetButtonParam(button_id, param);
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
});
|
||||
}
|
||||
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
|
||||
|
@ -454,7 +454,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
HandleClick(
|
||||
button, motion_id,
|
||||
[=, this](const Common::ParamPackage& params) {
|
||||
emulated_controller->SetMotionParam(motion_id, params);
|
||||
system_controller->SetMotionParam(motion_id, params);
|
||||
},
|
||||
InputCommon::Polling::InputType::Motion);
|
||||
});
|
||||
|
@ -464,9 +464,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
connect(button, &QPushButton::customContextMenuRequested,
|
||||
[=, this](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
Common::ParamPackage param = emulated_controller->GetMotionParam(motion_id);
|
||||
Common::ParamPackage param = system_controller->GetMotionParam(motion_id);
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
emulated_controller->SetMotionParam(motion_id, {});
|
||||
system_controller->SetMotionParam(motion_id, {});
|
||||
motion_map[motion_id]->setText(tr("[not set]"));
|
||||
});
|
||||
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%"),
|
||||
gyro_threshold, 0, 100);
|
||||
param.Set("threshold", new_threshold / 1000.0f);
|
||||
emulated_controller->SetMotionParam(motion_id, param);
|
||||
system_controller->SetMotionParam(motion_id, param);
|
||||
});
|
||||
context_menu.addAction(tr("Calibrate sensor"), [&] {
|
||||
emulated_controller->StartMotionCalibration();
|
||||
|
@ -489,21 +489,21 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
|
||||
connect(ui->sliderZLThreshold, &QSlider::valueChanged, [=, this] {
|
||||
Common::ParamPackage param =
|
||||
emulated_controller->GetButtonParam(Settings::NativeButton::ZL);
|
||||
system_controller->GetButtonParam(Settings::NativeButton::ZL);
|
||||
if (param.Has("threshold")) {
|
||||
const auto slider_value = ui->sliderZLThreshold->value();
|
||||
param.Set("threshold", slider_value / 100.0f);
|
||||
emulated_controller->SetButtonParam(Settings::NativeButton::ZL, param);
|
||||
system_controller->SetButtonParam(Settings::NativeButton::ZL, param);
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->sliderZRThreshold, &QSlider::valueChanged, [=, this] {
|
||||
Common::ParamPackage param =
|
||||
emulated_controller->GetButtonParam(Settings::NativeButton::ZR);
|
||||
system_controller->GetButtonParam(Settings::NativeButton::ZR);
|
||||
if (param.Has("threshold")) {
|
||||
const auto slider_value = ui->sliderZRThreshold->value();
|
||||
param.Set("threshold", slider_value / 100.0f);
|
||||
emulated_controller->SetButtonParam(Settings::NativeButton::ZR, param);
|
||||
system_controller->SetButtonParam(Settings::NativeButton::ZR, param);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -531,7 +531,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
HandleClick(
|
||||
analog_map_buttons[analog_id][sub_button_id], analog_id,
|
||||
[=, this](const Common::ParamPackage& params) {
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
||||
SetAnalogParam(params, param, analog_sub_buttons[sub_button_id]);
|
||||
// Correct axis direction for inverted sticks
|
||||
if (input_subsystem->IsStickInverted(param)) {
|
||||
|
@ -552,7 +552,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
break;
|
||||
}
|
||||
}
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
},
|
||||
InputCommon::Polling::InputType::Stick);
|
||||
});
|
||||
|
@ -562,10 +562,10 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
connect(analog_button, &QPushButton::customContextMenuRequested,
|
||||
[=, this](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
if (param.Get("engine", "") != "analog_from_button") {
|
||||
emulated_controller->SetStickParam(analog_id, {});
|
||||
system_controller->SetStickParam(analog_id, {});
|
||||
for (auto button : analog_map_buttons[analog_id]) {
|
||||
button->setText(tr("[not set]"));
|
||||
}
|
||||
|
@ -585,12 +585,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
param.Erase("right");
|
||||
break;
|
||||
}
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
|
||||
});
|
||||
context_menu.addAction(tr("Center axis"), [&] {
|
||||
const auto stick_value =
|
||||
emulated_controller->GetSticksValues()[analog_id];
|
||||
system_controller->GetSticksValues()[analog_id];
|
||||
const float offset_x = stick_value.x.properties.offset;
|
||||
const float offset_y = stick_value.y.properties.offset;
|
||||
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_y", -raw_value_y + offset_y);
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
});
|
||||
context_menu.addAction(tr("Invert axis"), [&] {
|
||||
if (sub_button_id == 2 || sub_button_id == 3) {
|
||||
const bool invert_value = param.Get("invert_x", "+") == "-";
|
||||
const std::string invert_str = invert_value ? "+" : "-";
|
||||
param.Set("invert_x", invert_str);
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
}
|
||||
if (sub_button_id == 0 || sub_button_id == 1) {
|
||||
const bool invert_value = param.Get("invert_y", "+") == "-";
|
||||
const std::string invert_str = invert_value ? "+" : "-";
|
||||
param.Set("invert_y", invert_str);
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
}
|
||||
for (int analog_sub_button_id = 0;
|
||||
analog_sub_button_id < ANALOG_SUB_BUTTONS_NUM;
|
||||
|
@ -644,9 +644,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
HandleClick(
|
||||
analog_map_modifier_button[analog_id], analog_id,
|
||||
[=, this](const Common::ParamPackage& params) {
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
||||
param.Set("modifier", params.Serialize());
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
},
|
||||
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,
|
||||
[=, this](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
param.Set("modifier", "");
|
||||
analog_map_modifier_button[analog_id]->setText(tr("[not set]"));
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
});
|
||||
context_menu.addAction(tr("Toggle button"), [&] {
|
||||
Common::ParamPackage modifier_param =
|
||||
|
@ -670,7 +670,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
modifier_param.Set("toggle", toggle_value);
|
||||
param.Set("modifier", modifier_param.Serialize());
|
||||
analog_map_modifier_button[analog_id]->setText(ButtonToText(modifier_param));
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
});
|
||||
context_menu.addAction(tr("Invert button"), [&] {
|
||||
Common::ParamPackage modifier_param =
|
||||
|
@ -679,7 +679,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
modifier_param.Set("inverted", invert_value);
|
||||
param.Set("modifier", modifier_param.Serialize());
|
||||
analog_map_modifier_button[analog_id]->setText(ButtonToText(modifier_param));
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
});
|
||||
context_menu.exec(
|
||||
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),
|
||||
[=, this] {
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
||||
const auto spinbox_value = analog_map_range_spinbox[analog_id]->value();
|
||||
param.Set("range", spinbox_value / 100.0f);
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
});
|
||||
|
||||
connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] {
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
||||
const auto slider_value = analog_map_deadzone_slider[analog_id]->value();
|
||||
analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value));
|
||||
param.Set("deadzone", slider_value / 100.0f);
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
});
|
||||
|
||||
connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] {
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
||||
const auto slider_value = analog_map_modifier_slider[analog_id]->value();
|
||||
analog_map_modifier_label[analog_id]->setText(
|
||||
tr("Modifier Range: %1%").arg(slider_value));
|
||||
param.Set("modifier_scale", slider_value / 100.0f);
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -749,28 +749,28 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
|
||||
|
||||
if (player_index == 0) {
|
||||
auto* emulated_controller_p1 =
|
||||
hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||
auto* emulated_controller_handheld =
|
||||
hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||
bool is_connected = emulated_controller->IsConnected(true);
|
||||
auto* system_controller_p1 =
|
||||
hid_core.GetSystemController(Core::HID::NpadIdType::Player1);
|
||||
auto* system_controller_handheld =
|
||||
hid_core.GetSystemController(Core::HID::NpadIdType::Handheld);
|
||||
bool is_connected = system_controller->IsConnected(true);
|
||||
|
||||
emulated_controller_p1->SetNpadStyleIndex(type);
|
||||
emulated_controller_handheld->SetNpadStyleIndex(type);
|
||||
system_controller_p1->SetNpadStyleIndex(type);
|
||||
system_controller_handheld->SetNpadStyleIndex(type);
|
||||
if (is_connected) {
|
||||
if (type == Core::HID::NpadStyleIndex::Handheld) {
|
||||
emulated_controller_p1->Disconnect();
|
||||
emulated_controller_handheld->Connect(true);
|
||||
emulated_controller = emulated_controller_handheld;
|
||||
system_controller_p1->Disconnect();
|
||||
system_controller_handheld->Connect(true);
|
||||
system_controller = system_controller_handheld;
|
||||
} else {
|
||||
emulated_controller_handheld->Disconnect();
|
||||
emulated_controller_p1->Connect(true);
|
||||
emulated_controller = emulated_controller_p1;
|
||||
system_controller_handheld->Disconnect();
|
||||
system_controller_p1->Connect(true);
|
||||
system_controller = system_controller_p1;
|
||||
}
|
||||
}
|
||||
ui->controllerFrame->SetController(emulated_controller);
|
||||
ui->controllerFrame->SetController(system_controller->GetNpadIdType());
|
||||
}
|
||||
emulated_controller->SetNpadStyleIndex(type);
|
||||
system_controller->SetNpadStyleIndex(type);
|
||||
});
|
||||
|
||||
connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this,
|
||||
|
@ -806,34 +806,33 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
|||
|
||||
ConfigureInputPlayer::~ConfigureInputPlayer() {
|
||||
if (player_index == 0) {
|
||||
auto* emulated_controller_p1 =
|
||||
hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||
auto* emulated_controller_handheld =
|
||||
hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||
emulated_controller_p1->DisableConfiguration();
|
||||
emulated_controller_handheld->DisableConfiguration();
|
||||
auto* system_controller_p1 =
|
||||
hid_core.GetSystemController(Core::HID::NpadIdType::Player1);
|
||||
auto* system_controller_handheld =
|
||||
hid_core.GetSystemController(Core::HID::NpadIdType::Handheld);
|
||||
system_controller_p1->DisableConfiguration();
|
||||
system_controller_handheld->DisableConfiguration();
|
||||
} else {
|
||||
emulated_controller->DisableConfiguration();
|
||||
system_controller->DisableConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureInputPlayer::ApplyConfiguration() {
|
||||
if (player_index == 0) {
|
||||
auto* emulated_controller_p1 =
|
||||
hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||
auto* emulated_controller_handheld =
|
||||
hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||
emulated_controller_p1->DisableConfiguration();
|
||||
emulated_controller_p1->SaveCurrentConfig();
|
||||
emulated_controller_p1->EnableConfiguration();
|
||||
emulated_controller_handheld->DisableConfiguration();
|
||||
emulated_controller_handheld->SaveCurrentConfig();
|
||||
emulated_controller_handheld->EnableConfiguration();
|
||||
auto* system_controller_p1 = hid_core.GetSystemController(Core::HID::NpadIdType::Player1);
|
||||
auto* system_controller_handheld =
|
||||
hid_core.GetSystemController(Core::HID::NpadIdType::Handheld);
|
||||
system_controller_p1->DisableConfiguration();
|
||||
system_controller_p1->SaveCurrentConfig();
|
||||
system_controller_p1->EnableConfiguration();
|
||||
system_controller_handheld->DisableConfiguration();
|
||||
system_controller_handheld->SaveCurrentConfig();
|
||||
system_controller_handheld->EnableConfiguration();
|
||||
return;
|
||||
}
|
||||
emulated_controller->DisableConfiguration();
|
||||
emulated_controller->SaveCurrentConfig();
|
||||
emulated_controller->EnableConfiguration();
|
||||
system_controller->DisableConfiguration();
|
||||
system_controller->SaveCurrentConfig();
|
||||
system_controller->EnableConfiguration();
|
||||
}
|
||||
|
||||
void ConfigureInputPlayer::showEvent(QShowEvent* event) {
|
||||
|
@ -858,7 +857,7 @@ void ConfigureInputPlayer::RetranslateUI() {
|
|||
}
|
||||
|
||||
void ConfigureInputPlayer::LoadConfiguration() {
|
||||
emulated_controller->ReloadFromSettings();
|
||||
system_controller->ReloadFromSettings();
|
||||
|
||||
UpdateUI();
|
||||
UpdateInputDeviceCombobox();
|
||||
|
@ -868,17 +867,17 @@ void ConfigureInputPlayer::LoadConfiguration() {
|
|||
}
|
||||
|
||||
const int comboBoxIndex =
|
||||
GetIndexFromControllerType(emulated_controller->GetNpadStyleIndex(true));
|
||||
GetIndexFromControllerType(system_controller->GetNpadStyleIndex(true));
|
||||
ui->comboControllerType->setCurrentIndex(comboBoxIndex);
|
||||
ui->groupConnectedController->setChecked(emulated_controller->IsConnected(true));
|
||||
ui->groupConnectedController->setChecked(system_controller->IsConnected(true));
|
||||
}
|
||||
|
||||
void ConfigureInputPlayer::ConnectPlayer(bool connected) {
|
||||
ui->groupConnectedController->setChecked(connected);
|
||||
if (connected) {
|
||||
emulated_controller->Connect(true);
|
||||
system_controller->Connect(true);
|
||||
} else {
|
||||
emulated_controller->Disconnect();
|
||||
system_controller->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -889,7 +888,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() {
|
|||
return;
|
||||
}
|
||||
|
||||
const auto devices = emulated_controller->GetMappedDevices();
|
||||
const auto devices = system_controller->GetMappedDevices();
|
||||
UpdateInputDevices();
|
||||
|
||||
if (devices.empty()) {
|
||||
|
@ -968,7 +967,7 @@ void ConfigureInputPlayer::ClearAll() {
|
|||
if (button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
emulated_controller->SetButtonParam(button_id, {});
|
||||
system_controller->SetButtonParam(button_id, {});
|
||||
}
|
||||
|
||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
|
||||
|
@ -977,7 +976,7 @@ void ConfigureInputPlayer::ClearAll() {
|
|||
if (analog_button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
emulated_controller->SetStickParam(analog_id, {});
|
||||
system_controller->SetStickParam(analog_id, {});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -986,7 +985,7 @@ void ConfigureInputPlayer::ClearAll() {
|
|||
if (motion_button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
emulated_controller->SetMotionParam(motion_id, {});
|
||||
system_controller->SetMotionParam(motion_id, {});
|
||||
}
|
||||
|
||||
UpdateUI();
|
||||
|
@ -995,31 +994,31 @@ void ConfigureInputPlayer::ClearAll() {
|
|||
|
||||
void ConfigureInputPlayer::UpdateUI() {
|
||||
for (int button = 0; button < Settings::NativeButton::NumButtons; ++button) {
|
||||
const Common::ParamPackage param = emulated_controller->GetButtonParam(button);
|
||||
const Common::ParamPackage param = system_controller->GetButtonParam(button);
|
||||
button_map[button]->setText(ButtonToText(param));
|
||||
}
|
||||
|
||||
const Common::ParamPackage ZL_param =
|
||||
emulated_controller->GetButtonParam(Settings::NativeButton::ZL);
|
||||
system_controller->GetButtonParam(Settings::NativeButton::ZL);
|
||||
if (ZL_param.Has("threshold")) {
|
||||
const int button_threshold = static_cast<int>(ZL_param.Get("threshold", 0.5f) * 100.0f);
|
||||
ui->sliderZLThreshold->setValue(button_threshold);
|
||||
}
|
||||
|
||||
const Common::ParamPackage ZR_param =
|
||||
emulated_controller->GetButtonParam(Settings::NativeButton::ZR);
|
||||
system_controller->GetButtonParam(Settings::NativeButton::ZR);
|
||||
if (ZR_param.Has("threshold")) {
|
||||
const int button_threshold = static_cast<int>(ZR_param.Get("threshold", 0.5f) * 100.0f);
|
||||
ui->sliderZRThreshold->setValue(button_threshold);
|
||||
}
|
||||
|
||||
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
|
||||
const Common::ParamPackage param = emulated_controller->GetMotionParam(motion_id);
|
||||
const Common::ParamPackage param = system_controller->GetMotionParam(motion_id);
|
||||
motion_map[motion_id]->setText(ButtonToText(param));
|
||||
}
|
||||
|
||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
|
||||
const Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
const Common::ParamPackage param = system_controller->GetStickParam(analog_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];
|
||||
|
||||
|
@ -1347,7 +1346,7 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
|||
if (button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
emulated_controller->SetButtonParam(button_id, {});
|
||||
system_controller->SetButtonParam(button_id, {});
|
||||
}
|
||||
|
||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
|
||||
|
@ -1356,7 +1355,7 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
|||
if (analog_button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
emulated_controller->SetStickParam(analog_id, {});
|
||||
system_controller->SetStickParam(analog_id, {});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1365,13 +1364,13 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
|||
if (motion_button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
emulated_controller->SetMotionParam(motion_id, {});
|
||||
system_controller->SetMotionParam(motion_id, {});
|
||||
}
|
||||
|
||||
// Reset keyboard or mouse bindings
|
||||
if (ui->comboDevices->currentIndex() == 1 || ui->comboDevices->currentIndex() == 2) {
|
||||
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
|
||||
emulated_controller->SetButtonParam(
|
||||
system_controller->SetButtonParam(
|
||||
button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam(
|
||||
Config::default_buttons[button_id])});
|
||||
}
|
||||
|
@ -1385,11 +1384,11 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
|||
|
||||
analog_param.Set("modifier", InputCommon::GenerateKeyboardParam(
|
||||
Config::default_stick_mod[analog_id]));
|
||||
emulated_controller->SetStickParam(analog_id, analog_param);
|
||||
system_controller->SetStickParam(analog_id, analog_param);
|
||||
}
|
||||
|
||||
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
|
||||
emulated_controller->SetMotionParam(
|
||||
system_controller->SetMotionParam(
|
||||
motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam(
|
||||
Config::default_motions[motion_id])});
|
||||
}
|
||||
|
@ -1409,15 +1408,15 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
|||
|
||||
for (const auto& button_mapping : button_mappings) {
|
||||
const std::size_t index = button_mapping.first;
|
||||
emulated_controller->SetButtonParam(index, button_mapping.second);
|
||||
system_controller->SetButtonParam(index, button_mapping.second);
|
||||
}
|
||||
for (const auto& analog_mapping : analog_mappings) {
|
||||
const std::size_t index = analog_mapping.first;
|
||||
emulated_controller->SetStickParam(index, analog_mapping.second);
|
||||
system_controller->SetStickParam(index, analog_mapping.second);
|
||||
}
|
||||
for (const auto& motion_mapping : motion_mappings) {
|
||||
const std::size_t index = motion_mapping.first;
|
||||
emulated_controller->SetMotionParam(index, motion_mapping.second);
|
||||
system_controller->SetMotionParam(index, motion_mapping.second);
|
||||
}
|
||||
|
||||
UpdateUI();
|
||||
|
@ -1609,7 +1608,7 @@ void ConfigureInputPlayer::SaveProfile() {
|
|||
ApplyConfiguration();
|
||||
|
||||
// When we're in handheld mode, only the handheld emulated controller bindings are updated
|
||||
const bool is_handheld = player_index == 0 && emulated_controller->GetNpadIdType() ==
|
||||
const bool is_handheld = player_index == 0 && system_controller->GetNpadIdType() ==
|
||||
Core::HID::NpadIdType::Handheld;
|
||||
const auto profile_player_index = is_handheld ? HANDHELD_INDEX : player_index;
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ class ConfigureInputPlayer;
|
|||
|
||||
namespace Core::HID {
|
||||
class HIDCore;
|
||||
class EmulatedController;
|
||||
class SystemController;
|
||||
enum class NpadStyleIndex : u8;
|
||||
} // namespace Core::HID
|
||||
|
||||
|
@ -189,7 +189,7 @@ private:
|
|||
/// This will be the the setting function when an input is awaiting configuration.
|
||||
std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
|
||||
|
||||
Core::HID::EmulatedController* emulated_controller;
|
||||
Core::HID::SystemController* system_controller;
|
||||
|
||||
static constexpr int ANALOG_SUB_BUTTONS_NUM = 4;
|
||||
|
||||
|
|
Loading…
Reference in New Issue