From f03a1a878fa29ae4c679b3a9dfb366de724fd5dc Mon Sep 17 00:00:00 2001 From: anirudhb Date: Tue, 5 May 2020 14:06:57 -0700 Subject: [PATCH 1/4] hid: Motion controls --- src/core/hle/service/hid/controllers/npad.cpp | 87 +++++++++++++++++++ src/core/hle/service/hid/controllers/npad.h | 29 ++++++- src/core/settings.h | 6 ++ src/yuzu/configuration/config.cpp | 37 ++++++++ src/yuzu/configuration/config.h | 1 + 5 files changed, 157 insertions(+), 3 deletions(-) diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index c55d900e27..0531601e45 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -235,6 +235,11 @@ void Controller_NPad::OnLoadInputDevices() { std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, sticks[i].begin(), Input::CreateDevice); + std::transform(players[i].motion_devices.begin(), players[i].motion_devices.end(), + motion_devices[i].begin(), [](const Settings::MotionRaw& raw) { + return raw.enabled ? Input::CreateDevice(raw.config) + : nullptr; + }); } } @@ -338,6 +343,41 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* cur_entry.timestamp2 = cur_entry.timestamp; } + const std::array controller_sixaxes{ + &npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left, + &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right, + }; + + for (auto* sixaxis_sensor : controller_sixaxes) { + sixaxis_sensor->common.entry_count = 16; + sixaxis_sensor->common.total_entry_count = 17; + + const auto& last_entry = + sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; + + sixaxis_sensor->common.timestamp = core_timing.GetTicks(); + sixaxis_sensor->common.last_entry_index = + (sixaxis_sensor->common.last_entry_index + 1) % 17; + + auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; + + cur_entry.timestamp = last_entry.timestamp + 1; + cur_entry.timestamp2 = cur_entry.timestamp; + } + + // Try to read sixaxis sensor states + Common::Vec3f accel1, gyro1, accel2, gyro2; + if (sixaxis_sensors_enabled) { + const auto& device1 = motion_devices[i][0]; + if (device1) { + std::tie(accel1, gyro1) = device1->GetStatus(); + } + const auto& device2 = motion_devices[i][1]; + if (device2) { + std::tie(accel2, gyro2) = device2->GetStatus(); + } + } + const auto& controller_type = connected_controllers[i].type; if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { @@ -359,6 +399,19 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index]; auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; + auto& full_sixaxis_entry = + npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index]; + auto& handheld_sixaxis_entry = + npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index]; + auto& dual_left_sixaxis_entry = + npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index]; + auto& dual_right_sixaxis_entry = + npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index]; + auto& left_sixaxis_entry = + npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index]; + auto& right_sixaxis_entry = + npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index]; + libnx_entry.connection_status.raw = 0; switch (controller_type) { @@ -375,6 +428,11 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw; handheld_entry.pad.l_stick = pad_state.l_stick; handheld_entry.pad.r_stick = pad_state.r_stick; + + if (sixaxis_sensors_enabled && motion_devices[i][0]) { + handheld_sixaxis_entry.accel = accel1; + handheld_sixaxis_entry.gyro = gyro1; + } break; case NPadControllerType::JoyDual: dual_entry.connection_status.raw = 0; @@ -390,6 +448,20 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* dual_entry.pad.pad_states.raw = pad_state.pad_states.raw; dual_entry.pad.l_stick = pad_state.l_stick; dual_entry.pad.r_stick = pad_state.r_stick; + + if (sixaxis_sensors_enabled) { + if (motion_devices[i][0] && motion_devices[i][1]) { + // set both + dual_left_sixaxis_entry.accel = accel1; + dual_left_sixaxis_entry.gyro = gyro1; + dual_right_sixaxis_entry.accel = accel2; + dual_right_sixaxis_entry.gyro = gyro2; + } else if (motion_devices[i][0]) { + // set right + dual_right_sixaxis_entry.accel = accel1; + dual_right_sixaxis_entry.gyro = gyro1; + } + } break; case NPadControllerType::JoyLeft: left_entry.connection_status.raw = 0; @@ -398,6 +470,11 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* left_entry.pad.pad_states.raw = pad_state.pad_states.raw; left_entry.pad.l_stick = pad_state.l_stick; left_entry.pad.r_stick = pad_state.r_stick; + + if (sixaxis_sensors_enabled && motion_devices[i][0]) { + left_sixaxis_entry.accel = accel1; + left_sixaxis_entry.gyro = gyro1; + } break; case NPadControllerType::JoyRight: right_entry.connection_status.raw = 0; @@ -406,6 +483,11 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* right_entry.pad.pad_states.raw = pad_state.pad_states.raw; right_entry.pad.l_stick = pad_state.l_stick; right_entry.pad.r_stick = pad_state.r_stick; + + if (sixaxis_sensors_enabled && motion_devices[i][0]) { + right_sixaxis_entry.accel = accel1; + right_sixaxis_entry.gyro = gyro1; + } break; case NPadControllerType::Pokeball: pokeball_entry.connection_status.raw = 0; @@ -425,6 +507,11 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* main_controller.pad.pad_states.raw = pad_state.pad_states.raw; main_controller.pad.l_stick = pad_state.l_stick; main_controller.pad.r_stick = pad_state.r_stick; + + if (sixaxis_sensors_enabled && motion_devices[i][0]) { + full_sixaxis_entry.accel = accel1; + full_sixaxis_entry.gyro = gyro1; + } break; } diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 931f03430e..323cc394aa 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -236,6 +236,24 @@ private: }; static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size"); + struct SixAxisStates { + s64_le timestamp; + INSERT_PADDING_WORDS(2); + s64_le timestamp2; + Common::Vec3f accel{}; + Common::Vec3f gyro{}; + INSERT_PADDING_WORDS(3); + std::array orientation{}; + s64_le always_one{1}; + }; + static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size"); + + struct SixAxisGeneric { + CommonHeader common{}; + std::array sixaxis{}; + }; + static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size"); + enum class ColorReadError : u32_le { ReadOk = 0, ColorDoesntExist = 1, @@ -284,9 +302,12 @@ private: NPadGeneric pokeball_states; NPadGeneric libnx; // TODO(ogniK): Find out what this actually is, libnx seems to only be // relying on this for the time being - INSERT_PADDING_BYTES( - 0x708 * - 6); // TODO(ogniK): SixAxis states, require more information before implementation + SixAxisGeneric sixaxis_full; + SixAxisGeneric sixaxis_handheld; + SixAxisGeneric sixaxis_dual_left; + SixAxisGeneric sixaxis_dual_right; + SixAxisGeneric sixaxis_left; + SixAxisGeneric sixaxis_right; NPadDevice device_type; NPadProperties properties; INSERT_PADDING_WORDS(1); @@ -318,6 +339,8 @@ private: std::array, Settings::NativeAnalog::NUM_STICKS_HID>, 10> sticks; + std::array, 2>, 10> motion_devices; + bool sixaxis_sensors_enabled{true}; std::vector supported_npad_id_types{}; NpadHoldType hold_type{NpadHoldType::Vertical}; // Each controller should have their own styleset changed event diff --git a/src/core/settings.h b/src/core/settings.h index 163900f0be..6553f5eed8 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -324,11 +324,17 @@ enum class ControllerType { LeftJoycon, }; +struct MotionRaw { + bool enabled; + std::string config; +}; + struct PlayerInput { bool connected; ControllerType type; ButtonsRaw buttons; AnalogsRaw analogs; + std::array motion_devices; u32 body_color_right; u32 button_color_right; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 75c6cf20b2..e928d7a0f0 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -230,6 +230,13 @@ const std::array Config::default_hotkeys{{ }}; // clang-format on +const std::array Config::default_motion_devices{{ + {false, std::string("engine:cemuhookudp,address:127.0.0.1,port:26760,pad_index:0,cx:0.0,cy:0.0," + "cz:0.0,sensitivity:1.0")}, + {false, std::string("engine:cemuhookudp,address:127.0.0.1,port:26760,pad_index:0,cx:0.0,cy:0.0," + "cz:0.0,sensitivity:1.0")}, +}}; + void Config::ReadPlayerValues() { for (std::size_t p = 0; p < Settings::values.players.size(); ++p) { auto& player = Settings::values.players[p]; @@ -293,6 +300,26 @@ void Config::ReadPlayerValues() { player_analogs = default_param; } } + + for (int i = 0; i < player.motion_devices.size(); ++i) { + const Settings::MotionRaw& default_param = default_motion_devices[i]; + auto& player_motion_device = player.motion_devices[i]; + + player_motion_device.config = + qt_config + ->value(QStringLiteral("player_%1_motion_device%2").arg(p).arg(i), + QString::fromStdString(default_param.config)) + .toString() + .toStdString(); + player_motion_device.enabled = + qt_config + ->value(QStringLiteral("player_%1_motion_device%2/enabled").arg(p).arg(i), + default_param.enabled) + .toBool(); + if (player_motion_device.config.empty()) { + player_motion_device.config = default_param.config; + } + } } std::stable_partition( @@ -847,6 +874,16 @@ void Config::SavePlayerValues() { QString::fromStdString(player.analogs[i]), QString::fromStdString(default_param)); } + + for (int i = 0; i < player.motion_devices.size(); ++i) { + const Settings::MotionRaw& default_param = default_motion_devices[i]; + const Settings::MotionRaw& player_motion_device = player.motion_devices[i]; + WriteSetting(QStringLiteral("player_%1_motion_device%2").arg(p).arg(i), + QString::fromStdString(player_motion_device.config), + QString::fromStdString(default_param.config)); + WriteSetting(QStringLiteral("player_%1_motion_device%2/enabled").arg(p).arg(i), + player_motion_device.enabled); + } } } diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 5cd2a5feb6..959b8a9248 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -28,6 +28,7 @@ public: static const std::array default_keyboard_keys; static const std::array default_keyboard_mods; static const std::array default_hotkeys; + static const std::array default_motion_devices; private: void ReadValues(); From f47d53d0d074f555fd14c0deb8874d967ae2f36a Mon Sep 17 00:00:00 2001 From: anirudhb Date: Tue, 5 May 2020 14:22:56 -0700 Subject: [PATCH 2/4] Address nits --- src/yuzu/configuration/config.cpp | 26 +++++++++++++------------- src/yuzu/configuration/config.h | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index e928d7a0f0..a7d5803839 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -230,11 +230,11 @@ const std::array Config::default_hotkeys{{ }}; // clang-format on -const std::array Config::default_motion_devices{{ - {false, std::string("engine:cemuhookudp,address:127.0.0.1,port:26760,pad_index:0,cx:0.0,cy:0.0," - "cz:0.0,sensitivity:1.0")}, - {false, std::string("engine:cemuhookudp,address:127.0.0.1,port:26760,pad_index:0,cx:0.0,cy:0.0," - "cz:0.0,sensitivity:1.0")}, +const std::array, 2> Config::default_motion_devices{{ + {false, "engine:cemuhookudp,address:127.0.0.1,port:26760,pad_index:0,cx:0.0,cy:0.0," + "cz:0.0,sensitivity:1.0"}, + {false, "engine:cemuhookudp,address:127.0.0.1,port:26760,pad_index:0,cx:0.0,cy:0.0," + "cz:0.0,sensitivity:1.0"}, }}; void Config::ReadPlayerValues() { @@ -301,23 +301,23 @@ void Config::ReadPlayerValues() { } } - for (int i = 0; i < player.motion_devices.size(); ++i) { - const Settings::MotionRaw& default_param = default_motion_devices[i]; + for (std::size_t i = 0; i < player.motion_devices.size(); ++i) { + const std::pair& default_param = default_motion_devices[i]; auto& player_motion_device = player.motion_devices[i]; player_motion_device.config = qt_config ->value(QStringLiteral("player_%1_motion_device%2").arg(p).arg(i), - QString::fromStdString(default_param.config)) + QString::fromLocal8Bit(std::get<1>(default_param))) .toString() .toStdString(); player_motion_device.enabled = qt_config ->value(QStringLiteral("player_%1_motion_device%2/enabled").arg(p).arg(i), - default_param.enabled) + std::get<0>(default_param)) .toBool(); if (player_motion_device.config.empty()) { - player_motion_device.config = default_param.config; + player_motion_device.config = std::get<1>(default_param); } } } @@ -875,12 +875,12 @@ void Config::SavePlayerValues() { QString::fromStdString(default_param)); } - for (int i = 0; i < player.motion_devices.size(); ++i) { - const Settings::MotionRaw& default_param = default_motion_devices[i]; + for (std::size_t i = 0; i < player.motion_devices.size(); ++i) { + const std::pair& default_param = default_motion_devices[i]; const Settings::MotionRaw& player_motion_device = player.motion_devices[i]; WriteSetting(QStringLiteral("player_%1_motion_device%2").arg(p).arg(i), QString::fromStdString(player_motion_device.config), - QString::fromStdString(default_param.config)); + QString::fromLocal8Bit(std::get<1>(default_param))); WriteSetting(QStringLiteral("player_%1_motion_device%2/enabled").arg(p).arg(i), player_motion_device.enabled); } diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 959b8a9248..b49eb878b3 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -28,7 +28,7 @@ public: static const std::array default_keyboard_keys; static const std::array default_keyboard_mods; static const std::array default_hotkeys; - static const std::array default_motion_devices; + static const std::array, 2> default_motion_devices; private: void ReadValues(); From 7732ca18682ae261b929f2553a83f4e3ae6d20f6 Mon Sep 17 00:00:00 2001 From: Anirudh Balaji Date: Wed, 6 May 2020 11:37:18 -0700 Subject: [PATCH 3/4] Address nits (2) Co-authored-by: Mat M. --- src/yuzu/configuration/config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index a7d5803839..f1d2f3cb23 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -302,7 +302,7 @@ void Config::ReadPlayerValues() { } for (std::size_t i = 0; i < player.motion_devices.size(); ++i) { - const std::pair& default_param = default_motion_devices[i]; + const auto& default_param = default_motion_devices[i]; auto& player_motion_device = player.motion_devices[i]; player_motion_device.config = @@ -876,7 +876,7 @@ void Config::SavePlayerValues() { } for (std::size_t i = 0; i < player.motion_devices.size(); ++i) { - const std::pair& default_param = default_motion_devices[i]; + const auto& default_param = default_motion_devices[i]; const Settings::MotionRaw& player_motion_device = player.motion_devices[i]; WriteSetting(QStringLiteral("player_%1_motion_device%2").arg(p).arg(i), QString::fromStdString(player_motion_device.config), From 175f4eabb40fa06f839672afd9d61cfe7c972a8a Mon Sep 17 00:00:00 2001 From: Anirudh Balaji Date: Wed, 6 May 2020 17:54:37 -0700 Subject: [PATCH 4/4] Address nits (3) Co-authored-by: David <25727384+ogniK5377@users.noreply.github.com> --- src/core/hle/service/hid/controllers/npad.cpp | 2 +- src/core/hle/service/hid/controllers/npad.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 0531601e45..05860ecb1d 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -366,7 +366,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* } // Try to read sixaxis sensor states - Common::Vec3f accel1, gyro1, accel2, gyro2; + Common::Vec3f accel1{}, gyro1{}, accel2{}, gyro2{}; if (sixaxis_sensors_enabled) { const auto& device1 = motion_devices[i][0]; if (device1) { diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 323cc394aa..7471b0f443 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -237,9 +237,9 @@ private: static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size"); struct SixAxisStates { - s64_le timestamp; + s64_le timestamp{}; INSERT_PADDING_WORDS(2); - s64_le timestamp2; + s64_le timestamp2{}; Common::Vec3f accel{}; Common::Vec3f gyro{}; INSERT_PADDING_WORDS(3);