diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 88d90fdb1..5e591b8bd 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -594,6 +594,8 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { this->TouchPressed(x, y); } else if (event->button() == Qt::RightButton) { InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y()); + } else if (event->button() == Qt::MiddleButton) { + InputCommon::GetMotionEmu()->BeginLook(pos.x(), pos.y()); } emit MouseActivity(); } @@ -607,6 +609,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { const auto [x, y] = ScaleTouch(pos); this->TouchMoved(x, y); InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y()); + InputCommon::GetMotionEmu()->Look(pos.x(), pos.y()); emit MouseActivity(); } @@ -619,6 +622,8 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { this->TouchReleased(); else if (event->button() == Qt::RightButton) InputCommon::GetMotionEmu()->EndTilt(); + else if (event->button() == Qt::MiddleButton) + InputCommon::GetMotionEmu()->EndLook(); emit MouseActivity(); } diff --git a/src/citra_qt/configuration/configure_motion_touch.cpp b/src/citra_qt/configuration/configure_motion_touch.cpp index 508d883ce..7bf25624f 100644 --- a/src/citra_qt/configuration/configure_motion_touch.cpp +++ b/src/citra_qt/configuration/configure_motion_touch.cpp @@ -1,6 +1,6 @@ // Copyright 2018-2026 Citra Emulator Project / Azahar Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the misc/licenses/gplv2.txt file included. +// Licensed under GPLv3 or any later version +// Refer to the LICENSE.txt file included. #include #include @@ -76,7 +76,8 @@ void CalibrationConfigurationDialog::UpdateButtonText(const QString& text) { } constexpr std::array, 3> MotionProviders = {{ - {"motion_emu", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Mouse (Right Click)")}, + {"motion_emu", QT_TRANSLATE_NOOP("ConfigureMotionTouch", + "Mouse (Right Click for Tilt, Middle Click for Look)")}, {"cemuhookudp", "CemuhookUDP"}, {"sdl", "SDL"}, }}; diff --git a/src/input_common/motion_emu.cpp b/src/input_common/motion_emu.cpp index 700027088..35b774753 100644 --- a/src/input_common/motion_emu.cpp +++ b/src/input_common/motion_emu.cpp @@ -1,9 +1,10 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the misc/licenses/gplv2.txt file included. +// Copyright 2017-2026 Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv3 or any later version +// Refer to the LICENSE.txt file included. #include #include +#include #include #include #include @@ -34,9 +35,21 @@ public: void BeginTilt(int x, int y) { mouse_origin = Common::MakeVec(x, y); + std::lock_guard guard{tilt_mutex}; + look_direction = Common::MakeVec(0.0f, 0.0f); + look_mode = false; + is_looking = false; is_tilting = true; } + void BeginLook(int x, int y) { + look_origin = Common::MakeVec(x, y); + std::lock_guard guard{tilt_mutex}; + previous_look_direction = look_direction; + look_mode = true; + is_looking = true; + } + void Tilt(int x, int y) { auto mouse_move = Common::MakeVec(x, y) - mouse_origin; if (is_tilting) { @@ -51,12 +64,25 @@ public: } } + void Look(int x, int y) { + if (is_looking) { + const auto mouse_move = (Common::MakeVec(x, y) - look_origin).Cast(); + std::lock_guard guard{tilt_mutex}; + look_direction = previous_look_direction + mouse_move; + } + } + void EndTilt() { std::lock_guard guard{tilt_mutex}; tilt_angle = 0; is_tilting = false; } + void EndLook() { + std::lock_guard guard{tilt_mutex}; + is_looking = false; + } + std::tuple, Common::Vec3> GetStatus() { std::lock_guard guard{status_mutex}; return status; @@ -68,13 +94,18 @@ private: const float sensitivity; Common::Vec2 mouse_origin; + Common::Vec2 look_origin; std::mutex tilt_mutex; Common::Vec2 tilt_direction; + Common::Vec2 look_direction = Common::MakeVec(0.0f, 0.0f); + Common::Vec2 previous_look_direction = Common::MakeVec(0.0f, 0.0f); float tilt_angle = 0; float tilt_clamp = 90; bool is_tilting = false; + bool is_looking = false; + bool look_mode = false; Common::Event shutdown_event; @@ -87,7 +118,7 @@ private: void MotionEmuThread() { auto update_time = std::chrono::steady_clock::now(); - Common::Quaternion q = Common::MakeQuaternion(Common::Vec3(), 0); + Common::Quaternion q = {{0.0f, 0.0f, 0.0f}, 1.0f}; Common::Quaternion old_q; while (!shutdown_event.WaitUntil(update_time)) { @@ -97,9 +128,23 @@ private: { std::lock_guard guard{tilt_mutex}; - // Find the quaternion describing current 3DS tilting - q = Common::MakeQuaternion( - Common::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x), tilt_angle); + if (!look_mode) { + // Find the quaternion describing current 3DS tilting + q = Common::MakeQuaternion( + Common::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x), tilt_angle); + } else { + // Find the quaternion describing current 3DS looking + float p = + -1.0f * ((Common::PI * 0.25f) + + Common::PI * (-look_direction.y * sensitivity * 100.0f) / 360.0f); + float y = Common::PI * (-look_direction.x * sensitivity * 100.0f) / 360.0f; + float qw = std::cos(p) * std::cos(y); + float qx = std::sin(p) * std::cos(y); + float qy = std::cos(p) * std::sin(y); + float qz = -1.0f * std::sin(p) * std::sin(y); + + q = {Common::MakeVec(qx, qy, qz), qw}; + } } auto inv_q = q.Inverse(); @@ -158,16 +203,34 @@ void MotionEmu::BeginTilt(int x, int y) { } } +void MotionEmu::BeginLook(int x, int y) { + if (auto ptr = current_device.lock()) { + ptr->BeginLook(x, y); + } +} + void MotionEmu::Tilt(int x, int y) { if (auto ptr = current_device.lock()) { ptr->Tilt(x, y); } } +void MotionEmu::Look(int x, int y) { + if (auto ptr = current_device.lock()) { + ptr->Look(x, y); + } +} + void MotionEmu::EndTilt() { if (auto ptr = current_device.lock()) { ptr->EndTilt(); } } +void MotionEmu::EndLook() { + if (auto ptr = current_device.lock()) { + ptr->EndLook(); + } +} + } // namespace InputCommon diff --git a/src/input_common/motion_emu.h b/src/input_common/motion_emu.h index f94b0f90b..1a5432145 100644 --- a/src/input_common/motion_emu.h +++ b/src/input_common/motion_emu.h @@ -1,6 +1,6 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the misc/licenses/gplv2.txt file included. +// Copyright 2017-2026 Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv3 or any later version +// Refer to the LICENSE.txt file included. #pragma once @@ -21,7 +21,7 @@ public: std::unique_ptr Create(const Common::ParamPackage& params) override; /** - * Signals that a motion sensor tilt has begun. + * Signals that a motion sensor tilt has begun. This also leaves look mode. * @param x the x-coordinate of the cursor * @param y the y-coordinate of the cursor */ @@ -39,6 +39,27 @@ public: */ void EndTilt(); + /** + * Signals that a motion sensor look has begun. The device is held upright and the cursor + * movement rotates it in pitch and yaw, continuing from the previous look orientation. + * @param x the x-coordinate of the cursor + * @param y the y-coordinate of the cursor + */ + void BeginLook(int x, int y); + + /** + * Signals that a motion sensor look is occurring. + * @param x the x-coordinate of the cursor + * @param y the y-coordinate of the cursor + */ + void Look(int x, int y); + + /** + * Signals that a motion sensor look has ended. The look orientation is kept until the next + * tilt begins. + */ + void EndLook(); + private: std::weak_ptr current_device; };