diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/frontend/emu_window.h | 10 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/applet_cabinet.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/service/mii/types/ver3_store_data.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/service/nfc/common/device.cpp | 68 | ||||
-rw-r--r-- | src/core/hle/service/nfc/common/device.h | 1 | ||||
-rw-r--r-- | src/yuzu/bootmanager.cpp | 56 | ||||
-rw-r--r-- | src/yuzu/bootmanager.h | 6 | ||||
-rw-r--r-- | src/yuzu/main.cpp | 44 | ||||
-rw-r--r-- | src/yuzu/main.h | 3 |
9 files changed, 104 insertions, 88 deletions
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index a72df034e..c7b48a58d 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -167,6 +167,11 @@ protected: */ std::pair<f32, f32> MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const; + /** + * Clip the provided coordinates to be inside the touchscreen area. + */ + std::pair<u32, u32> ClipToTouchScreen(u32 new_x, u32 new_y) const; + WindowSystemInfo window_info; bool strict_context_required = false; @@ -181,11 +186,6 @@ private: // By default, ignore this request and do nothing. } - /** - * Clip the provided coordinates to be inside the touchscreen area. - */ - std::pair<u32, u32> ClipToTouchScreen(u32 new_x, u32 new_y) const; - Layout::FramebufferLayout framebuffer_layout; ///< Current framebuffer layout u32 client_area_width; ///< Current client width, should be set by window impl. diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index 9d1960cb7..3906c0fa4 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -131,7 +131,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) nfp_device->DeleteApplicationArea(); break; case Service::NFP::CabinetMode::StartRestorer: - nfp_device->RestoreAmiibo(); + nfp_device->Restore(); break; case Service::NFP::CabinetMode::StartFormatter: nfp_device->Format(); diff --git a/src/core/hle/service/mii/types/ver3_store_data.cpp b/src/core/hle/service/mii/types/ver3_store_data.cpp index a019cc9f7..c27646fcf 100644 --- a/src/core/hle/service/mii/types/ver3_store_data.cpp +++ b/src/core/hle/service/mii/types/ver3_store_data.cpp @@ -98,7 +98,7 @@ void Ver3StoreData::BuildToStoreData(StoreData& out_store_data) const { } void Ver3StoreData::BuildFromStoreData(const StoreData& store_data) { - version = 1; + version = 3; mii_information.gender.Assign(static_cast<u8>(store_data.GetGender())); mii_information.favorite_color.Assign(static_cast<u8>(store_data.GetFavoriteColor())); height = store_data.GetHeight(); diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp index e7a00deb3..47516f883 100644 --- a/src/core/hle/service/nfc/common/device.cpp +++ b/src/core/hle/service/nfc/common/device.cpp @@ -401,6 +401,12 @@ Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& time } Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target_) { + bool is_corrupted = false; + + if (model_type != NFP::ModelType::Amiibo) { + return ResultInvalidArgument; + } + if (device_state != DeviceState::TagFound) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); return ResultWrongDeviceState; @@ -420,26 +426,32 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target if (is_plain_amiibo) { std::vector<u8> data(sizeof(NFP::NTAG215File)); memcpy(data.data(), &tag_data, sizeof(tag_data)); - WriteBackupData(tag_data.uid, data); + } - device_state = DeviceState::TagMounted; - mount_target = mount_target_; - return ResultSuccess; + if (!is_plain_amiibo && !NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) { + LOG_ERROR(Service_NFP, "Can't decode amiibo"); + is_corrupted = true; } - if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) { - bool has_backup = HasBackup(encrypted_tag_data.uuid).IsSuccess(); - LOG_ERROR(Service_NFP, "Can't decode amiibo, has_backup= {}", has_backup); - return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData; + if (tag_data.settings.settings.amiibo_initialized && !tag_data.owner_mii.IsValid()) { + LOG_ERROR(Service_NFP, "Invalid mii data"); + is_corrupted = true; } - std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File)); - memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data)); - WriteBackupData(encrypted_tag_data.uuid, data); + if (!is_corrupted) { + std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File)); + memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data)); + WriteBackupData(encrypted_tag_data.uuid, data); + } device_state = DeviceState::TagMounted; mount_target = mount_target_; + if (is_corrupted) { + bool has_backup = HasBackup(encrypted_tag_data.uuid).IsSuccess(); + return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData; + } + return ResultSuccess; } @@ -606,6 +618,17 @@ Result NfcDevice::Restore() { } } + // Restore mii data in case is corrupted by previous instances of yuzu + if (tag_data.settings.settings.amiibo_initialized && !tag_data.owner_mii.IsValid()) { + LOG_ERROR(Service_NFP, "Regenerating mii data"); + Mii::StoreData new_mii{}; + new_mii.BuildRandom(Mii::Age::All, Mii::Gender::All, Mii::Race::All); + new_mii.SetNickname({u'y', u'u', u'z', u'u', u'\0'}); + + tag_data.owner_mii.BuildFromStoreData(new_mii); + tag_data.mii_extension.SetFromStoreData(new_mii); + } + // Overwrite tag contents with backup and mount the tag tag_data = temporary_tag_data; encrypted_tag_data = temporary_encrypted_tag_data; @@ -851,25 +874,6 @@ Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& registe return Flush(); } -Result NfcDevice::RestoreAmiibo() { - if (device_state != DeviceState::TagMounted) { - LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); - if (device_state == DeviceState::TagRemoved) { - return ResultTagRemoved; - } - return ResultWrongDeviceState; - } - - if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) { - LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); - return ResultWrongDeviceState; - } - - // TODO: Load amiibo from backup on system - LOG_ERROR(Service_NFP, "Not Implemented"); - return ResultSuccess; -} - Result NfcDevice::Format() { Result result = ResultSuccess; @@ -877,7 +881,9 @@ Result NfcDevice::Format() { result = Mount(NFP::ModelType::Amiibo, NFP::MountTarget::All); } - if (result.IsError()) { + // We are formatting all data. Corruption is not an issue. + if (result.IsError() && + (result != ResultCorruptedData && result != ResultCorruptedDataWithBackup)) { return result; } diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h index 0ed1ff34c..d8efe25ec 100644 --- a/src/core/hle/service/nfc/common/device.h +++ b/src/core/hle/service/nfc/common/device.h @@ -68,7 +68,6 @@ public: Result DeleteRegisterInfo(); Result SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info); - Result RestoreAmiibo(); Result Format(); Result OpenApplicationArea(u32 access_id); diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 2afa72140..ed5750155 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -30,7 +30,6 @@ #include <QSize> #include <QStringLiteral> #include <QSurfaceFormat> -#include <QTimer> #include <QWindow> #include <QtCore/qobjectdefs.h> @@ -66,6 +65,8 @@ class QObject; class QPaintEngine; class QSurface; +constexpr int default_mouse_constrain_timeout = 10; + EmuThread::EmuThread(Core::System& system) : m_system{system} {} EmuThread::~EmuThread() = default; @@ -304,6 +305,9 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, Qt::QueuedConnection); connect(this, &GRenderWindow::ExitSignal, parent, &GMainWindow::OnExit, Qt::QueuedConnection); connect(this, &GRenderWindow::TasPlaybackStateChanged, parent, &GMainWindow::OnTasStateChanged); + + mouse_constrain_timer.setInterval(default_mouse_constrain_timeout); + connect(&mouse_constrain_timer, &QTimer::timeout, this, &GRenderWindow::ConstrainMouse); } void GRenderWindow::ExecuteProgram(std::size_t program_index) { @@ -393,6 +397,22 @@ void GRenderWindow::closeEvent(QCloseEvent* event) { QWidget::closeEvent(event); } +void GRenderWindow::leaveEvent(QEvent* event) { + if (Settings::values.mouse_panning) { + const QRect& rect = QWidget::geometry(); + QPoint position = QCursor::pos(); + + qint32 x = qBound(rect.left(), position.x(), rect.right()); + qint32 y = qBound(rect.top(), position.y(), rect.bottom()); + // Only start the timer if the mouse has left the window bound. + // The leave event is also triggered when the window looses focus. + if (x != position.x() || y != position.y()) { + mouse_constrain_timer.start(); + } + event->accept(); + } +} + int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { static constexpr std::array<std::pair<Qt::Key, Settings::NativeKeyboard::Keys>, 106> key_map = { std::pair<Qt::Key, Settings::NativeKeyboard::Keys>{Qt::Key_A, Settings::NativeKeyboard::A}, @@ -658,10 +678,19 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { input_subsystem->GetMouse()->TouchMove(touch_x, touch_y); input_subsystem->GetMouse()->Move(pos.x(), pos.y(), center_x, center_y); + // Center mouse for mouse panning if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); } + // Constrain mouse for mouse emulation with mouse panning + if (Settings::values.mouse_panning && Settings::values.mouse_enabled) { + const auto [clamped_mouse_x, clamped_mouse_y] = ClipToTouchScreen(x, y); + QCursor::setPos(mapToGlobal( + QPoint{static_cast<int>(clamped_mouse_x), static_cast<int>(clamped_mouse_y)})); + } + + mouse_constrain_timer.stop(); emit MouseActivity(); } @@ -675,6 +704,31 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { input_subsystem->GetMouse()->ReleaseButton(button); } +void GRenderWindow::ConstrainMouse() { + if (emu_thread == nullptr || !Settings::values.mouse_panning) { + mouse_constrain_timer.stop(); + return; + } + if (!this->isActiveWindow()) { + mouse_constrain_timer.stop(); + return; + } + + if (Settings::values.mouse_enabled) { + const auto pos = mapFromGlobal(QCursor::pos()); + const int new_pos_x = std::clamp(pos.x(), 0, width()); + const int new_pos_y = std::clamp(pos.y(), 0, height()); + + QCursor::setPos(mapToGlobal(QPoint{new_pos_x, new_pos_y})); + return; + } + + const int center_x = width() / 2; + const int center_y = height() / 2; + + QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); +} + void GRenderWindow::wheelEvent(QWheelEvent* event) { const int x = event->angleDelta().x(); const int y = event->angleDelta().y(); diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 87b23df12..60edd464c 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -17,6 +17,7 @@ #include <QString> #include <QStringList> #include <QThread> +#include <QTimer> #include <QWidget> #include <qglobal.h> #include <qnamespace.h> @@ -38,7 +39,6 @@ class QMouseEvent; class QObject; class QResizeEvent; class QShowEvent; -class QTimer; class QTouchEvent; class QWheelEvent; @@ -166,6 +166,7 @@ public: std::pair<u32, u32> ScaleTouch(const QPointF& pos) const; void closeEvent(QCloseEvent* event) override; + void leaveEvent(QEvent* event) override; void resizeEvent(QResizeEvent* event) override; @@ -229,6 +230,7 @@ private: void TouchBeginEvent(const QTouchEvent* event); void TouchUpdateEvent(const QTouchEvent* event); void TouchEndEvent(); + void ConstrainMouse(); void RequestCameraCapture(); void OnCameraCapture(int requestId, const QImage& img); @@ -268,6 +270,8 @@ private: std::unique_ptr<QTimer> camera_timer; #endif + QTimer mouse_constrain_timer; + Core::System& system; protected: diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index dcf68460a..31aabb78a 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -187,7 +187,6 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; #endif constexpr int default_mouse_hide_timeout = 2500; -constexpr int default_mouse_center_timeout = 10; constexpr int default_input_update_timeout = 1; constexpr size_t CopyBufferSize = 1_MiB; @@ -437,9 +436,6 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor); connect(ui->menubar, &QMenuBar::hovered, this, &GMainWindow::ShowMouseCursor); - mouse_center_timer.setInterval(default_mouse_center_timeout); - connect(&mouse_center_timer, &QTimer::timeout, this, &GMainWindow::CenterMouseCursor); - update_input_timer.setInterval(default_input_update_timeout); connect(&update_input_timer, &QTimer::timeout, this, &GMainWindow::UpdateInputDrivers); update_input_timer.start(); @@ -1376,14 +1372,6 @@ void GMainWindow::InitializeHotkeys() { } }); connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] { - if (Settings::values.mouse_enabled) { - Settings::values.mouse_panning = false; - QMessageBox::warning( - this, tr("Emulated mouse is enabled"), - tr("Real mouse input and mouse panning are incompatible. Please disable the " - "emulated mouse in input advanced settings to allow mouse panning.")); - return; - } Settings::values.mouse_panning = !Settings::values.mouse_panning; if (Settings::values.mouse_panning) { render_window->installEventFilter(render_window); @@ -4711,26 +4699,10 @@ void GMainWindow::ShowMouseCursor() { } } -void GMainWindow::CenterMouseCursor() { - if (emu_thread == nullptr || !Settings::values.mouse_panning) { - mouse_center_timer.stop(); - return; - } - if (!this->isActiveWindow()) { - mouse_center_timer.stop(); - return; - } - const int center_x = render_window->width() / 2; - const int center_y = render_window->height() / 2; - - QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); -} - void GMainWindow::OnMouseActivity() { if (!Settings::values.mouse_panning) { ShowMouseCursor(); } - mouse_center_timer.stop(); } void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { @@ -5031,22 +5003,6 @@ void GMainWindow::dragMoveEvent(QDragMoveEvent* event) { AcceptDropEvent(event); } -void GMainWindow::leaveEvent(QEvent* event) { - if (Settings::values.mouse_panning) { - const QRect& rect = geometry(); - QPoint position = QCursor::pos(); - - qint32 x = qBound(rect.left(), position.x(), rect.right()); - qint32 y = qBound(rect.top(), position.y(), rect.bottom()); - // Only start the timer if the mouse has left the window bound. - // The leave event is also triggered when the window looses focus. - if (x != position.x() || y != position.y()) { - mouse_center_timer.start(); - } - event->accept(); - } -} - bool GMainWindow::ConfirmChangeGame() { if (emu_thread == nullptr) return true; diff --git a/src/yuzu/main.h b/src/yuzu/main.h index e99d58995..733d6291e 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -451,7 +451,6 @@ private: void UpdateInputDrivers(); void HideMouseCursor(); void ShowMouseCursor(); - void CenterMouseCursor(); void OpenURL(const QUrl& url); void LoadTranslation(); void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); @@ -535,7 +534,6 @@ private: bool auto_paused = false; bool auto_muted = false; QTimer mouse_hide_timer; - QTimer mouse_center_timer; QTimer update_input_timer; QString startup_icon_theme; @@ -592,5 +590,4 @@ protected: void dropEvent(QDropEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override; void dragMoveEvent(QDragMoveEvent* event) override; - void leaveEvent(QEvent* event) override; }; |