diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index c55d900e27..05860ecb1d 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..7471b0f443 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 33e1e06cd7..b940987db0 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 32c81dc702..2860f442c7 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, 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() { 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 (std::size_t i = 0; i < player.motion_devices.size(); ++i) { + const auto& 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::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), + std::get<0>(default_param)) + .toBool(); + if (player_motion_device.config.empty()) { + player_motion_device.config = std::get<1>(default_param); + } + } } std::stable_partition( @@ -849,6 +876,16 @@ void Config::SavePlayerValues() { QString::fromStdString(player.analogs[i]), QString::fromStdString(default_param)); } + + for (std::size_t i = 0; i < player.motion_devices.size(); ++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), + 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 5cd2a5feb6..b49eb878b3 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, 2> default_motion_devices; private: void ReadValues();