Compare commits
2 Commits
system-con
...
controller
Author | SHA1 | Date | |
---|---|---|---|
b6478b2de9 | |||
3055ebc9a0 |
@ -159,8 +159,6 @@ 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();
|
||||
controller->Connect(true);
|
||||
} else if (parameters.allow_dual_joycons) {
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
|
||||
controller->Connect();
|
||||
controller->Connect(true);
|
||||
} 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();
|
||||
controller->Connect(true);
|
||||
} else {
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight);
|
||||
controller->Connect();
|
||||
controller->Connect(true);
|
||||
}
|
||||
} 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();
|
||||
controller->Connect(true);
|
||||
} else {
|
||||
ASSERT_MSG(false, "Unable to add a new controller based on the given parameters!");
|
||||
}
|
||||
|
@ -95,6 +95,7 @@ void EmulatedController::ReloadFromSettings() {
|
||||
motion_params[index] = Common::ParamPackage(player.motions[index]);
|
||||
}
|
||||
|
||||
controller.color_values = {};
|
||||
controller.colors_state.fullkey = {
|
||||
.body = GetNpadColor(player.body_color_left),
|
||||
.button = GetNpadColor(player.button_color_left),
|
||||
@ -536,18 +537,181 @@ void EmulatedController::UnloadInput() {
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatedController::DisableInput() {
|
||||
npad_input_enabled = false;
|
||||
void EmulatedController::EnableConfiguration() {
|
||||
is_configuring = true;
|
||||
tmp_is_connected = is_connected;
|
||||
tmp_npad_type = npad_type;
|
||||
}
|
||||
|
||||
void EmulatedController::EnableInput() {
|
||||
npad_input_enabled = true;
|
||||
void EmulatedController::DisableConfiguration() {
|
||||
is_configuring = false;
|
||||
|
||||
// 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() {
|
||||
@ -602,6 +766,16 @@ 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) {
|
||||
@ -683,6 +857,18 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
|
||||
controller.npad_button_state.left_sr.Assign(current_status.value);
|
||||
controller.npad_button_state.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();
|
||||
@ -695,7 +881,7 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
|
||||
Connect();
|
||||
}
|
||||
}
|
||||
TriggerOnChange(ControllerTriggerType::Button);
|
||||
TriggerOnChange(ControllerTriggerType::Button, true);
|
||||
}
|
||||
|
||||
void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
@ -704,7 +890,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
|
||||
return;
|
||||
}
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick); });
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto stick_value = TransformToStick(callback);
|
||||
|
||||
@ -725,6 +911,12 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
|
||||
controller.stick_values[index] = stick_value;
|
||||
controller.stick_values[index].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),
|
||||
@ -754,7 +946,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
|
||||
return;
|
||||
}
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger); });
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto trigger_value = TransformToTrigger(callback);
|
||||
|
||||
@ -768,6 +960,12 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
|
||||
controller.trigger_values[index] = trigger_value;
|
||||
controller.trigger_values[index].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();
|
||||
@ -794,7 +992,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
|
||||
if (index >= controller.motion_values.size()) {
|
||||
return;
|
||||
}
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion); });
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
auto& raw_status = controller.motion_values[index].raw_status;
|
||||
auto& emulated = controller.motion_values[index].emulated;
|
||||
@ -825,44 +1023,48 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
|
||||
|
||||
void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index > RightIndex) {
|
||||
if (index >= controller.color_values.size()) {
|
||||
return;
|
||||
}
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color); });
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto color_values = TransformToColor(callback);
|
||||
controller.color_values[index] = TransformToColor(callback);
|
||||
|
||||
if (color_values.body == 0) {
|
||||
if (is_configuring) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (controller.color_values[index].body == 0) {
|
||||
trigger_guard.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
controller.colors_state.fullkey = {
|
||||
.body = GetNpadColor(color_values.body),
|
||||
.button = GetNpadColor(color_values.buttons),
|
||||
.body = GetNpadColor(controller.color_values[index].body),
|
||||
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||
};
|
||||
if (npad_type == NpadStyleIndex::ProController) {
|
||||
controller.colors_state.left = {
|
||||
.body = GetNpadColor(color_values.left_grip),
|
||||
.button = GetNpadColor(color_values.buttons),
|
||||
.body = GetNpadColor(controller.color_values[index].left_grip),
|
||||
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||
};
|
||||
controller.colors_state.right = {
|
||||
.body = GetNpadColor(color_values.right_grip),
|
||||
.button = GetNpadColor(color_values.buttons),
|
||||
.body = GetNpadColor(controller.color_values[index].right_grip),
|
||||
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||
};
|
||||
} else {
|
||||
switch (index) {
|
||||
case LeftIndex:
|
||||
controller.colors_state.left = {
|
||||
.body = GetNpadColor(color_values.body),
|
||||
.button = GetNpadColor(color_values.buttons),
|
||||
.body = GetNpadColor(controller.color_values[index].body),
|
||||
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||
};
|
||||
break;
|
||||
case RightIndex:
|
||||
controller.colors_state.right = {
|
||||
.body = GetNpadColor(color_values.body),
|
||||
.button = GetNpadColor(color_values.buttons),
|
||||
.body = GetNpadColor(controller.color_values[index].body),
|
||||
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||
};
|
||||
break;
|
||||
}
|
||||
@ -871,17 +1073,21 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback
|
||||
|
||||
void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index > DualIndex) {
|
||||
if (index >= controller.battery_values.size()) {
|
||||
return;
|
||||
}
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery); });
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto battery_values = TransformToBattery(callback);
|
||||
controller.battery_values[index] = TransformToBattery(callback);
|
||||
|
||||
if (is_configuring) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_charging = false;
|
||||
bool is_powered = false;
|
||||
NpadBatteryLevel battery_level = 0;
|
||||
switch (battery_values) {
|
||||
switch (controller.battery_values[index]) {
|
||||
case Common::Input::BatteryLevel::Charging:
|
||||
is_charging = true;
|
||||
is_powered = true;
|
||||
@ -933,33 +1139,46 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
|
||||
}
|
||||
|
||||
void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) {
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor); });
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto camera_values = TransformToCamera(callback);
|
||||
controller.camera_values = TransformToCamera(callback);
|
||||
|
||||
if (is_configuring) {
|
||||
return;
|
||||
}
|
||||
|
||||
controller.camera_state.sample++;
|
||||
controller.camera_state.format =
|
||||
static_cast<Core::IrSensor::ImageTransferProcessorFormat>(camera_values.format);
|
||||
controller.camera_state.data = camera_values.data;
|
||||
static_cast<Core::IrSensor::ImageTransferProcessorFormat>(controller.camera_values.format);
|
||||
controller.camera_state.data = controller.camera_values.data;
|
||||
}
|
||||
|
||||
void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) {
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController); });
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
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); });
|
||||
SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto nfc_values = TransformToNfc(callback);
|
||||
controller.nfc_values = TransformToNfc(callback);
|
||||
|
||||
if (is_configuring) {
|
||||
return;
|
||||
}
|
||||
|
||||
controller.nfc_state = {
|
||||
nfc_values.state,
|
||||
nfc_values.data,
|
||||
controller.nfc_values.state,
|
||||
controller.nfc_values.data,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1190,9 +1409,10 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
|
||||
npad_type);
|
||||
}
|
||||
|
||||
bool EmulatedController::IsControllerFullkey() const {
|
||||
bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
switch (npad_type) {
|
||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||
switch (type) {
|
||||
case NpadStyleIndex::ProController:
|
||||
case NpadStyleIndex::GameCube:
|
||||
case NpadStyleIndex::NES:
|
||||
@ -1205,9 +1425,10 @@ bool EmulatedController::IsControllerFullkey() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool EmulatedController::IsControllerSupported() const {
|
||||
bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
switch (npad_type) {
|
||||
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:
|
||||
@ -1235,15 +1456,20 @@ bool EmulatedController::IsControllerSupported() const {
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatedController::Connect() {
|
||||
if (!IsControllerSupported()) {
|
||||
LOG_ERROR(Service_HID, "Controller type {} is not supported", npad_type);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected); });
|
||||
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();
|
||||
@ -1254,8 +1480,12 @@ void EmulatedController::Connect() {
|
||||
|
||||
void EmulatedController::Disconnect() {
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected); });
|
||||
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();
|
||||
@ -1264,8 +1494,11 @@ void EmulatedController::Disconnect() {
|
||||
is_connected = false;
|
||||
}
|
||||
|
||||
bool EmulatedController::IsConnected() const {
|
||||
bool EmulatedController::IsConnected(bool get_temporary_value) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (get_temporary_value && is_configuring) {
|
||||
return tmp_is_connected;
|
||||
}
|
||||
return is_connected;
|
||||
}
|
||||
|
||||
@ -1275,14 +1508,27 @@ 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); });
|
||||
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;
|
||||
@ -1322,23 +1568,87 @@ 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;
|
||||
}
|
||||
|
||||
@ -1363,7 +1673,6 @@ const CameraState& EmulatedController::GetCamera() const {
|
||||
}
|
||||
|
||||
RingSensorForce EmulatedController::GetRingSensorForce() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.ring_analog_state;
|
||||
}
|
||||
|
||||
@ -1381,10 +1690,13 @@ NpadColor EmulatedController::GetNpadColor(u32 color) {
|
||||
};
|
||||
}
|
||||
|
||||
void EmulatedController::TriggerOnChange(ControllerTriggerType type) {
|
||||
void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
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,8 +126,16 @@ 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{};
|
||||
@ -159,6 +167,7 @@ enum class ControllerTriggerType {
|
||||
|
||||
struct ControllerUpdateCallback {
|
||||
std::function<void(ControllerTriggerType)> on_change;
|
||||
bool is_npad_service;
|
||||
};
|
||||
|
||||
class EmulatedController {
|
||||
@ -201,29 +210,43 @@ public:
|
||||
|
||||
/**
|
||||
* Sets the connected status to true
|
||||
* @param use_temporary_value If true tmp_npad_type will be used
|
||||
*/
|
||||
void Connect();
|
||||
void Connect(bool use_temporary_value = false);
|
||||
|
||||
/// Sets the connected status to false
|
||||
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() const;
|
||||
bool IsConnected(bool get_temporary_value = false) const;
|
||||
|
||||
/// Removes all callbacks created from input devices
|
||||
void UnloadInput();
|
||||
|
||||
/**
|
||||
* Sets the emulated controller into idle mode
|
||||
* Sets the emulated controller into configuring mode
|
||||
* This prevents the modification of the HID state of the emulated controller by input commands
|
||||
*/
|
||||
void DisableInput();
|
||||
void EnableConfiguration();
|
||||
|
||||
/// Returns the emulated controller into normal mode, allowing the modification of the HID state
|
||||
void EnableInput();
|
||||
void DisableConfiguration();
|
||||
|
||||
/// Enables Home and Screenshot buttons
|
||||
void EnableSystemButtons();
|
||||
|
||||
/// Disables Home and Screenshot buttons
|
||||
void DisableSystemButtons();
|
||||
|
||||
/// Sets Home and Screenshot buttons to false
|
||||
void ResetSystemButtons();
|
||||
|
||||
/// Returns true if the emulated controller is in configuring mode
|
||||
bool IsConfiguring() const;
|
||||
|
||||
/// Reload all input devices
|
||||
void ReloadInput();
|
||||
@ -231,9 +254,75 @@ 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;
|
||||
|
||||
@ -343,15 +432,17 @@ 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() const;
|
||||
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() const;
|
||||
bool IsControllerSupported(bool use_temporary_value = false) const;
|
||||
|
||||
/**
|
||||
* Updates the button status of the controller
|
||||
@ -426,8 +517,9 @@ 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);
|
||||
void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
|
||||
|
||||
NpadButton GetTurboButtonMask() const;
|
||||
|
||||
@ -436,10 +528,15 @@ private:
|
||||
NpadStyleIndex original_npad_type{NpadStyleIndex::None};
|
||||
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
||||
bool is_connected{false};
|
||||
bool npad_input_enabled{true};
|
||||
bool is_configuring{false};
|
||||
bool system_buttons_enabled{true};
|
||||
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
|
||||
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,7 +6,6 @@
|
||||
#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 {
|
||||
|
||||
@ -21,16 +20,6 @@ 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;
|
||||
@ -92,65 +81,6 @@ 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();
|
||||
}
|
||||
@ -177,16 +107,16 @@ const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t inde
|
||||
|
||||
void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) {
|
||||
supported_style_tag.raw = style_tag.raw;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
NpadStyleTag HIDCore::GetSupportedStyleTag() const {
|
||||
@ -225,57 +155,57 @@ NpadIdType HIDCore::GetFirstDisconnectedNpadId() const {
|
||||
}
|
||||
|
||||
void HIDCore::EnableAllControllerConfiguration() {
|
||||
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();
|
||||
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();
|
||||
}
|
||||
|
||||
void HIDCore::DisableAllControllerConfiguration() {
|
||||
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();
|
||||
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();
|
||||
}
|
||||
|
||||
void HIDCore::ReloadInputDevices() {
|
||||
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();
|
||||
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();
|
||||
console->ReloadFromSettings();
|
||||
devices->ReloadFromSettings();
|
||||
}
|
||||
|
||||
void HIDCore::UnloadInputDevices() {
|
||||
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();
|
||||
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();
|
||||
console->UnloadInput();
|
||||
devices->UnloadInput();
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ namespace Core::HID {
|
||||
class EmulatedConsole;
|
||||
class EmulatedController;
|
||||
class EmulatedDevices;
|
||||
class SystemController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Core::HID {
|
||||
@ -31,12 +30,6 @@ 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;
|
||||
|
||||
@ -83,16 +76,6 @@ 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};
|
||||
};
|
||||
|
||||
|
@ -1,860 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <common/scope_exit.h>
|
||||
|
||||
#include "common/polyfill_ranges.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/hid/system_controller.h"
|
||||
#include "core/hid/input_converter.h"
|
||||
|
||||
namespace Core::HID {
|
||||
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
|
||||
constexpr s32 HID_TRIGGER_MAX = 0x7fff;
|
||||
|
||||
SystemController::SystemController(NpadIdType npad_id_type_) : npad_id_type(npad_id_type_) {}
|
||||
|
||||
SystemController::~SystemController() = default;
|
||||
|
||||
NpadStyleIndex SystemController::MapSettingsTypeToNPad(Settings::ControllerType type) {
|
||||
switch (type) {
|
||||
case Settings::ControllerType::ProController:
|
||||
return NpadStyleIndex::ProController;
|
||||
case Settings::ControllerType::DualJoyconDetached:
|
||||
return NpadStyleIndex::JoyconDual;
|
||||
case Settings::ControllerType::LeftJoycon:
|
||||
return NpadStyleIndex::JoyconLeft;
|
||||
case Settings::ControllerType::RightJoycon:
|
||||
return NpadStyleIndex::JoyconRight;
|
||||
case Settings::ControllerType::Handheld:
|
||||
return NpadStyleIndex::Handheld;
|
||||
case Settings::ControllerType::GameCube:
|
||||
return NpadStyleIndex::GameCube;
|
||||
case Settings::ControllerType::Pokeball:
|
||||
return NpadStyleIndex::Pokeball;
|
||||
case Settings::ControllerType::NES:
|
||||
return NpadStyleIndex::NES;
|
||||
case Settings::ControllerType::SNES:
|
||||
return NpadStyleIndex::SNES;
|
||||
case Settings::ControllerType::N64:
|
||||
return NpadStyleIndex::N64;
|
||||
case Settings::ControllerType::SegaGenesis:
|
||||
return NpadStyleIndex::SegaGenesis;
|
||||
default:
|
||||
return NpadStyleIndex::ProController;
|
||||
}
|
||||
}
|
||||
|
||||
Settings::ControllerType SystemController::MapNPadToSettingsType(NpadStyleIndex type) {
|
||||
switch (type) {
|
||||
case NpadStyleIndex::ProController:
|
||||
return Settings::ControllerType::ProController;
|
||||
case NpadStyleIndex::JoyconDual:
|
||||
return Settings::ControllerType::DualJoyconDetached;
|
||||
case NpadStyleIndex::JoyconLeft:
|
||||
return Settings::ControllerType::LeftJoycon;
|
||||
case NpadStyleIndex::JoyconRight:
|
||||
return Settings::ControllerType::RightJoycon;
|
||||
case NpadStyleIndex::Handheld:
|
||||
return Settings::ControllerType::Handheld;
|
||||
case NpadStyleIndex::GameCube:
|
||||
return Settings::ControllerType::GameCube;
|
||||
case NpadStyleIndex::Pokeball:
|
||||
return Settings::ControllerType::Pokeball;
|
||||
case NpadStyleIndex::NES:
|
||||
return Settings::ControllerType::NES;
|
||||
case NpadStyleIndex::SNES:
|
||||
return Settings::ControllerType::SNES;
|
||||
case NpadStyleIndex::N64:
|
||||
return Settings::ControllerType::N64;
|
||||
case NpadStyleIndex::SegaGenesis:
|
||||
return Settings::ControllerType::SegaGenesis;
|
||||
default:
|
||||
return Settings::ControllerType::ProController;
|
||||
}
|
||||
}
|
||||
|
||||
void SystemController::ReloadFromSettings() {
|
||||
const auto player_index = NpadIdTypeToIndex(npad_id_type);
|
||||
const auto& player = Settings::values.players.GetValue()[player_index];
|
||||
|
||||
for (std::size_t index = 0; index < player.buttons.size(); ++index) {
|
||||
button_params[index] = Common::ParamPackage(player.buttons[index]);
|
||||
}
|
||||
for (std::size_t index = 0; index < player.analogs.size(); ++index) {
|
||||
stick_params[index] = Common::ParamPackage(player.analogs[index]);
|
||||
}
|
||||
for (std::size_t index = 0; index < player.motions.size(); ++index) {
|
||||
motion_params[index] = Common::ParamPackage(player.motions[index]);
|
||||
}
|
||||
|
||||
ring_params[0] = Common::ParamPackage(Settings::values.ringcon_analogs);
|
||||
|
||||
// Other or debug controller should always be a pro controller
|
||||
if (npad_id_type != NpadIdType::Other) {
|
||||
SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
|
||||
original_npad_type = npad_type;
|
||||
} else {
|
||||
SetNpadStyleIndex(NpadStyleIndex::ProController);
|
||||
original_npad_type = npad_type;
|
||||
}
|
||||
|
||||
Disconnect();
|
||||
if (player.connected) {
|
||||
Connect();
|
||||
}
|
||||
|
||||
ReloadInput();
|
||||
}
|
||||
|
||||
void SystemController::LoadDevices() {
|
||||
// TODO(german77): Use more buttons to detect the correct device
|
||||
const auto left_joycon = button_params[Settings::NativeButton::DRight];
|
||||
const auto right_joycon = button_params[Settings::NativeButton::A];
|
||||
|
||||
// Triggers for GC controllers
|
||||
trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL];
|
||||
trigger_params[RightIndex] = button_params[Settings::NativeButton::ZR];
|
||||
|
||||
std::ranges::transform(button_params, button_devices.begin(), Common::Input::CreateInputDevice);
|
||||
std::ranges::transform(stick_params, stick_devices.begin(), Common::Input::CreateInputDevice);
|
||||
std::ranges::transform(motion_params, motion_devices.begin(), Common::Input::CreateInputDevice);
|
||||
std::ranges::transform(trigger_params, trigger_devices.begin(),
|
||||
Common::Input::CreateInputDevice);
|
||||
}
|
||||
|
||||
void SystemController::ReloadInput() {
|
||||
// If you load any device here add the equivalent to the UnloadInput() function
|
||||
LoadDevices();
|
||||
for (std::size_t index = 0; index < button_devices.size(); ++index) {
|
||||
if (!button_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
const auto uuid = Common::UUID{button_params[index].Get("guid", "")};
|
||||
button_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index, uuid](const Common::Input::CallbackStatus& callback) {
|
||||
SetButton(callback, index, uuid);
|
||||
},
|
||||
});
|
||||
button_devices[index]->ForceUpdate();
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < stick_devices.size(); ++index) {
|
||||
if (!stick_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
const auto uuid = Common::UUID{stick_params[index].Get("guid", "")};
|
||||
stick_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index, uuid](const Common::Input::CallbackStatus& callback) {
|
||||
SetStick(callback, index, uuid);
|
||||
},
|
||||
});
|
||||
stick_devices[index]->ForceUpdate();
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < trigger_devices.size(); ++index) {
|
||||
if (!trigger_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
const auto uuid = Common::UUID{trigger_params[index].Get("guid", "")};
|
||||
trigger_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index, uuid](const Common::Input::CallbackStatus& callback) {
|
||||
SetTrigger(callback, index, uuid);
|
||||
},
|
||||
});
|
||||
trigger_devices[index]->ForceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void SystemController::UnloadInput() {
|
||||
for (auto& button : button_devices) {
|
||||
button.reset();
|
||||
}
|
||||
for (auto& stick : stick_devices) {
|
||||
stick.reset();
|
||||
}
|
||||
for (auto& motion : motion_devices) {
|
||||
motion.reset();
|
||||
}
|
||||
for (auto& trigger : trigger_devices) {
|
||||
trigger.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void SystemController::EnableConfiguration() {
|
||||
is_configuring = true;
|
||||
tmp_is_connected = is_connected;
|
||||
tmp_npad_type = npad_type;
|
||||
}
|
||||
|
||||
void SystemController::DisableConfiguration() {
|
||||
is_configuring = false;
|
||||
|
||||
// Apply temporary npad type to the real controller
|
||||
if (tmp_npad_type != npad_type) {
|
||||
if (is_connected) {
|
||||
Disconnect();
|
||||
}
|
||||
SetNpadStyleIndex(tmp_npad_type);
|
||||
original_npad_type = tmp_npad_type;
|
||||
}
|
||||
|
||||
// Apply temporary connected status to the real controller
|
||||
if (tmp_is_connected != is_connected) {
|
||||
if (tmp_is_connected) {
|
||||
Connect();
|
||||
return;
|
||||
}
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void SystemController::EnableSystemButtons() {
|
||||
std::scoped_lock lock{mutex};
|
||||
system_buttons_enabled = true;
|
||||
}
|
||||
|
||||
void SystemController::DisableSystemButtons() {
|
||||
std::scoped_lock lock{mutex};
|
||||
system_buttons_enabled = false;
|
||||
controller.home_button_state.raw = 0;
|
||||
controller.capture_button_state.raw = 0;
|
||||
}
|
||||
|
||||
void SystemController::ResetSystemButtons() {
|
||||
std::scoped_lock lock{mutex};
|
||||
controller.home_button_state.home.Assign(false);
|
||||
controller.capture_button_state.capture.Assign(false);
|
||||
}
|
||||
|
||||
bool SystemController::IsConfiguring() const {
|
||||
return is_configuring;
|
||||
}
|
||||
|
||||
void SystemController::SaveCurrentConfig() {
|
||||
const auto player_index = NpadIdTypeToIndex(npad_id_type);
|
||||
auto& player = Settings::values.players.GetValue()[player_index];
|
||||
player.connected = is_connected;
|
||||
player.controller_type = MapNPadToSettingsType(npad_type);
|
||||
for (std::size_t index = 0; index < player.buttons.size(); ++index) {
|
||||
player.buttons[index] = button_params[index].Serialize();
|
||||
}
|
||||
for (std::size_t index = 0; index < player.analogs.size(); ++index) {
|
||||
player.analogs[index] = stick_params[index].Serialize();
|
||||
}
|
||||
for (std::size_t index = 0; index < player.motions.size(); ++index) {
|
||||
player.motions[index] = motion_params[index].Serialize();
|
||||
}
|
||||
if (npad_id_type == NpadIdType::Player1) {
|
||||
Settings::values.ringcon_analogs = ring_params[0].Serialize();
|
||||
}
|
||||
}
|
||||
|
||||
void SystemController::RestoreConfig() {
|
||||
if (!is_configuring) {
|
||||
return;
|
||||
}
|
||||
ReloadFromSettings();
|
||||
}
|
||||
|
||||
std::vector<Common::ParamPackage> SystemController::GetMappedDevices() const {
|
||||
std::vector<Common::ParamPackage> devices;
|
||||
for (const auto& param : button_params) {
|
||||
if (!param.Has("engine")) {
|
||||
continue;
|
||||
}
|
||||
const auto devices_it = std::find_if(
|
||||
devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) {
|
||||
return param.Get("engine", "") == param_.Get("engine", "") &&
|
||||
param.Get("guid", "") == param_.Get("guid", "") &&
|
||||
param.Get("port", 0) == param_.Get("port", 0) &&
|
||||
param.Get("pad", 0) == param_.Get("pad", 0);
|
||||
});
|
||||
if (devices_it != devices.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& device = devices.emplace_back();
|
||||
device.Set("engine", param.Get("engine", ""));
|
||||
device.Set("guid", param.Get("guid", ""));
|
||||
device.Set("port", param.Get("port", 0));
|
||||
device.Set("pad", param.Get("pad", 0));
|
||||
}
|
||||
|
||||
for (const auto& param : stick_params) {
|
||||
if (!param.Has("engine")) {
|
||||
continue;
|
||||
}
|
||||
if (param.Get("engine", "") == "analog_from_button") {
|
||||
continue;
|
||||
}
|
||||
const auto devices_it = std::find_if(
|
||||
devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) {
|
||||
return param.Get("engine", "") == param_.Get("engine", "") &&
|
||||
param.Get("guid", "") == param_.Get("guid", "") &&
|
||||
param.Get("port", 0) == param_.Get("port", 0) &&
|
||||
param.Get("pad", 0) == param_.Get("pad", 0);
|
||||
});
|
||||
if (devices_it != devices.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& device = devices.emplace_back();
|
||||
device.Set("engine", param.Get("engine", ""));
|
||||
device.Set("guid", param.Get("guid", ""));
|
||||
device.Set("port", param.Get("port", 0));
|
||||
device.Set("pad", param.Get("pad", 0));
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
Common::ParamPackage SystemController::GetButtonParam(std::size_t index) const {
|
||||
if (index >= button_params.size()) {
|
||||
return {};
|
||||
}
|
||||
return button_params[index];
|
||||
}
|
||||
|
||||
Common::ParamPackage SystemController::GetStickParam(std::size_t index) const {
|
||||
if (index >= stick_params.size()) {
|
||||
return {};
|
||||
}
|
||||
return stick_params[index];
|
||||
}
|
||||
|
||||
Common::ParamPackage SystemController::GetMotionParam(std::size_t index) const {
|
||||
if (index >= motion_params.size()) {
|
||||
return {};
|
||||
}
|
||||
return motion_params[index];
|
||||
}
|
||||
|
||||
void SystemController::SetButtonParam(std::size_t index, Common::ParamPackage param) {
|
||||
if (index >= button_params.size()) {
|
||||
return;
|
||||
}
|
||||
button_params[index] = std::move(param);
|
||||
ReloadInput();
|
||||
}
|
||||
|
||||
void SystemController::SetStickParam(std::size_t index, Common::ParamPackage param) {
|
||||
if (index >= stick_params.size()) {
|
||||
return;
|
||||
}
|
||||
stick_params[index] = std::move(param);
|
||||
ReloadInput();
|
||||
}
|
||||
|
||||
void SystemController::SetMotionParam(std::size_t index, Common::ParamPackage param) {
|
||||
if (index >= motion_params.size()) {
|
||||
return;
|
||||
}
|
||||
motion_params[index] = std::move(param);
|
||||
ReloadInput();
|
||||
}
|
||||
|
||||
void SystemController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
Common::UUID uuid) {
|
||||
if (index >= controller.button_values.size()) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock lock{mutex};
|
||||
bool value_changed = false;
|
||||
const auto new_status = TransformToButton(callback);
|
||||
auto& current_status = controller.button_values[index];
|
||||
|
||||
// Only read button values that have the same uuid or are pressed once
|
||||
if (current_status.uuid != uuid) {
|
||||
if (!new_status.value) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
current_status.toggle = new_status.toggle;
|
||||
current_status.turbo = new_status.turbo;
|
||||
current_status.uuid = uuid;
|
||||
|
||||
// Update button status with current
|
||||
if (!current_status.toggle) {
|
||||
current_status.locked = false;
|
||||
if (current_status.value != new_status.value) {
|
||||
current_status.value = new_status.value;
|
||||
value_changed = true;
|
||||
}
|
||||
} else {
|
||||
// Toggle button and lock status
|
||||
if (new_status.value && !current_status.locked) {
|
||||
current_status.locked = true;
|
||||
current_status.value = !current_status.value;
|
||||
value_changed = true;
|
||||
}
|
||||
|
||||
// Unlock button ready for next press
|
||||
if (!new_status.value && current_status.locked) {
|
||||
current_status.locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!value_changed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_configuring) {
|
||||
controller.npad_button_state.raw = NpadButton::None;
|
||||
controller.home_button_state.raw = 0;
|
||||
controller.capture_button_state.raw = 0;
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Button, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// GC controllers have triggers not buttons
|
||||
if (npad_type == NpadStyleIndex::GameCube) {
|
||||
if (index == Settings::NativeButton::ZR) {
|
||||
return;
|
||||
}
|
||||
if (index == Settings::NativeButton::ZL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (index) {
|
||||
case Settings::NativeButton::A:
|
||||
controller.npad_button_state.a.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::B:
|
||||
controller.npad_button_state.b.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::X:
|
||||
controller.npad_button_state.x.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Y:
|
||||
controller.npad_button_state.y.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::LStick:
|
||||
controller.npad_button_state.stick_l.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::RStick:
|
||||
controller.npad_button_state.stick_r.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::L:
|
||||
controller.npad_button_state.l.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::R:
|
||||
controller.npad_button_state.r.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::ZL:
|
||||
controller.npad_button_state.zl.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::ZR:
|
||||
controller.npad_button_state.zr.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Plus:
|
||||
controller.npad_button_state.plus.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Minus:
|
||||
controller.npad_button_state.minus.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::DLeft:
|
||||
controller.npad_button_state.left.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::DUp:
|
||||
controller.npad_button_state.up.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::DRight:
|
||||
controller.npad_button_state.right.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::DDown:
|
||||
controller.npad_button_state.down.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::SL:
|
||||
controller.npad_button_state.left_sl.Assign(current_status.value);
|
||||
controller.npad_button_state.right_sl.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::SR:
|
||||
controller.npad_button_state.left_sr.Assign(current_status.value);
|
||||
controller.npad_button_state.right_sr.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Home:
|
||||
if (!system_buttons_enabled) {
|
||||
break;
|
||||
}
|
||||
controller.home_button_state.home.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Screenshot:
|
||||
if (!system_buttons_enabled) {
|
||||
break;
|
||||
}
|
||||
controller.capture_button_state.capture.Assign(current_status.value);
|
||||
break;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
||||
if (!is_connected) {
|
||||
if (npad_id_type == NpadIdType::Player1 && npad_type != NpadStyleIndex::Handheld) {
|
||||
Connect();
|
||||
}
|
||||
if (npad_id_type == NpadIdType::Handheld && npad_type == NpadStyleIndex::Handheld) {
|
||||
Connect();
|
||||
}
|
||||
}
|
||||
TriggerOnChange(ControllerTriggerType::Button, true);
|
||||
}
|
||||
|
||||
void SystemController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
Common::UUID uuid) {
|
||||
if (index >= controller.stick_values.size()) {
|
||||
return;
|
||||
}
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto stick_value = TransformToStick(callback);
|
||||
|
||||
// Only read stick values that have the same uuid or are over the threshold to avoid flapping
|
||||
if (controller.stick_values[index].uuid != uuid) {
|
||||
if (!stick_value.down && !stick_value.up && !stick_value.left &&
|
||||
!stick_value.right) {
|
||||
trigger_guard.Cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
controller.stick_values[index] = stick_value;
|
||||
controller.stick_values[index].uuid = uuid;
|
||||
|
||||
if (is_configuring) {
|
||||
controller.analog_stick_state.left = {};
|
||||
controller.analog_stick_state.right = {};
|
||||
return;
|
||||
}
|
||||
|
||||
const AnalogStickState stick{
|
||||
.x = static_cast<s32>(controller.stick_values[index].x.value * HID_JOYSTICK_MAX),
|
||||
.y = static_cast<s32>(controller.stick_values[index].y.value * HID_JOYSTICK_MAX),
|
||||
};
|
||||
|
||||
switch (index) {
|
||||
case Settings::NativeAnalog::LStick:
|
||||
controller.analog_stick_state.left = stick;
|
||||
controller.npad_button_state.stick_l_left.Assign(controller.stick_values[index].left);
|
||||
controller.npad_button_state.stick_l_up.Assign(controller.stick_values[index].up);
|
||||
controller.npad_button_state.stick_l_right.Assign(controller.stick_values[index].right);
|
||||
controller.npad_button_state.stick_l_down.Assign(controller.stick_values[index].down);
|
||||
break;
|
||||
case Settings::NativeAnalog::RStick:
|
||||
controller.analog_stick_state.right = stick;
|
||||
controller.npad_button_state.stick_r_left.Assign(controller.stick_values[index].left);
|
||||
controller.npad_button_state.stick_r_up.Assign(controller.stick_values[index].up);
|
||||
controller.npad_button_state.stick_r_right.Assign(controller.stick_values[index].right);
|
||||
controller.npad_button_state.stick_r_down.Assign(controller.stick_values[index].down);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SystemController::SetTrigger(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index, Common::UUID uuid) {
|
||||
if (index >= controller.trigger_values.size()) {
|
||||
return;
|
||||
}
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto trigger_value = TransformToTrigger(callback);
|
||||
|
||||
// Only read trigger values that have the same uuid or are pressed once
|
||||
if (controller.trigger_values[index].uuid != uuid) {
|
||||
if (!trigger_value.pressed.value) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
controller.trigger_values[index] = trigger_value;
|
||||
controller.trigger_values[index].uuid = uuid;
|
||||
|
||||
if (is_configuring) {
|
||||
controller.gc_trigger_state.left = 0;
|
||||
controller.gc_trigger_state.right = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Only GC controllers have analog triggers
|
||||
if (npad_type != NpadStyleIndex::GameCube) {
|
||||
trigger_guard.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& trigger = controller.trigger_values[index];
|
||||
|
||||
switch (index) {
|
||||
case Settings::NativeTrigger::LTrigger:
|
||||
controller.gc_trigger_state.left = static_cast<s32>(trigger.analog.value * HID_TRIGGER_MAX);
|
||||
controller.npad_button_state.zl.Assign(trigger.pressed.value);
|
||||
break;
|
||||
case Settings::NativeTrigger::RTrigger:
|
||||
controller.gc_trigger_state.right =
|
||||
static_cast<s32>(trigger.analog.value * HID_TRIGGER_MAX);
|
||||
controller.npad_button_state.zr.Assign(trigger.pressed.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SystemController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) {
|
||||
supported_style_tag = supported_styles;
|
||||
if (!is_connected) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to reconnect with the original type
|
||||
if (npad_type != original_npad_type) {
|
||||
Disconnect();
|
||||
const auto current_npad_type = npad_type;
|
||||
SetNpadStyleIndex(original_npad_type);
|
||||
if (IsControllerSupported()) {
|
||||
Connect();
|
||||
return;
|
||||
}
|
||||
SetNpadStyleIndex(current_npad_type);
|
||||
Connect();
|
||||
}
|
||||
|
||||
if (IsControllerSupported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Disconnect();
|
||||
|
||||
// Fallback Fullkey controllers to Pro controllers
|
||||
if (IsControllerFullkey() && supported_style_tag.fullkey) {
|
||||
LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
|
||||
SetNpadStyleIndex(NpadStyleIndex::ProController);
|
||||
Connect();
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback Dual joycon controllers to Pro controllers
|
||||
if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) {
|
||||
LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
|
||||
SetNpadStyleIndex(NpadStyleIndex::ProController);
|
||||
Connect();
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback Pro controllers to Dual joycon
|
||||
if (npad_type == NpadStyleIndex::ProController && supported_style_tag.joycon_dual) {
|
||||
LOG_WARNING(Service_HID, "Reconnecting controller type {} as Dual Joycons", npad_type);
|
||||
SetNpadStyleIndex(NpadStyleIndex::JoyconDual);
|
||||
Connect();
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller",
|
||||
npad_type);
|
||||
}
|
||||
|
||||
bool SystemController::IsControllerFullkey(bool use_temporary_value) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||
switch (type) {
|
||||
case NpadStyleIndex::ProController:
|
||||
case NpadStyleIndex::GameCube:
|
||||
case NpadStyleIndex::NES:
|
||||
case NpadStyleIndex::SNES:
|
||||
case NpadStyleIndex::N64:
|
||||
case NpadStyleIndex::SegaGenesis:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SystemController::IsControllerSupported(bool use_temporary_value) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||
switch (type) {
|
||||
case NpadStyleIndex::ProController:
|
||||
return supported_style_tag.fullkey.As<bool>();
|
||||
case NpadStyleIndex::Handheld:
|
||||
return supported_style_tag.handheld.As<bool>();
|
||||
case NpadStyleIndex::JoyconDual:
|
||||
return supported_style_tag.joycon_dual.As<bool>();
|
||||
case NpadStyleIndex::JoyconLeft:
|
||||
return supported_style_tag.joycon_left.As<bool>();
|
||||
case NpadStyleIndex::JoyconRight:
|
||||
return supported_style_tag.joycon_right.As<bool>();
|
||||
case NpadStyleIndex::GameCube:
|
||||
return supported_style_tag.gamecube.As<bool>();
|
||||
case NpadStyleIndex::Pokeball:
|
||||
return supported_style_tag.palma.As<bool>();
|
||||
case NpadStyleIndex::NES:
|
||||
return supported_style_tag.lark.As<bool>();
|
||||
case NpadStyleIndex::SNES:
|
||||
return supported_style_tag.lucia.As<bool>();
|
||||
case NpadStyleIndex::N64:
|
||||
return supported_style_tag.lagoon.As<bool>();
|
||||
case NpadStyleIndex::SegaGenesis:
|
||||
return supported_style_tag.lager.As<bool>();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void SystemController::Connect(bool use_temporary_value) {
|
||||
if (!IsControllerSupported(use_temporary_value)) {
|
||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||
LOG_ERROR(Service_HID, "Controller type {} is not supported", type);
|
||||
return;
|
||||
}
|
||||
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
tmp_is_connected = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_connected) {
|
||||
trigger_guard.Cancel();
|
||||
return;
|
||||
}
|
||||
is_connected = true;
|
||||
}
|
||||
|
||||
void SystemController::Disconnect() {
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
if (is_configuring) {
|
||||
tmp_is_connected = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_connected) {
|
||||
trigger_guard.Cancel();
|
||||
return;
|
||||
}
|
||||
is_connected = false;
|
||||
}
|
||||
|
||||
bool SystemController::IsConnected(bool get_temporary_value) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (get_temporary_value && is_configuring) {
|
||||
return tmp_is_connected;
|
||||
}
|
||||
return is_connected;
|
||||
}
|
||||
|
||||
NpadIdType SystemController::GetNpadIdType() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return npad_id_type;
|
||||
}
|
||||
|
||||
NpadStyleIndex SystemController::GetNpadStyleIndex(bool get_temporary_value) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
if (get_temporary_value && is_configuring) {
|
||||
return tmp_npad_type;
|
||||
}
|
||||
return npad_type;
|
||||
}
|
||||
|
||||
void SystemController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
|
||||
auto trigger_guard =
|
||||
SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); });
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
if (is_configuring) {
|
||||
if (tmp_npad_type == npad_type_) {
|
||||
trigger_guard.Cancel();
|
||||
return;
|
||||
}
|
||||
tmp_npad_type = npad_type_;
|
||||
return;
|
||||
}
|
||||
|
||||
if (npad_type == npad_type_) {
|
||||
trigger_guard.Cancel();
|
||||
return;
|
||||
}
|
||||
if (is_connected) {
|
||||
LOG_WARNING(Service_HID, "Controller {} type changed while it's connected",
|
||||
NpadIdTypeToIndex(npad_id_type));
|
||||
}
|
||||
npad_type = npad_type_;
|
||||
}
|
||||
|
||||
ButtonValues SystemController::GetButtonsValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.button_values;
|
||||
}
|
||||
|
||||
SticksValues SystemController::GetSticksValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.stick_values;
|
||||
}
|
||||
|
||||
TriggerValues SystemController::GetTriggersValues() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.trigger_values;
|
||||
}
|
||||
|
||||
HomeButtonState SystemController::GetHomeButtons() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.home_button_state;
|
||||
}
|
||||
|
||||
CaptureButtonState SystemController::GetCaptureButtons() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.capture_button_state;
|
||||
}
|
||||
|
||||
NpadButtonState SystemController::GetNpadButtons() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.npad_button_state;
|
||||
}
|
||||
|
||||
AnalogSticks SystemController::GetSticks() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.analog_stick_state;
|
||||
}
|
||||
|
||||
NpadGcTriggerState SystemController::GetTriggers() const {
|
||||
std::scoped_lock lock{mutex};
|
||||
return controller.gc_trigger_state;
|
||||
}
|
||||
|
||||
void SystemController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
for (const auto& poller_pair : callback_list) {
|
||||
const ControllerUpdateCallback& poller = poller_pair.second;
|
||||
if (!is_npad_service_update && poller.is_npad_service) {
|
||||
continue;
|
||||
}
|
||||
if (poller.on_change) {
|
||||
poller.on_change(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SystemController::SetCallback(ControllerUpdateCallback update_callback) {
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
|
||||
return last_callback_key++;
|
||||
}
|
||||
|
||||
void SystemController::DeleteCallback(int key) {
|
||||
std::scoped_lock lock{callback_mutex};
|
||||
const auto& iterator = callback_list.find(key);
|
||||
if (iterator == callback_list.end()) {
|
||||
LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
|
||||
return;
|
||||
}
|
||||
callback_list.erase(iterator);
|
||||
}
|
||||
|
||||
} // namespace Core::HID
|
@ -1,330 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/input.h"
|
||||
#include "common/param_package.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/vector_math.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hid/motion_input.h"
|
||||
|
||||
namespace Core::HID {
|
||||
const std::size_t max_emulated_controllers = 2;
|
||||
const std::size_t output_devices_size = 4;
|
||||
struct ControllerMotionInfo {
|
||||
Common::Input::MotionStatus raw_status{};
|
||||
MotionInput emulated{};
|
||||
};
|
||||
|
||||
using ButtonDevices =
|
||||
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeButton::NumButtons>;
|
||||
using StickDevices =
|
||||
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeAnalog::NumAnalogs>;
|
||||
using ControllerMotionDevices =
|
||||
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMotion::NumMotions>;
|
||||
using TriggerDevices =
|
||||
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>;
|
||||
|
||||
using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
|
||||
using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
|
||||
using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>;
|
||||
using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>;
|
||||
using RingAnalogParams = std::array<Common::ParamPackage, max_emulated_controllers>;
|
||||
|
||||
using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>;
|
||||
using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>;
|
||||
using TriggerValues =
|
||||
std::array<Common::Input::TriggerStatus, Settings::NativeTrigger::NumTriggers>;
|
||||
|
||||
struct AnalogSticks {
|
||||
AnalogStickState left{};
|
||||
AnalogStickState right{};
|
||||
};
|
||||
|
||||
|
||||
enum EmulatedDeviceIndex : u8 {
|
||||
LeftIndex,
|
||||
RightIndex,
|
||||
DualIndex,
|
||||
AllDevices,
|
||||
};
|
||||
|
||||
struct ControllerStatus {
|
||||
// Data from input_common
|
||||
ButtonValues button_values{};
|
||||
SticksValues stick_values{};
|
||||
TriggerValues trigger_values{};
|
||||
|
||||
// Data for HID services
|
||||
HomeButtonState home_button_state{};
|
||||
CaptureButtonState capture_button_state{};
|
||||
NpadButtonState npad_button_state{};
|
||||
AnalogSticks analog_stick_state{};
|
||||
NpadGcTriggerState gc_trigger_state{};
|
||||
};
|
||||
|
||||
enum class ControllerTriggerType {
|
||||
Button,
|
||||
Stick,
|
||||
Trigger,
|
||||
Connected,
|
||||
Disconnected,
|
||||
Type,
|
||||
All,
|
||||
};
|
||||
|
||||
struct ControllerUpdateCallback {
|
||||
std::function<void(ControllerTriggerType)> on_change;
|
||||
bool is_npad_service;
|
||||
};
|
||||
|
||||
class SystemController {
|
||||
public:
|
||||
/**
|
||||
* Contains all input data (buttons, joysticks, vibration, and motion) within this controller.
|
||||
* @param npad_id_type npad id type for this specific controller
|
||||
*/
|
||||
explicit SystemController(NpadIdType npad_id_type_);
|
||||
~SystemController();
|
||||
|
||||
YUZU_NON_COPYABLE(SystemController);
|
||||
YUZU_NON_MOVEABLE(SystemController);
|
||||
|
||||
/// Converts the controller type from settings to npad type
|
||||
static NpadStyleIndex MapSettingsTypeToNPad(Settings::ControllerType type);
|
||||
|
||||
/// Converts npad type to the equivalent of controller type from settings
|
||||
static Settings::ControllerType MapNPadToSettingsType(NpadStyleIndex type);
|
||||
|
||||
/// Gets the NpadIdType for this controller
|
||||
NpadIdType GetNpadIdType() const;
|
||||
|
||||
/// Sets the NpadStyleIndex for this controller
|
||||
void SetNpadStyleIndex(NpadStyleIndex npad_type_);
|
||||
|
||||
/**
|
||||
* Gets the NpadStyleIndex for this controller
|
||||
* @param get_temporary_value If true tmp_npad_type will be returned
|
||||
* @return NpadStyleIndex set on the controller
|
||||
*/
|
||||
NpadStyleIndex GetNpadStyleIndex(bool get_temporary_value = false) const;
|
||||
|
||||
/**
|
||||
* Sets the supported controller types. Disconnects the controller if current type is not
|
||||
* supported
|
||||
* @param supported_styles bitflag with supported types
|
||||
*/
|
||||
void SetSupportedNpadStyleTag(NpadStyleTag supported_styles);
|
||||
|
||||
/**
|
||||
* Sets the connected status to true
|
||||
* @param use_temporary_value If true tmp_npad_type will be used
|
||||
*/
|
||||
void Connect(bool use_temporary_value = false);
|
||||
|
||||
/// Sets the connected status to false
|
||||
void Disconnect();
|
||||
|
||||
/**
|
||||
* Is the emulated connected
|
||||
* @param get_temporary_value If true tmp_is_connected will be returned
|
||||
* @return true if the controller has the connected status
|
||||
*/
|
||||
bool IsConnected(bool get_temporary_value = false) const;
|
||||
|
||||
/// Removes all callbacks created from input devices
|
||||
void UnloadInput();
|
||||
|
||||
/**
|
||||
* Sets the emulated controller into configuring mode
|
||||
* This prevents the modification of the HID state of the emulated controller by input commands
|
||||
*/
|
||||
void EnableConfiguration();
|
||||
|
||||
/// Returns the emulated controller into normal mode, allowing the modification of the HID state
|
||||
void DisableConfiguration();
|
||||
|
||||
/// Enables Home and Screenshot buttons
|
||||
void EnableSystemButtons();
|
||||
|
||||
/// Disables Home and Screenshot buttons
|
||||
void DisableSystemButtons();
|
||||
|
||||
/// Sets Home and Screenshot buttons to false
|
||||
void ResetSystemButtons();
|
||||
|
||||
/// Returns true if the emulated controller is in configuring mode
|
||||
bool IsConfiguring() const;
|
||||
|
||||
/// Reload all input devices
|
||||
void ReloadInput();
|
||||
|
||||
/// Overrides current mapped devices with the stored configuration and reloads all input devices
|
||||
void ReloadFromSettings();
|
||||
|
||||
/// Saves the current mapped configuration
|
||||
void SaveCurrentConfig();
|
||||
|
||||
/// Reverts any mapped changes made that weren't saved
|
||||
void RestoreConfig();
|
||||
|
||||
/// Returns a vector of mapped devices from the mapped button and stick parameters
|
||||
std::vector<Common::ParamPackage> GetMappedDevices() const;
|
||||
|
||||
// Returns the current mapped button device
|
||||
Common::ParamPackage GetButtonParam(std::size_t index) const;
|
||||
|
||||
// Returns the current mapped stick device
|
||||
Common::ParamPackage GetStickParam(std::size_t index) const;
|
||||
|
||||
// Returns the current mapped motion device
|
||||
Common::ParamPackage GetMotionParam(std::size_t index) const;
|
||||
|
||||
/**
|
||||
* Updates the current mapped button device
|
||||
* @param param ParamPackage with controller data to be mapped
|
||||
*/
|
||||
void SetButtonParam(std::size_t index, Common::ParamPackage param);
|
||||
|
||||
/**
|
||||
* Updates the current mapped stick device
|
||||
* @param param ParamPackage with controller data to be mapped
|
||||
*/
|
||||
void SetStickParam(std::size_t index, Common::ParamPackage param);
|
||||
|
||||
/**
|
||||
* Updates the current mapped motion device
|
||||
* @param param ParamPackage with controller data to be mapped
|
||||
*/
|
||||
void SetMotionParam(std::size_t index, Common::ParamPackage param);
|
||||
|
||||
/// Returns the latest button status from the controller with parameters
|
||||
ButtonValues GetButtonsValues() const;
|
||||
|
||||
/// Returns the latest analog stick status from the controller with parameters
|
||||
SticksValues GetSticksValues() const;
|
||||
|
||||
/// Returns the latest trigger status from the controller with parameters
|
||||
TriggerValues GetTriggersValues() const;
|
||||
|
||||
/// Returns the latest status of button input for the hid::HomeButton service
|
||||
HomeButtonState GetHomeButtons() const;
|
||||
|
||||
/// Returns the latest status of button input for the hid::CaptureButton service
|
||||
CaptureButtonState GetCaptureButtons() const;
|
||||
|
||||
/// Returns the latest status of button input for the hid::Npad service
|
||||
NpadButtonState GetNpadButtons() const;
|
||||
|
||||
/// Returns the latest status of stick input from the mouse
|
||||
AnalogSticks GetSticks() const;
|
||||
|
||||
/// Returns the latest status of trigger input from the mouse
|
||||
NpadGcTriggerState GetTriggers() const;
|
||||
|
||||
/**
|
||||
* Adds a callback to the list of events
|
||||
* @param update_callback A ConsoleUpdateCallback that will be triggered
|
||||
* @return an unique key corresponding to the callback index in the list
|
||||
*/
|
||||
int SetCallback(ControllerUpdateCallback update_callback);
|
||||
|
||||
/**
|
||||
* Removes a callback from the list stopping any future events to this object
|
||||
* @param key Key corresponding to the callback index in the list
|
||||
*/
|
||||
void DeleteCallback(int key);
|
||||
|
||||
private:
|
||||
/// creates input devices from params
|
||||
void LoadDevices();
|
||||
|
||||
/**
|
||||
* @param use_temporary_value If true tmp_npad_type will be used
|
||||
* @return true if the controller style is fullkey
|
||||
*/
|
||||
bool IsControllerFullkey(bool use_temporary_value = false) const;
|
||||
|
||||
/**
|
||||
* Checks the current controller type against the supported_style_tag
|
||||
* @param use_temporary_value If true tmp_npad_type will be used
|
||||
* @return true if the controller is supported
|
||||
*/
|
||||
bool IsControllerSupported(bool use_temporary_value = false) const;
|
||||
|
||||
/**
|
||||
* Updates the button status of the controller
|
||||
* @param callback A CallbackStatus containing the button status
|
||||
* @param index Button ID of the to be updated
|
||||
*/
|
||||
void SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
Common::UUID uuid);
|
||||
|
||||
/**
|
||||
* Updates the analog stick status of the controller
|
||||
* @param callback A CallbackStatus containing the analog stick status
|
||||
* @param index stick ID of the to be updated
|
||||
*/
|
||||
void SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
Common::UUID uuid);
|
||||
|
||||
/**
|
||||
* Updates the trigger status of the controller
|
||||
* @param callback A CallbackStatus containing the trigger status
|
||||
* @param index trigger ID of the to be updated
|
||||
*/
|
||||
void SetTrigger(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
Common::UUID uuid);
|
||||
|
||||
/**
|
||||
* Triggers a callback that something has changed on the controller status
|
||||
* @param type Input type of the event to trigger
|
||||
* @param is_service_update indicates if this event should only be sent to HID services
|
||||
*/
|
||||
void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
|
||||
|
||||
const NpadIdType npad_id_type;
|
||||
NpadStyleIndex npad_type{NpadStyleIndex::None};
|
||||
NpadStyleIndex original_npad_type{NpadStyleIndex::None};
|
||||
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
||||
bool is_connected{false};
|
||||
bool is_configuring{false};
|
||||
bool system_buttons_enabled{true};
|
||||
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
|
||||
|
||||
// Temporary values to avoid doing changes while the controller is in configuring mode
|
||||
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
|
||||
bool tmp_is_connected{false};
|
||||
|
||||
ButtonParams button_params;
|
||||
StickParams stick_params;
|
||||
TriggerParams trigger_params;
|
||||
ControllerMotionParams motion_params;
|
||||
RingAnalogParams ring_params;
|
||||
|
||||
ButtonDevices button_devices;
|
||||
StickDevices stick_devices;
|
||||
ControllerMotionDevices motion_devices;
|
||||
TriggerDevices trigger_devices;
|
||||
|
||||
mutable std::mutex mutex;
|
||||
mutable std::mutex callback_mutex;
|
||||
std::unordered_map<int, ControllerUpdateCallback> callback_list;
|
||||
int last_callback_key = 0;
|
||||
|
||||
// Stores the current status of all controller input
|
||||
ControllerStatus controller;
|
||||
};
|
||||
|
||||
} // namespace Core::HID
|
@ -24,6 +24,7 @@ ClusteringProcessor::ClusteringProcessor(Core::HID::HIDCore& hid_core_,
|
||||
|
||||
Core::HID::ControllerUpdateCallback engine_callback{
|
||||
.on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); },
|
||||
.is_npad_service = true,
|
||||
};
|
||||
callback_key = npad_device->SetCallback(engine_callback);
|
||||
}
|
||||
|
@ -199,6 +199,14 @@ add_executable(yuzu
|
||||
util/clickable_label.h
|
||||
util/controller_navigation.cpp
|
||||
util/controller_navigation.h
|
||||
util/controller_viewer/common_shapes.cpp
|
||||
util/controller_viewer/common_shapes.h
|
||||
util/controller_viewer/controller_base.cpp
|
||||
util/controller_viewer/controller_base.h
|
||||
util/controller_viewer/controller_viewer.cpp
|
||||
util/controller_viewer/controller_viewer.h
|
||||
util/controller_viewer/pro_controller.cpp
|
||||
util/controller_viewer/pro_controller.h
|
||||
util/limitable_input_dialog.cpp
|
||||
util/limitable_input_dialog.h
|
||||
util/overlay_dialog.cpp
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <QStandardItemModel>
|
||||
#include <QTimer>
|
||||
|
||||
#include "core/hid/system_controller.h"
|
||||
#include "core/hid/emulated_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.GetSystemController(Core::HID::NpadIdType::Player1);
|
||||
controller = hid_core.GetEmulatedController(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 SystemController;
|
||||
class EmulatedController;
|
||||
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::SystemController* controller;
|
||||
Core::HID::EmulatedController* 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/system_controller.h"
|
||||
#include "core/hid/emulated_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* 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;
|
||||
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;
|
||||
} else {
|
||||
system_controller = system_controller_p1;
|
||||
emulated_controller = emulated_controller_p1;
|
||||
}
|
||||
} else {
|
||||
system_controller = hid_core.GetSystemControllerByIndex(player_index);
|
||||
system_controller->SaveCurrentConfig();
|
||||
system_controller->EnableConfiguration();
|
||||
emulated_controller = hid_core.GetEmulatedControllerByIndex(player_index);
|
||||
emulated_controller->SaveCurrentConfig();
|
||||
emulated_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(system_controller->GetNpadIdType());
|
||||
ui->controllerFrame->SetController(emulated_controller);
|
||||
|
||||
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) {
|
||||
system_controller->SetButtonParam(button_id, params);
|
||||
emulated_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 = system_controller->GetButtonParam(button_id);
|
||||
Common::ParamPackage param = emulated_controller->GetButtonParam(button_id);
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
system_controller->SetButtonParam(button_id, {});
|
||||
emulated_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));
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
emulated_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));
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
emulated_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));
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
emulated_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));
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
emulated_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));
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
emulated_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);
|
||||
}
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
emulated_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));
|
||||
system_controller->SetButtonParam(button_id, param);
|
||||
emulated_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) {
|
||||
system_controller->SetMotionParam(motion_id, params);
|
||||
emulated_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 = system_controller->GetMotionParam(motion_id);
|
||||
Common::ParamPackage param = emulated_controller->GetMotionParam(motion_id);
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
system_controller->SetMotionParam(motion_id, {});
|
||||
emulated_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);
|
||||
system_controller->SetMotionParam(motion_id, param);
|
||||
emulated_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 =
|
||||
system_controller->GetButtonParam(Settings::NativeButton::ZL);
|
||||
emulated_controller->GetButtonParam(Settings::NativeButton::ZL);
|
||||
if (param.Has("threshold")) {
|
||||
const auto slider_value = ui->sliderZLThreshold->value();
|
||||
param.Set("threshold", slider_value / 100.0f);
|
||||
system_controller->SetButtonParam(Settings::NativeButton::ZL, param);
|
||||
emulated_controller->SetButtonParam(Settings::NativeButton::ZL, param);
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->sliderZRThreshold, &QSlider::valueChanged, [=, this] {
|
||||
Common::ParamPackage param =
|
||||
system_controller->GetButtonParam(Settings::NativeButton::ZR);
|
||||
emulated_controller->GetButtonParam(Settings::NativeButton::ZR);
|
||||
if (param.Has("threshold")) {
|
||||
const auto slider_value = ui->sliderZRThreshold->value();
|
||||
param.Set("threshold", slider_value / 100.0f);
|
||||
system_controller->SetButtonParam(Settings::NativeButton::ZR, param);
|
||||
emulated_controller->SetButtonParam(Settings::NativeButton::ZR, param);
|
||||
}
|
||||
});
|
||||
|
||||
@ -531,7 +531,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||
HandleClick(
|
||||
analog_map_buttons[analog_id][sub_button_id], analog_id,
|
||||
[=, this](const Common::ParamPackage& params) {
|
||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
SetAnalogParam(params, param, analog_sub_buttons[sub_button_id]);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
emulated_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 = system_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
if (param.Get("engine", "") != "analog_from_button") {
|
||||
system_controller->SetStickParam(analog_id, {});
|
||||
emulated_controller->SetStickParam(analog_id, {});
|
||||
for (auto button : analog_map_buttons[analog_id]) {
|
||||
button->setText(tr("[not set]"));
|
||||
}
|
||||
@ -585,12 +585,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||
param.Erase("right");
|
||||
break;
|
||||
}
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
|
||||
});
|
||||
context_menu.addAction(tr("Center axis"), [&] {
|
||||
const auto stick_value =
|
||||
system_controller->GetSticksValues()[analog_id];
|
||||
emulated_controller->GetSticksValues()[analog_id];
|
||||
const float offset_x = stick_value.x.properties.offset;
|
||||
const float offset_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);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
emulated_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);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
emulated_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);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
emulated_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 = system_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
param.Set("modifier", params.Serialize());
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
emulated_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 = system_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
param.Set("modifier", "");
|
||||
analog_map_modifier_button[analog_id]->setText(tr("[not set]"));
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
});
|
||||
context_menu.addAction(tr("Toggle button"), [&] {
|
||||
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));
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
emulated_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));
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
emulated_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 = system_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
const auto spinbox_value = analog_map_range_spinbox[analog_id]->value();
|
||||
param.Set("range", spinbox_value / 100.0f);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
});
|
||||
|
||||
connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] {
|
||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
const auto slider_value = analog_map_deadzone_slider[analog_id]->value();
|
||||
analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value));
|
||||
param.Set("deadzone", slider_value / 100.0f);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
});
|
||||
|
||||
connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] {
|
||||
Common::ParamPackage param = system_controller->GetStickParam(analog_id);
|
||||
Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
const auto slider_value = analog_map_modifier_slider[analog_id]->value();
|
||||
analog_map_modifier_label[analog_id]->setText(
|
||||
tr("Modifier Range: %1%").arg(slider_value));
|
||||
param.Set("modifier_scale", slider_value / 100.0f);
|
||||
system_controller->SetStickParam(analog_id, param);
|
||||
emulated_controller->SetStickParam(analog_id, param);
|
||||
});
|
||||
}
|
||||
|
||||
@ -749,28 +749,28 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||
GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
|
||||
|
||||
if (player_index == 0) {
|
||||
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);
|
||||
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);
|
||||
|
||||
system_controller_p1->SetNpadStyleIndex(type);
|
||||
system_controller_handheld->SetNpadStyleIndex(type);
|
||||
emulated_controller_p1->SetNpadStyleIndex(type);
|
||||
emulated_controller_handheld->SetNpadStyleIndex(type);
|
||||
if (is_connected) {
|
||||
if (type == Core::HID::NpadStyleIndex::Handheld) {
|
||||
system_controller_p1->Disconnect();
|
||||
system_controller_handheld->Connect(true);
|
||||
system_controller = system_controller_handheld;
|
||||
emulated_controller_p1->Disconnect();
|
||||
emulated_controller_handheld->Connect(true);
|
||||
emulated_controller = emulated_controller_handheld;
|
||||
} else {
|
||||
system_controller_handheld->Disconnect();
|
||||
system_controller_p1->Connect(true);
|
||||
system_controller = system_controller_p1;
|
||||
emulated_controller_handheld->Disconnect();
|
||||
emulated_controller_p1->Connect(true);
|
||||
emulated_controller = emulated_controller_p1;
|
||||
}
|
||||
}
|
||||
ui->controllerFrame->SetController(system_controller->GetNpadIdType());
|
||||
ui->controllerFrame->SetController(emulated_controller);
|
||||
}
|
||||
system_controller->SetNpadStyleIndex(type);
|
||||
emulated_controller->SetNpadStyleIndex(type);
|
||||
});
|
||||
|
||||
connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this,
|
||||
@ -806,33 +806,34 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||
|
||||
ConfigureInputPlayer::~ConfigureInputPlayer() {
|
||||
if (player_index == 0) {
|
||||
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();
|
||||
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();
|
||||
} else {
|
||||
system_controller->DisableConfiguration();
|
||||
emulated_controller->DisableConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureInputPlayer::ApplyConfiguration() {
|
||||
if (player_index == 0) {
|
||||
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();
|
||||
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();
|
||||
return;
|
||||
}
|
||||
system_controller->DisableConfiguration();
|
||||
system_controller->SaveCurrentConfig();
|
||||
system_controller->EnableConfiguration();
|
||||
emulated_controller->DisableConfiguration();
|
||||
emulated_controller->SaveCurrentConfig();
|
||||
emulated_controller->EnableConfiguration();
|
||||
}
|
||||
|
||||
void ConfigureInputPlayer::showEvent(QShowEvent* event) {
|
||||
@ -857,7 +858,7 @@ void ConfigureInputPlayer::RetranslateUI() {
|
||||
}
|
||||
|
||||
void ConfigureInputPlayer::LoadConfiguration() {
|
||||
system_controller->ReloadFromSettings();
|
||||
emulated_controller->ReloadFromSettings();
|
||||
|
||||
UpdateUI();
|
||||
UpdateInputDeviceCombobox();
|
||||
@ -867,17 +868,17 @@ void ConfigureInputPlayer::LoadConfiguration() {
|
||||
}
|
||||
|
||||
const int comboBoxIndex =
|
||||
GetIndexFromControllerType(system_controller->GetNpadStyleIndex(true));
|
||||
GetIndexFromControllerType(emulated_controller->GetNpadStyleIndex(true));
|
||||
ui->comboControllerType->setCurrentIndex(comboBoxIndex);
|
||||
ui->groupConnectedController->setChecked(system_controller->IsConnected(true));
|
||||
ui->groupConnectedController->setChecked(emulated_controller->IsConnected(true));
|
||||
}
|
||||
|
||||
void ConfigureInputPlayer::ConnectPlayer(bool connected) {
|
||||
ui->groupConnectedController->setChecked(connected);
|
||||
if (connected) {
|
||||
system_controller->Connect(true);
|
||||
emulated_controller->Connect(true);
|
||||
} else {
|
||||
system_controller->Disconnect();
|
||||
emulated_controller->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@ -888,7 +889,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto devices = system_controller->GetMappedDevices();
|
||||
const auto devices = emulated_controller->GetMappedDevices();
|
||||
UpdateInputDevices();
|
||||
|
||||
if (devices.empty()) {
|
||||
@ -967,7 +968,7 @@ void ConfigureInputPlayer::ClearAll() {
|
||||
if (button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
system_controller->SetButtonParam(button_id, {});
|
||||
emulated_controller->SetButtonParam(button_id, {});
|
||||
}
|
||||
|
||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
|
||||
@ -976,7 +977,7 @@ void ConfigureInputPlayer::ClearAll() {
|
||||
if (analog_button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
system_controller->SetStickParam(analog_id, {});
|
||||
emulated_controller->SetStickParam(analog_id, {});
|
||||
}
|
||||
}
|
||||
|
||||
@ -985,7 +986,7 @@ void ConfigureInputPlayer::ClearAll() {
|
||||
if (motion_button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
system_controller->SetMotionParam(motion_id, {});
|
||||
emulated_controller->SetMotionParam(motion_id, {});
|
||||
}
|
||||
|
||||
UpdateUI();
|
||||
@ -994,31 +995,31 @@ void ConfigureInputPlayer::ClearAll() {
|
||||
|
||||
void ConfigureInputPlayer::UpdateUI() {
|
||||
for (int button = 0; button < Settings::NativeButton::NumButtons; ++button) {
|
||||
const Common::ParamPackage param = system_controller->GetButtonParam(button);
|
||||
const Common::ParamPackage param = emulated_controller->GetButtonParam(button);
|
||||
button_map[button]->setText(ButtonToText(param));
|
||||
}
|
||||
|
||||
const Common::ParamPackage ZL_param =
|
||||
system_controller->GetButtonParam(Settings::NativeButton::ZL);
|
||||
emulated_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 =
|
||||
system_controller->GetButtonParam(Settings::NativeButton::ZR);
|
||||
emulated_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 = system_controller->GetMotionParam(motion_id);
|
||||
const Common::ParamPackage param = emulated_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 = system_controller->GetStickParam(analog_id);
|
||||
const Common::ParamPackage param = emulated_controller->GetStickParam(analog_id);
|
||||
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
|
||||
auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
|
||||
|
||||
@ -1346,7 +1347,7 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
||||
if (button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
system_controller->SetButtonParam(button_id, {});
|
||||
emulated_controller->SetButtonParam(button_id, {});
|
||||
}
|
||||
|
||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
|
||||
@ -1355,7 +1356,7 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
||||
if (analog_button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
system_controller->SetStickParam(analog_id, {});
|
||||
emulated_controller->SetStickParam(analog_id, {});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1364,13 +1365,13 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
||||
if (motion_button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
system_controller->SetMotionParam(motion_id, {});
|
||||
emulated_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) {
|
||||
system_controller->SetButtonParam(
|
||||
emulated_controller->SetButtonParam(
|
||||
button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam(
|
||||
Config::default_buttons[button_id])});
|
||||
}
|
||||
@ -1384,11 +1385,11 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
||||
|
||||
analog_param.Set("modifier", InputCommon::GenerateKeyboardParam(
|
||||
Config::default_stick_mod[analog_id]));
|
||||
system_controller->SetStickParam(analog_id, analog_param);
|
||||
emulated_controller->SetStickParam(analog_id, analog_param);
|
||||
}
|
||||
|
||||
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
|
||||
system_controller->SetMotionParam(
|
||||
emulated_controller->SetMotionParam(
|
||||
motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam(
|
||||
Config::default_motions[motion_id])});
|
||||
}
|
||||
@ -1408,15 +1409,15 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
|
||||
|
||||
for (const auto& button_mapping : button_mappings) {
|
||||
const std::size_t index = button_mapping.first;
|
||||
system_controller->SetButtonParam(index, button_mapping.second);
|
||||
emulated_controller->SetButtonParam(index, button_mapping.second);
|
||||
}
|
||||
for (const auto& analog_mapping : analog_mappings) {
|
||||
const std::size_t index = analog_mapping.first;
|
||||
system_controller->SetStickParam(index, analog_mapping.second);
|
||||
emulated_controller->SetStickParam(index, analog_mapping.second);
|
||||
}
|
||||
for (const auto& motion_mapping : motion_mappings) {
|
||||
const std::size_t index = motion_mapping.first;
|
||||
system_controller->SetMotionParam(index, motion_mapping.second);
|
||||
emulated_controller->SetMotionParam(index, motion_mapping.second);
|
||||
}
|
||||
|
||||
UpdateUI();
|
||||
@ -1608,7 +1609,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 && system_controller->GetNpadIdType() ==
|
||||
const bool is_handheld = player_index == 0 && emulated_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 SystemController;
|
||||
class EmulatedController;
|
||||
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::SystemController* system_controller;
|
||||
Core::HID::EmulatedController* emulated_controller;
|
||||
|
||||
static constexpr int ANALOG_SUB_BUTTONS_NUM = 4;
|
||||
|
||||
|
407
src/yuzu/util/controller_viewer/common_shapes.cpp
Normal file
407
src/yuzu/util/controller_viewer/common_shapes.cpp
Normal file
@ -0,0 +1,407 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <QMenu>
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
|
||||
#include "common/input.h"
|
||||
#include "yuzu/util/controller_viewer/common_shapes.h"
|
||||
|
||||
namespace ControllerViewer {
|
||||
|
||||
void CommonShapes::DrawBattery(QPainter& p, QPointF center, Common::Input::BatteryLevel battery,
|
||||
QColor outline, QColor battery_color, QColor charging_outline,
|
||||
QColor charging_color) {
|
||||
if (battery == Common::Input::BatteryLevel::None) {
|
||||
return;
|
||||
}
|
||||
// Draw outline
|
||||
p.setPen(QPen(outline, 5));
|
||||
p.setBrush(Qt::transparent);
|
||||
p.drawRoundedRect(center.x(), center.y(), 34, 16, 2, 2);
|
||||
|
||||
p.setPen(QPen(outline, 3));
|
||||
p.drawRect(center.x() + 35, center.y() + 4.5f, 4, 7);
|
||||
|
||||
// Draw Battery shape
|
||||
p.setPen(QPen(battery_color, 3));
|
||||
p.setBrush(Qt::transparent);
|
||||
p.drawRoundedRect(center.x(), center.y(), 34, 16, 2, 2);
|
||||
|
||||
p.setPen(QPen(battery_color, 1));
|
||||
p.setBrush(battery_color);
|
||||
p.drawRect(center.x() + 35, center.y() + 4.5f, 4, 7);
|
||||
switch (battery) {
|
||||
case Common::Input::BatteryLevel::Charging:
|
||||
p.drawRect(center.x(), center.y(), 34, 16);
|
||||
p.setPen(charging_outline);
|
||||
p.setBrush(charging_color);
|
||||
DrawSymbol(p, center + QPointF(17.0f, 8.0f), Symbol::Charging, 2.1f);
|
||||
break;
|
||||
case Common::Input::BatteryLevel::Full:
|
||||
p.drawRect(center.x(), center.y(), 34, 16);
|
||||
break;
|
||||
case Common::Input::BatteryLevel::Medium:
|
||||
p.drawRect(center.x(), center.y(), 25, 16);
|
||||
break;
|
||||
case Common::Input::BatteryLevel::Low:
|
||||
p.drawRect(center.x(), center.y(), 17, 16);
|
||||
break;
|
||||
case Common::Input::BatteryLevel::Critical:
|
||||
p.drawRect(center.x(), center.y(), 6, 16);
|
||||
break;
|
||||
case Common::Input::BatteryLevel::Empty:
|
||||
p.drawRect(center.x(), center.y(), 3, 16);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CommonShapes::DrawSymbol(QPainter& p, const QPointF center, Symbol symbol, float icon_size) {
|
||||
std::array<QPointF, house.size() / 2> house_icon;
|
||||
std::array<QPointF, symbol_a.size() / 2> a_icon;
|
||||
std::array<QPointF, symbol_b.size() / 2> b_icon;
|
||||
std::array<QPointF, symbol_x.size() / 2> x_icon;
|
||||
std::array<QPointF, symbol_y.size() / 2> y_icon;
|
||||
std::array<QPointF, symbol_l.size() / 2> l_icon;
|
||||
std::array<QPointF, symbol_r.size() / 2> r_icon;
|
||||
std::array<QPointF, symbol_c.size() / 2> c_icon;
|
||||
std::array<QPointF, symbol_zl.size() / 2> zl_icon;
|
||||
std::array<QPointF, symbol_sl.size() / 2> sl_icon;
|
||||
std::array<QPointF, symbol_zr.size() / 2> zr_icon;
|
||||
std::array<QPointF, symbol_sr.size() / 2> sr_icon;
|
||||
std::array<QPointF, symbol_charging.size() / 2> charging_icon;
|
||||
switch (symbol) {
|
||||
case Symbol::House:
|
||||
for (std::size_t point = 0; point < house.size() / 2; ++point) {
|
||||
house_icon[point] = center + QPointF(house[point * 2] * icon_size,
|
||||
(house[point * 2 + 1] - 0.025f) * icon_size);
|
||||
}
|
||||
p.drawPolygon(house_icon.data(), static_cast<int>(house_icon.size()));
|
||||
break;
|
||||
case Symbol::A:
|
||||
for (std::size_t point = 0; point < symbol_a.size() / 2; ++point) {
|
||||
a_icon[point] = center + QPointF(symbol_a[point * 2] * icon_size,
|
||||
symbol_a[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(a_icon.data(), static_cast<int>(a_icon.size()));
|
||||
break;
|
||||
case Symbol::B:
|
||||
for (std::size_t point = 0; point < symbol_b.size() / 2; ++point) {
|
||||
b_icon[point] = center + QPointF(symbol_b[point * 2] * icon_size,
|
||||
symbol_b[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(b_icon.data(), static_cast<int>(b_icon.size()));
|
||||
break;
|
||||
case Symbol::X:
|
||||
for (std::size_t point = 0; point < symbol_x.size() / 2; ++point) {
|
||||
x_icon[point] = center + QPointF(symbol_x[point * 2] * icon_size,
|
||||
symbol_x[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(x_icon.data(), static_cast<int>(x_icon.size()));
|
||||
break;
|
||||
case Symbol::Y:
|
||||
for (std::size_t point = 0; point < symbol_y.size() / 2; ++point) {
|
||||
y_icon[point] = center + QPointF(symbol_y[point * 2] * icon_size,
|
||||
(symbol_y[point * 2 + 1] - 1.0f) * icon_size);
|
||||
}
|
||||
p.drawPolygon(y_icon.data(), static_cast<int>(y_icon.size()));
|
||||
break;
|
||||
case Symbol::L:
|
||||
for (std::size_t point = 0; point < symbol_l.size() / 2; ++point) {
|
||||
l_icon[point] = center + QPointF(symbol_l[point * 2] * icon_size,
|
||||
(symbol_l[point * 2 + 1] - 1.0f) * icon_size);
|
||||
}
|
||||
p.drawPolygon(l_icon.data(), static_cast<int>(l_icon.size()));
|
||||
break;
|
||||
case Symbol::R:
|
||||
for (std::size_t point = 0; point < symbol_r.size() / 2; ++point) {
|
||||
r_icon[point] = center + QPointF(symbol_r[point * 2] * icon_size,
|
||||
(symbol_r[point * 2 + 1] - 1.0f) * icon_size);
|
||||
}
|
||||
p.drawPolygon(r_icon.data(), static_cast<int>(r_icon.size()));
|
||||
break;
|
||||
case Symbol::C:
|
||||
for (std::size_t point = 0; point < symbol_c.size() / 2; ++point) {
|
||||
c_icon[point] = center + QPointF(symbol_c[point * 2] * icon_size,
|
||||
(symbol_c[point * 2 + 1] - 1.0f) * icon_size);
|
||||
}
|
||||
p.drawPolygon(c_icon.data(), static_cast<int>(c_icon.size()));
|
||||
break;
|
||||
case Symbol::ZL:
|
||||
for (std::size_t point = 0; point < symbol_zl.size() / 2; ++point) {
|
||||
zl_icon[point] = center + QPointF(symbol_zl[point * 2] * icon_size,
|
||||
symbol_zl[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(zl_icon.data(), static_cast<int>(zl_icon.size()));
|
||||
break;
|
||||
case Symbol::SL:
|
||||
for (std::size_t point = 0; point < symbol_sl.size() / 2; ++point) {
|
||||
sl_icon[point] = center + QPointF(symbol_sl[point * 2] * icon_size,
|
||||
symbol_sl[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(sl_icon.data(), static_cast<int>(sl_icon.size()));
|
||||
break;
|
||||
case Symbol::ZR:
|
||||
for (std::size_t point = 0; point < symbol_zr.size() / 2; ++point) {
|
||||
zr_icon[point] = center + QPointF(symbol_zr[point * 2] * icon_size,
|
||||
symbol_zr[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(zr_icon.data(), static_cast<int>(zr_icon.size()));
|
||||
break;
|
||||
case Symbol::SR:
|
||||
for (std::size_t point = 0; point < symbol_sr.size() / 2; ++point) {
|
||||
sr_icon[point] = center + QPointF(symbol_sr[point * 2] * icon_size,
|
||||
symbol_sr[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(sr_icon.data(), static_cast<int>(sr_icon.size()));
|
||||
break;
|
||||
case Symbol::Charging:
|
||||
for (std::size_t point = 0; point < symbol_charging.size() / 2; ++point) {
|
||||
charging_icon[point] = center + QPointF(symbol_charging[point * 2] * icon_size,
|
||||
symbol_charging[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(charging_icon.data(), static_cast<int>(charging_icon.size()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CommonShapes::DrawArrow(QPainter& p, const QPointF center, const Direction direction,
|
||||
float size) {
|
||||
|
||||
std::array<QPointF, up_arrow_symbol.size() / 2> arrow_symbol;
|
||||
|
||||
for (std::size_t point = 0; point < up_arrow_symbol.size() / 2; ++point) {
|
||||
const float up_arrow_x = up_arrow_symbol[point * 2 + 0];
|
||||
const float up_arrow_y = up_arrow_symbol[point * 2 + 1];
|
||||
|
||||
switch (direction) {
|
||||
case Direction::Up:
|
||||
arrow_symbol[point] = center + QPointF(up_arrow_x * size, up_arrow_y * size);
|
||||
break;
|
||||
case Direction::Left:
|
||||
arrow_symbol[point] = center + QPointF(up_arrow_y * size, up_arrow_x * size);
|
||||
break;
|
||||
case Direction::Right:
|
||||
arrow_symbol[point] = center + QPointF(-up_arrow_y * size, up_arrow_x * size);
|
||||
break;
|
||||
case Direction::Down:
|
||||
arrow_symbol[point] = center + QPointF(up_arrow_x * size, -up_arrow_y * size);
|
||||
break;
|
||||
case Direction::None:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DrawPolygon(p, arrow_symbol);
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
void CommonShapes::DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon) {
|
||||
p.drawPolygon(polygon.data(), static_cast<int>(polygon.size()));
|
||||
}
|
||||
|
||||
void CommonShapes::DrawCircle(QPainter& p, const QPointF center, float size) {
|
||||
p.drawEllipse(center, size, size);
|
||||
}
|
||||
|
||||
void CommonShapes::DrawRectangle(QPainter& p, const QPointF center, float width, float height) {
|
||||
const QRectF rect = QRectF(center.x() - (width / 2), center.y() - (height / 2), width, height);
|
||||
p.drawRect(rect);
|
||||
}
|
||||
void CommonShapes::DrawRoundRectangle(QPainter& p, const QPointF center, float width, float height,
|
||||
float round) {
|
||||
const QRectF rect = QRectF(center.x() - (width / 2), center.y() - (height / 2), width, height);
|
||||
p.drawRoundedRect(rect, round, round);
|
||||
}
|
||||
|
||||
void CommonShapes::DrawText(QPainter& p, const QPointF center, float text_size,
|
||||
const QString& text) {
|
||||
SetTextFont(p, text_size);
|
||||
const QFontMetrics fm(p.font());
|
||||
const QPointF offset = {fm.horizontalAdvance(text) / 2.0f, -text_size / 2.0f};
|
||||
p.drawText(center - offset, text);
|
||||
}
|
||||
|
||||
void CommonShapes::SetTextFont(QPainter& p, float text_size, const QString& font_family) {
|
||||
QFont font = p.font();
|
||||
font.setPointSizeF(text_size);
|
||||
font.setFamily(font_family);
|
||||
p.setFont(font);
|
||||
}
|
||||
|
||||
constexpr std::array<float, 13 * 2> symbol_a = {
|
||||
-1.085f, -5.2f, 1.085f, -5.2f, 5.085f, 5.0f, 2.785f, 5.0f, 1.785f,
|
||||
2.65f, -1.785f, 2.65f, -2.785f, 5.0f, -5.085f, 5.0f, -1.4f, 1.0f,
|
||||
0.0f, -2.8f, 1.4f, 1.0f, -1.4f, 1.0f, -5.085f, 5.0f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 134 * 2> symbol_b = {
|
||||
-4.0f, 0.0f, -4.0f, 0.0f, -4.0f, -0.1f, -3.8f, -5.1f, 1.8f, -5.0f, 2.3f, -4.9f, 2.6f,
|
||||
-4.8f, 2.8f, -4.7f, 2.9f, -4.6f, 3.1f, -4.5f, 3.2f, -4.4f, 3.4f, -4.3f, 3.4f, -4.2f,
|
||||
3.5f, -4.1f, 3.7f, -4.0f, 3.7f, -3.9f, 3.8f, -3.8f, 3.8f, -3.7f, 3.9f, -3.6f, 3.9f,
|
||||
-3.5f, 4.0f, -3.4f, 4.0f, -3.3f, 4.1f, -3.1f, 4.1f, -3.0f, 4.0f, -2.0f, 4.0f, -1.9f,
|
||||
3.9f, -1.7f, 3.9f, -1.6f, 3.8f, -1.5f, 3.8f, -1.4f, 3.7f, -1.3f, 3.7f, -1.2f, 3.6f,
|
||||
-1.1f, 3.6f, -1.0f, 3.5f, -0.9f, 3.3f, -0.8f, 3.3f, -0.7f, 3.2f, -0.6f, 3.0f, -0.5f,
|
||||
2.9f, -0.4f, 2.7f, -0.3f, 2.9f, -0.2f, 3.2f, -0.1f, 3.3f, 0.0f, 3.5f, 0.1f, 3.6f,
|
||||
0.2f, 3.8f, 0.3f, 3.9f, 0.4f, 4.0f, 0.6f, 4.1f, 0.7f, 4.3f, 0.8f, 4.3f, 0.9f,
|
||||
4.4f, 1.0f, 4.4f, 1.1f, 4.5f, 1.3f, 4.5f, 1.4f, 4.6f, 1.6f, 4.6f, 1.7f, 4.5f,
|
||||
2.8f, 4.5f, 2.9f, 4.4f, 3.1f, 4.4f, 3.2f, 4.3f, 3.4f, 4.3f, 3.5f, 4.2f, 3.6f,
|
||||
4.2f, 3.7f, 4.1f, 3.8f, 4.1f, 3.9f, 4.0f, 4.0f, 3.9f, 4.2f, 3.8f, 4.3f, 3.6f,
|
||||
4.4f, 3.6f, 4.5f, 3.4f, 4.6f, 3.3f, 4.7f, 3.1f, 4.8f, 2.8f, 4.9f, 2.6f, 5.0f,
|
||||
2.1f, 5.1f, -4.0f, 5.0f, -4.0f, 4.9f,
|
||||
|
||||
-4.0f, 0.0f, 1.1f, 3.4f, 1.1f, 3.4f, 1.5f, 3.3f, 1.8f, 3.2f, 2.0f, 3.1f, 2.1f,
|
||||
3.0f, 2.3f, 2.9f, 2.3f, 2.8f, 2.4f, 2.7f, 2.4f, 2.6f, 2.5f, 2.3f, 2.5f, 2.2f,
|
||||
2.4f, 1.7f, 2.4f, 1.6f, 2.3f, 1.4f, 2.3f, 1.3f, 2.2f, 1.2f, 2.2f, 1.1f, 2.1f,
|
||||
1.0f, 1.9f, 0.9f, 1.6f, 0.8f, 1.4f, 0.7f, -1.9f, 0.6f, -1.9f, 0.7f, -1.8f, 3.4f,
|
||||
1.1f, 3.4f, -4.0f, 0.0f,
|
||||
|
||||
0.3f, -1.1f, 0.3f, -1.1f, 1.3f, -1.2f, 1.5f, -1.3f, 1.8f, -1.4f, 1.8f, -1.5f, 1.9f,
|
||||
-1.6f, 2.0f, -1.8f, 2.0f, -1.9f, 2.1f, -2.0f, 2.1f, -2.1f, 2.0f, -2.7f, 2.0f, -2.8f,
|
||||
1.9f, -2.9f, 1.9f, -3.0f, 1.8f, -3.1f, 1.6f, -3.2f, 1.6f, -3.3f, 1.3f, -3.4f, -1.9f,
|
||||
-3.3f, -1.9f, -3.2f, -1.8f, -1.0f, 0.2f, -1.1f, 0.3f, -1.1f, -4.0f, 0.0f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 9 * 2> symbol_y = {
|
||||
-4.79f, -4.9f, -2.44f, -4.9f, 0.0f, -0.9f, 2.44f, -4.9f, 4.79f,
|
||||
-4.9f, 1.05f, 1.0f, 1.05f, 5.31f, -1.05f, 5.31f, -1.05f, 1.0f,
|
||||
|
||||
};
|
||||
|
||||
constexpr std::array<float, 12 * 2> symbol_x = {
|
||||
-4.4f, -5.0f, -2.0f, -5.0f, 0.0f, -1.7f, 2.0f, -5.0f, 4.4f, -5.0f, 1.2f, 0.0f,
|
||||
4.4f, 5.0f, 2.0f, 5.0f, 0.0f, 1.7f, -2.0f, 5.0f, -4.4f, 5.0f, -1.2f, 0.0f,
|
||||
|
||||
};
|
||||
|
||||
constexpr std::array<float, 7 * 2> symbol_l = {
|
||||
2.4f, -3.23f, 2.4f, 2.1f, 5.43f, 2.1f, 5.43f, 3.22f, 0.98f, 3.22f, 0.98f, -3.23f, 2.4f, -3.23f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 98 * 2> symbol_r = {
|
||||
1.0f, 0.0f, 1.0f, -0.1f, 1.1f, -3.3f, 4.3f, -3.2f, 5.1f, -3.1f, 5.4f, -3.0f, 5.6f, -2.9f,
|
||||
5.7f, -2.8f, 5.9f, -2.7f, 5.9f, -2.6f, 6.0f, -2.5f, 6.1f, -2.3f, 6.2f, -2.2f, 6.2f, -2.1f,
|
||||
6.3f, -2.0f, 6.3f, -1.9f, 6.2f, -0.8f, 6.2f, -0.7f, 6.1f, -0.6f, 6.1f, -0.5f, 6.0f, -0.4f,
|
||||
6.0f, -0.3f, 5.9f, -0.2f, 5.7f, -0.1f, 5.7f, 0.0f, 5.6f, 0.1f, 5.4f, 0.2f, 5.1f, 0.3f,
|
||||
4.7f, 0.4f, 4.7f, 0.5f, 4.9f, 0.6f, 5.0f, 0.7f, 5.2f, 0.8f, 5.2f, 0.9f, 5.3f, 1.0f,
|
||||
5.5f, 1.1f, 5.5f, 1.2f, 5.6f, 1.3f, 5.7f, 1.5f, 5.8f, 1.6f, 5.9f, 1.8f, 6.0f, 1.9f,
|
||||
6.1f, 2.1f, 6.2f, 2.2f, 6.2f, 2.3f, 6.3f, 2.4f, 6.4f, 2.6f, 6.5f, 2.7f, 6.6f, 2.9f,
|
||||
6.7f, 3.0f, 6.7f, 3.1f, 6.8f, 3.2f, 6.8f, 3.3f, 5.3f, 3.2f, 5.2f, 3.1f, 5.2f, 3.0f,
|
||||
5.1f, 2.9f, 5.0f, 2.7f, 4.9f, 2.6f, 4.8f, 2.4f, 4.7f, 2.3f, 4.6f, 2.1f, 4.5f, 2.0f,
|
||||
4.4f, 1.8f, 4.3f, 1.7f, 4.1f, 1.4f, 4.0f, 1.3f, 3.9f, 1.1f, 3.8f, 1.0f, 3.6f, 0.9f,
|
||||
3.6f, 0.8f, 3.5f, 0.7f, 3.3f, 0.6f, 2.9f, 0.5f, 2.3f, 0.6f, 2.3f, 0.7f, 2.2f, 3.3f,
|
||||
1.0f, 3.2f, 1.0f, 3.1f, 1.0f, 0.0f,
|
||||
|
||||
4.2f, -0.5f, 4.4f, -0.6f, 4.7f, -0.7f, 4.8f, -0.8f, 4.9f, -1.0f, 5.0f, -1.1f, 5.0f, -1.2f,
|
||||
4.9f, -1.7f, 4.9f, -1.8f, 4.8f, -1.9f, 4.8f, -2.0f, 4.6f, -2.1f, 4.3f, -2.2f, 2.3f, -2.1f,
|
||||
2.3f, -2.0f, 2.4f, -0.5f, 4.2f, -0.5f, 1.0f, 0.0f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 18 * 2> symbol_zl = {
|
||||
-2.6f, -2.13f, -5.6f, -2.13f, -5.6f, -3.23f, -0.8f, -3.23f, -0.8f, -2.13f, -4.4f, 2.12f,
|
||||
-0.7f, 2.12f, -0.7f, 3.22f, -6.0f, 3.22f, -6.0f, 2.12f, 2.4f, -3.23f, 2.4f, 2.1f,
|
||||
5.43f, 2.1f, 5.43f, 3.22f, 0.98f, 3.22f, 0.98f, -3.23f, 2.4f, -3.23f, -6.0f, 2.12f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 57 * 2> symbol_sl = {
|
||||
-3.0f, -3.65f, -2.76f, -4.26f, -2.33f, -4.76f, -1.76f, -5.09f, -1.13f, -5.26f, -0.94f,
|
||||
-4.77f, -0.87f, -4.11f, -1.46f, -3.88f, -1.91f, -3.41f, -2.05f, -2.78f, -1.98f, -2.13f,
|
||||
-1.59f, -1.61f, -0.96f, -1.53f, -0.56f, -2.04f, -0.38f, -2.67f, -0.22f, -3.31f, 0.0f,
|
||||
-3.93f, 0.34f, -4.49f, 0.86f, -4.89f, 1.49f, -5.05f, 2.14f, -4.95f, 2.69f, -4.6f,
|
||||
3.07f, -4.07f, 3.25f, -3.44f, 3.31f, -2.78f, 3.25f, -2.12f, 3.07f, -1.49f, 2.7f,
|
||||
-0.95f, 2.16f, -0.58f, 1.52f, -0.43f, 1.41f, -0.99f, 1.38f, -1.65f, 1.97f, -1.91f,
|
||||
2.25f, -2.49f, 2.25f, -3.15f, 1.99f, -3.74f, 1.38f, -3.78f, 1.06f, -3.22f, 0.88f,
|
||||
-2.58f, 0.71f, -1.94f, 0.49f, -1.32f, 0.13f, -0.77f, -0.4f, -0.4f, -1.04f, -0.25f,
|
||||
-1.69f, -0.32f, -2.28f, -0.61f, -2.73f, -1.09f, -2.98f, -1.69f, -3.09f, -2.34f,
|
||||
|
||||
3.23f, 2.4f, -2.1f, 2.4f, -2.1f, 5.43f, -3.22f, 5.43f, -3.22f, 0.98f, 3.23f,
|
||||
0.98f, 3.23f, 2.4f, -3.09f, -2.34f,
|
||||
};
|
||||
constexpr std::array<float, 109 * 2> symbol_zr = {
|
||||
-2.6f, -2.13f, -5.6f, -2.13f, -5.6f, -3.23f, -0.8f, -3.23f, -0.8f, -2.13f, -4.4f, 2.12f, -0.7f,
|
||||
2.12f, -0.7f, 3.22f, -6.0f, 3.22f, -6.0f, 2.12f,
|
||||
|
||||
1.0f, 0.0f, 1.0f, -0.1f, 1.1f, -3.3f, 4.3f, -3.2f, 5.1f, -3.1f, 5.4f, -3.0f, 5.6f,
|
||||
-2.9f, 5.7f, -2.8f, 5.9f, -2.7f, 5.9f, -2.6f, 6.0f, -2.5f, 6.1f, -2.3f, 6.2f, -2.2f,
|
||||
6.2f, -2.1f, 6.3f, -2.0f, 6.3f, -1.9f, 6.2f, -0.8f, 6.2f, -0.7f, 6.1f, -0.6f, 6.1f,
|
||||
-0.5f, 6.0f, -0.4f, 6.0f, -0.3f, 5.9f, -0.2f, 5.7f, -0.1f, 5.7f, 0.0f, 5.6f, 0.1f,
|
||||
5.4f, 0.2f, 5.1f, 0.3f, 4.7f, 0.4f, 4.7f, 0.5f, 4.9f, 0.6f, 5.0f, 0.7f, 5.2f,
|
||||
0.8f, 5.2f, 0.9f, 5.3f, 1.0f, 5.5f, 1.1f, 5.5f, 1.2f, 5.6f, 1.3f, 5.7f, 1.5f,
|
||||
5.8f, 1.6f, 5.9f, 1.8f, 6.0f, 1.9f, 6.1f, 2.1f, 6.2f, 2.2f, 6.2f, 2.3f, 6.3f,
|
||||
2.4f, 6.4f, 2.6f, 6.5f, 2.7f, 6.6f, 2.9f, 6.7f, 3.0f, 6.7f, 3.1f, 6.8f, 3.2f,
|
||||
6.8f, 3.3f, 5.3f, 3.2f, 5.2f, 3.1f, 5.2f, 3.0f, 5.1f, 2.9f, 5.0f, 2.7f, 4.9f,
|
||||
2.6f, 4.8f, 2.4f, 4.7f, 2.3f, 4.6f, 2.1f, 4.5f, 2.0f, 4.4f, 1.8f, 4.3f, 1.7f,
|
||||
4.1f, 1.4f, 4.0f, 1.3f, 3.9f, 1.1f, 3.8f, 1.0f, 3.6f, 0.9f, 3.6f, 0.8f, 3.5f,
|
||||
0.7f, 3.3f, 0.6f, 2.9f, 0.5f, 2.3f, 0.6f, 2.3f, 0.7f, 2.2f, 3.3f, 1.0f, 3.2f,
|
||||
1.0f, 3.1f, 1.0f, 0.0f,
|
||||
|
||||
4.2f, -0.5f, 4.4f, -0.6f, 4.7f, -0.7f, 4.8f, -0.8f, 4.9f, -1.0f, 5.0f, -1.1f, 5.0f,
|
||||
-1.2f, 4.9f, -1.7f, 4.9f, -1.8f, 4.8f, -1.9f, 4.8f, -2.0f, 4.6f, -2.1f, 4.3f, -2.2f,
|
||||
2.3f, -2.1f, 2.3f, -2.0f, 2.4f, -0.5f, 4.2f, -0.5f, 1.0f, 0.0f, -6.0f, 2.12f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 148 * 2> symbol_sr = {
|
||||
-3.0f, -3.65f, -2.76f, -4.26f, -2.33f, -4.76f, -1.76f, -5.09f, -1.13f, -5.26f, -0.94f, -4.77f,
|
||||
-0.87f, -4.11f, -1.46f, -3.88f, -1.91f, -3.41f, -2.05f, -2.78f, -1.98f, -2.13f, -1.59f, -1.61f,
|
||||
-0.96f, -1.53f, -0.56f, -2.04f, -0.38f, -2.67f, -0.22f, -3.31f, 0.0f, -3.93f, 0.34f, -4.49f,
|
||||
0.86f, -4.89f, 1.49f, -5.05f, 2.14f, -4.95f, 2.69f, -4.6f, 3.07f, -4.07f, 3.25f, -3.44f,
|
||||
3.31f, -2.78f, 3.25f, -2.12f, 3.07f, -1.49f, 2.7f, -0.95f, 2.16f, -0.58f, 1.52f, -0.43f,
|
||||
1.41f, -0.99f, 1.38f, -1.65f, 1.97f, -1.91f, 2.25f, -2.49f, 2.25f, -3.15f, 1.99f, -3.74f,
|
||||
1.38f, -3.78f, 1.06f, -3.22f, 0.88f, -2.58f, 0.71f, -1.94f, 0.49f, -1.32f, 0.13f, -0.77f,
|
||||
-0.4f, -0.4f, -1.04f, -0.25f, -1.69f, -0.32f, -2.28f, -0.61f, -2.73f, -1.09f, -2.98f, -1.69f,
|
||||
-3.09f, -2.34f,
|
||||
|
||||
-1.0f, 0.0f, 0.1f, 1.0f, 3.3f, 1.1f, 3.2f, 4.3f, 3.1f, 5.1f, 3.0f, 5.4f,
|
||||
2.9f, 5.6f, 2.8f, 5.7f, 2.7f, 5.9f, 2.6f, 5.9f, 2.5f, 6.0f, 2.3f, 6.1f,
|
||||
2.2f, 6.2f, 2.1f, 6.2f, 2.0f, 6.3f, 1.9f, 6.3f, 0.8f, 6.2f, 0.7f, 6.2f,
|
||||
0.6f, 6.1f, 0.5f, 6.1f, 0.4f, 6.0f, 0.3f, 6.0f, 0.2f, 5.9f, 0.1f, 5.7f,
|
||||
0.0f, 5.7f, -0.1f, 5.6f, -0.2f, 5.4f, -0.3f, 5.1f, -0.4f, 4.7f, -0.5f, 4.7f,
|
||||
-0.6f, 4.9f, -0.7f, 5.0f, -0.8f, 5.2f, -0.9f, 5.2f, -1.0f, 5.3f, -1.1f, 5.5f,
|
||||
-1.2f, 5.5f, -1.3f, 5.6f, -1.5f, 5.7f, -1.6f, 5.8f, -1.8f, 5.9f, -1.9f, 6.0f,
|
||||
-2.1f, 6.1f, -2.2f, 6.2f, -2.3f, 6.2f, -2.4f, 6.3f, -2.6f, 6.4f, -2.7f, 6.5f,
|
||||
-2.9f, 6.6f, -3.0f, 6.7f, -3.1f, 6.7f, -3.2f, 6.8f, -3.3f, 6.8f, -3.2f, 5.3f,
|
||||
-3.1f, 5.2f, -3.0f, 5.2f, -2.9f, 5.1f, -2.7f, 5.0f, -2.6f, 4.9f, -2.4f, 4.8f,
|
||||
-2.3f, 4.7f, -2.1f, 4.6f, -2.0f, 4.5f, -1.8f, 4.4f, -1.7f, 4.3f, -1.4f, 4.1f,
|
||||
-1.3f, 4.0f, -1.1f, 3.9f, -1.0f, 3.8f, -0.9f, 3.6f, -0.8f, 3.6f, -0.7f, 3.5f,
|
||||
-0.6f, 3.3f, -0.5f, 2.9f, -0.6f, 2.3f, -0.7f, 2.3f, -3.3f, 2.2f, -3.2f, 1.0f,
|
||||
-3.1f, 1.0f, 0.0f, 1.0f,
|
||||
|
||||
0.5f, 4.2f, 0.6f, 4.4f, 0.7f, 4.7f, 0.8f, 4.8f, 1.0f, 4.9f, 1.1f, 5.0f,
|
||||
1.2f, 5.0f, 1.7f, 4.9f, 1.8f, 4.9f, 1.9f, 4.8f, 2.0f, 4.8f, 2.1f, 4.6f,
|
||||
2.2f, 4.3f, 2.1f, 2.3f, 2.0f, 2.3f, 0.5f, 2.4f, 0.5f, 4.2f, -0.0f, 1.0f,
|
||||
-3.09f, -2.34f,
|
||||
|
||||
};
|
||||
|
||||
constexpr std::array<float, 30 * 2> symbol_c = {
|
||||
2.86f, 7.57f, 0.99f, 7.94f, -0.91f, 7.87f, -2.73f, 7.31f, -4.23f, 6.14f, -5.2f, 4.51f,
|
||||
-5.65f, 2.66f, -5.68f, 0.75f, -5.31f, -1.12f, -4.43f, -2.81f, -3.01f, -4.08f, -1.24f, -4.78f,
|
||||
0.66f, -4.94f, 2.54f, -4.67f, 4.33f, -4.0f, 4.63f, -2.27f, 3.37f, -2.7f, 1.6f, -3.4f,
|
||||
-0.3f, -3.5f, -2.09f, -2.87f, -3.34f, -1.45f, -3.91f, 0.37f, -3.95f, 2.27f, -3.49f, 4.12f,
|
||||
-2.37f, 5.64f, -0.65f, 6.44f, 1.25f, 6.47f, 3.06f, 5.89f, 4.63f, 4.92f, 4.63f, 6.83f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 6 * 2> symbol_charging = {
|
||||
6.5f, -1.0f, 1.0f, -1.0f, 1.0f, -3.0f, -6.5f, 1.0f, -1.0f, 1.0f, -1.0f, 3.0f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 12 * 2> house = {
|
||||
-1.3f, 0.0f, -0.93f, 0.0f, -0.93f, 1.15f, 0.93f, 1.15f, 0.93f, 0.0f, 1.3f, 0.0f,
|
||||
0.0f, -1.2f, -1.3f, 0.0f, -0.43f, 0.0f, -0.43f, .73f, 0.43f, .73f, 0.43f, 0.0f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 11 * 2> up_arrow_button = {
|
||||
9.1f, -9.1f, 9.1f, -30.0f, 8.1f, -30.1f, 7.7f, -30.1f, -8.6f, -30.0f, -9.0f,
|
||||
-29.8f, -9.3f, -29.5f, -9.5f, -29.1f, -9.1f, -28.7f, -9.1f, -9.1f, 0.0f, 0.6f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 3 * 2> up_arrow_symbol = {
|
||||
0.0f, -3.0f, -3.0f, 2.0f, 3.0f, 2.0f,
|
||||
};
|
||||
|
||||
} // namespace ControllerViewer
|
65
src/yuzu/util/controller_viewer/common_shapes.h
Normal file
65
src/yuzu/util/controller_viewer/common_shapes.h
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <QColor>
|
||||
#include <QPointer>
|
||||
|
||||
#include "common\common_types.h"
|
||||
|
||||
namespace Common::Input {
|
||||
enum class BatteryLevel : u32;
|
||||
}
|
||||
|
||||
namespace ControllerViewer {
|
||||
|
||||
// Widget for representing controller animations
|
||||
class CommonShapes {
|
||||
|
||||
enum class Direction : std::size_t {
|
||||
None,
|
||||
Up,
|
||||
Right,
|
||||
Down,
|
||||
Left,
|
||||
};
|
||||
|
||||
enum class Symbol {
|
||||
House,
|
||||
A,
|
||||
B,
|
||||
X,
|
||||
Y,
|
||||
L,
|
||||
R,
|
||||
C,
|
||||
SL,
|
||||
ZL,
|
||||
ZR,
|
||||
SR,
|
||||
Charging,
|
||||
};
|
||||
|
||||
// Draw battery functions
|
||||
void DrawBattery(QPainter& p, QPointF center, Common::Input::BatteryLevel battery,
|
||||
QColor outline, QColor battery_color, QColor charging_outline,
|
||||
QColor charging_color);
|
||||
|
||||
// Draw icon functions
|
||||
void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size);
|
||||
void DrawArrow(QPainter& p, QPointF center, Direction direction, float size);
|
||||
|
||||
// Draw primitive types
|
||||
template <size_t N>
|
||||
void DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon);
|
||||
void DrawCircle(QPainter& p, QPointF center, float size);
|
||||
void DrawRectangle(QPainter& p, QPointF center, float width, float height);
|
||||
void DrawRoundRectangle(QPainter& p, QPointF center, float width, float height, float round);
|
||||
void DrawText(QPainter& p, QPointF center, float text_size, const QString& text);
|
||||
void SetTextFont(QPainter& p, float text_size,
|
||||
const QString& font_family = QStringLiteral("sans-serif"));
|
||||
};
|
||||
} // namespace ControllerViewer
|
0
src/yuzu/util/controller_viewer/controller_base.cpp
Normal file
0
src/yuzu/util/controller_viewer/controller_base.cpp
Normal file
77
src/yuzu/util/controller_viewer/controller_base.h
Normal file
77
src/yuzu/util/controller_viewer/controller_base.h
Normal file
@ -0,0 +1,77 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <QColor>
|
||||
#include <QPainter>
|
||||
#include <QPointer>
|
||||
|
||||
#include "common/input.h"
|
||||
#include "common/settings_input.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
|
||||
namespace ControllerViewer {
|
||||
|
||||
using AnalogParam = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
|
||||
using ButtonParam = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
|
||||
|
||||
enum class Theme {
|
||||
White,
|
||||
Dark,
|
||||
Midnight,
|
||||
};
|
||||
|
||||
// Widget for representing controller animations
|
||||
class ControllerBase {
|
||||
struct ColorMapping {
|
||||
QColor outline{};
|
||||
QColor primary{};
|
||||
QColor left{};
|
||||
QColor right{};
|
||||
QColor button{};
|
||||
QColor button2{};
|
||||
QColor font{};
|
||||
QColor font2{};
|
||||
QColor highlight{};
|
||||
QColor highlight2{};
|
||||
QColor transparent{};
|
||||
QColor indicator{};
|
||||
QColor indicator2{};
|
||||
QColor led_on{};
|
||||
QColor led_off{};
|
||||
QColor slider{};
|
||||
QColor slider_button{};
|
||||
QColor slider_arrow{};
|
||||
QColor deadzone{};
|
||||
QColor charging{};
|
||||
};
|
||||
|
||||
void DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right);
|
||||
void DrawJoystickProperties(QPainter& p, QPointF center,
|
||||
const Common::Input::AnalogProperties& properties);
|
||||
|
||||
bool is_controller_set{};
|
||||
bool is_connected{};
|
||||
bool needs_redraw{};
|
||||
Core::HID::NpadStyleIndex controller_type;
|
||||
|
||||
bool mapping_active{};
|
||||
int blink_counter{};
|
||||
int callback_key;
|
||||
QColor button_color{};
|
||||
ColorMapping colors{};
|
||||
Core::HID::LedPattern led_pattern{0, 0, 0, 0};
|
||||
std::size_t player_index{};
|
||||
Core::HID::EmulatedController* controller;
|
||||
std::size_t button_mapping_index{Settings::NativeButton::NumButtons};
|
||||
std::size_t analog_mapping_index{Settings::NativeAnalog::NumAnalogs};
|
||||
Core::HID::ButtonValues button_values{};
|
||||
Core::HID::SticksValues stick_values{};
|
||||
Core::HID::TriggerValues trigger_values{};
|
||||
Core::HID::BatteryValues battery_values{};
|
||||
};
|
||||
|
||||
} // namespace ControllerViewer
|
112
src/yuzu/util/controller_viewer/controller_viewer.cpp
Normal file
112
src/yuzu/util/controller_viewer/controller_viewer.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright 2022 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <QMenu>
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "yuzu/util/controller_viewer/controller_viewer.h"
|
||||
|
||||
namespace ControllerViewer {
|
||||
ControllerViewer::ControllerViewer(QWidget* parent) : QFrame(parent) {
|
||||
is_controller_set = false;
|
||||
QTimer* timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout, this, QOverload<>::of(&ControllerViewer::UpdateInput));
|
||||
|
||||
// refresh at 60hz
|
||||
timer->start(16);
|
||||
}
|
||||
|
||||
ControllerViewer::~ControllerViewer() {
|
||||
UnloadController();
|
||||
};
|
||||
|
||||
void ControllerViewer::SetController(Core::HID::EmulatedController* controller_) {
|
||||
UnloadController();
|
||||
is_controller_set = true;
|
||||
controller = controller_;
|
||||
Core::HID::ControllerUpdateCallback engine_callback{
|
||||
.on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); },
|
||||
.is_npad_service = false,
|
||||
};
|
||||
callback_key = controller->SetCallback(engine_callback);
|
||||
ControllerUpdate(Core::HID::ControllerTriggerType::All);
|
||||
}
|
||||
|
||||
void ControllerViewer::UnloadController() {
|
||||
if (is_controller_set) {
|
||||
controller->DeleteCallback(callback_key);
|
||||
is_controller_set = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerViewer::BeginMappingButton(std::size_t button_id) {
|
||||
controller_view.BeginMappingButton(button_id);
|
||||
}
|
||||
|
||||
void ControllerViewer::BeginMappingAnalog(std::size_t stick_id) {
|
||||
controller_view.BeginMappingAnalog(stick_id);
|
||||
}
|
||||
|
||||
void ControllerViewer::EndMapping() {
|
||||
controller_view.EndMapping();
|
||||
}
|
||||
|
||||
void ControllerViewer::UpdateColors() {
|
||||
if (QIcon::themeName().contains(QStringLiteral("dark"))) {
|
||||
controller_view.UpdateColors(Theme::Midnight);
|
||||
return;
|
||||
}
|
||||
|
||||
if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
|
||||
controller_view.UpdateColors(Theme::Midnight);
|
||||
return;
|
||||
}
|
||||
|
||||
controller_view.UpdateColors(Theme::White);
|
||||
}
|
||||
|
||||
void ControllerViewer::ResetInputs() {
|
||||
controller_view.ResetInputs();
|
||||
}
|
||||
|
||||
void ControllerViewer::ControllerUpdate(Core::HID::ControllerTriggerType type) {
|
||||
if (type == Core::HID::ControllerTriggerType::All) {
|
||||
ControllerUpdate(Core::HID::ControllerTriggerType::Color);
|
||||
ControllerUpdate(Core::HID::ControllerTriggerType::Type);
|
||||
ControllerUpdate(Core::HID::ControllerTriggerType::Connected);
|
||||
ControllerUpdate(Core::HID::ControllerTriggerType::Button);
|
||||
ControllerUpdate(Core::HID::ControllerTriggerType::Stick);
|
||||
ControllerUpdate(Core::HID::ControllerTriggerType::Trigger);
|
||||
ControllerUpdate(Core::HID::ControllerTriggerType::Battery);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case Core::HID::ControllerTriggerType::Type:
|
||||
controller_type = controller->GetNpadStyleIndex(true);
|
||||
needs_redraw = true;
|
||||
break;
|
||||
default:
|
||||
controller_view.ControllerUpdate(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerViewer::UpdateInput() {
|
||||
controller_view.UpdateInput();
|
||||
}
|
||||
|
||||
void ControllerViewer::paintEvent(QPaintEvent* event) {
|
||||
QFrame::paintEvent(event);
|
||||
QPainter p(this);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
const QPointF center = rect().center();
|
||||
|
||||
controller_view.DrawController(p, center);
|
||||
}
|
||||
|
||||
} // namespace ControllerViewer
|
64
src/yuzu/util/controller_viewer/controller_viewer.h
Normal file
64
src/yuzu/util/controller_viewer/controller_viewer.h
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2022 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <QFrame>
|
||||
#include <QPointer>
|
||||
|
||||
#include "common/input.h"
|
||||
#include "common/settings_input.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "yuzu/util/controller_viewer/controller_base.h"
|
||||
|
||||
namespace ControllerViewer {
|
||||
|
||||
// Widget for representing controller animations
|
||||
class ControllerViewer : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ControllerViewer(QWidget* parent);
|
||||
~ControllerViewer() override;
|
||||
|
||||
// Sets the emulated controller to be displayed
|
||||
void SetController(Core::HID::EmulatedController* controller);
|
||||
|
||||
// Disables events from the emulated controller
|
||||
void UnloadController();
|
||||
|
||||
// Starts blinking animation at the button specified
|
||||
void BeginMappingButton(std::size_t button_id);
|
||||
|
||||
// Starts moving animation at the stick specified
|
||||
void BeginMappingAnalog(std::size_t stick_id);
|
||||
|
||||
// Stops any ongoing animation
|
||||
void EndMapping();
|
||||
|
||||
// Handles emulated controller events
|
||||
void ControllerUpdate(Core::HID::ControllerTriggerType type);
|
||||
|
||||
// Updates input on sheduled interval
|
||||
void UpdateInput();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
private:
|
||||
void UpdateColors();
|
||||
void ResetInputs();
|
||||
|
||||
bool is_controller_set{};
|
||||
bool is_connected{};
|
||||
bool needs_redraw{};
|
||||
|
||||
int callback_key;
|
||||
ControllerBase controller_view;
|
||||
Core::HID::EmulatedController* controller;
|
||||
};
|
||||
|
||||
} // namespace ControllerViewer
|
2134
src/yuzu/util/controller_viewer/pro_controller.cpp
Normal file
2134
src/yuzu/util/controller_viewer/pro_controller.cpp
Normal file
File diff suppressed because it is too large
Load Diff
28
src/yuzu/util/controller_viewer/pro_controller.h
Normal file
28
src/yuzu/util/controller_viewer/pro_controller.h
Normal file
@ -0,0 +1,28 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <QFrame>
|
||||
#include <QPointer>
|
||||
|
||||
#include "util\controller_viewer\controller_base.h"
|
||||
|
||||
// Widget for representing controller animations
|
||||
class ProController : public PlayerControllerBase {
|
||||
void UpdateColors();
|
||||
void ResetInputs();
|
||||
|
||||
void DrawProController(QPainter& p, QPointF center);
|
||||
|
||||
void DrawGCBody(QPainter& p, QPointF center);
|
||||
|
||||
// Draw triggers functions
|
||||
void DrawProTriggers(QPainter& p, QPointF center,
|
||||
const Common::Input::ButtonStatus& left_pressed,
|
||||
const Common::Input::ButtonStatus& right_pressed);
|
||||
|
||||
void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar,
|
||||
const Common::Input::ButtonStatus& pressed);
|
||||
};
|
Reference in New Issue
Block a user