From 6be642a118cc403c927c225493aba42432e92cda Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 9 Dec 2024 19:54:29 +0100 Subject: [PATCH 1/3] Qt: put preferences and about in native spots on MacOS (#676) --- src/panda_qt/main_window.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/panda_qt/main_window.cpp b/src/panda_qt/main_window.cpp index c30d23ca2..784e1176e 100644 --- a/src/panda_qt/main_window.cpp +++ b/src/panda_qt/main_window.cpp @@ -55,6 +55,8 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent) auto resumeAction = emulationMenu->addAction(tr("Resume")); auto resetAction = emulationMenu->addAction(tr("Reset")); auto configureAction = emulationMenu->addAction(tr("Configure")); + configureAction->setMenuRole(QAction::PreferencesRole); + connect(pauseAction, &QAction::triggered, this, [this]() { sendMessage(EmulatorMessage{.type = MessageType::Pause}); }); connect(resumeAction, &QAction::triggered, this, [this]() { sendMessage(EmulatorMessage{.type = MessageType::Resume}); }); connect(resetAction, &QAction::triggered, this, [this]() { sendMessage(EmulatorMessage{.type = MessageType::Reset}); }); @@ -75,7 +77,9 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent) connect(dumpDspFirmware, &QAction::triggered, this, &MainWindow::dumpDspFirmware); auto aboutAction = aboutMenu->addAction(tr("About Panda3DS")); + aboutAction->setMenuRole(QAction::AboutRole); connect(aboutAction, &QAction::triggered, this, &MainWindow::showAboutMenu); + setMenuBar(menuBar); emu->setOutputSize(screen->surfaceWidth, screen->surfaceHeight); From 79d24cba11768e0867ae71bd934098790e490bb1 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 10 Dec 2024 00:29:56 +0200 Subject: [PATCH 2/3] Make filesystem decent, part 1 (#677) --- include/fs/archive_base.hpp | 29 +++++++++++++++ src/core/fs/archive_card_spi.cpp | 2 +- src/core/fs/archive_ext_save_data.cpp | 45 +++++++++++++----------- src/core/fs/archive_ncch.cpp | 4 +-- src/core/fs/archive_save_data.cpp | 12 +++---- src/core/fs/archive_sdmc.cpp | 20 +++++------ src/core/fs/archive_self_ncch.cpp | 4 +-- src/core/fs/archive_system_save_data.cpp | 12 +++---- src/core/fs/archive_twl_photo.cpp | 2 +- src/core/fs/archive_twl_sound.cpp | 2 +- src/core/fs/archive_user_save_data.cpp | 18 ++++++---- src/core/services/service_manager.cpp | 1 + 12 files changed, 95 insertions(+), 56 deletions(-) diff --git a/include/fs/archive_base.hpp b/include/fs/archive_base.hpp index d899d1a6e..475ca50e9 100644 --- a/include/fs/archive_base.hpp +++ b/include/fs/archive_base.hpp @@ -90,6 +90,14 @@ struct FSPath { }; } } + + bool isUTF16() const { return type == PathType::UTF16; } + bool isASCII() const { return type == PathType::ASCII; } + bool isBinary() const { return type == PathType::Binary; } + // This is not called "isEmpty()" to make obvious that we're talking about an empty-type path, NOT an empty text path + bool isEmptyType() const { return type == PathType::Empty; } + + bool isTextPath() const { return isUTF16() || isASCII(); } }; struct FilePerms { @@ -259,6 +267,27 @@ class ArchiveBase { virtual std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0; ArchiveBase(Memory& mem) : mem(mem) {} + + bool isSafeTextPath(const FSPath& path) { + if (path.type == PathType::UTF16) { + return isPathSafe(path); + } else if (path.type == PathType::ASCII){ + return isPathSafe(path); + } + + Helpers::panic("ArchiveBase::IsSafeTextPath: Invalid path"); + } + + // Appends a 3DS path to an std::filesystem::path + void appendPath(std::filesystem::path& diskPath, const FSPath& guestPath) { + if (guestPath.type == PathType::UTF16) { + diskPath += std::filesystem::path(guestPath.utf16_string).make_preferred(); + } else if (guestPath.type == PathType::ASCII) { + diskPath += std::filesystem::path(guestPath.string).make_preferred(); + } else [[unlikely]] { + Helpers::panic("ArchiveBase::AppendPath: Invalid 3DS path"); + } + } }; struct ArchiveResource { diff --git a/src/core/fs/archive_card_spi.cpp b/src/core/fs/archive_card_spi.cpp index db1b5fded..965ae9822 100644 --- a/src/core/fs/archive_card_spi.cpp +++ b/src/core/fs/archive_card_spi.cpp @@ -26,7 +26,7 @@ FileDescriptor CardSPIArchive::openFile(const FSPath& path, const FilePerms& per } Rust::Result CardSPIArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Empty) { + if (!path.isEmptyType()) { Helpers::panic("Unimplemented path type for CardSPIArchive::OpenArchive"); } diff --git a/src/core/fs/archive_ext_save_data.cpp b/src/core/fs/archive_ext_save_data.cpp index 4b57f2457..2aaa157e2 100644 --- a/src/core/fs/archive_ext_save_data.cpp +++ b/src/core/fs/archive_ext_save_data.cpp @@ -7,12 +7,13 @@ HorizonResult ExtSaveDataArchive::createFile(const FSPath& path, u64 size) { if (size == 0) Helpers::panic("ExtSaveData file does not support size == 0"); - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) - Helpers::panic("Unsafe path in ExtSaveData::CreateFile"); + if (path.isTextPath()) { + if (!isSafeTextPath(path)) { + Helpers::panic("Unsafe path in ExtSaveData::OpenFile"); + } fs::path p = IOFile::getAppData() / backingFolder; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::exists(p)) return Result::FS::AlreadyExists; @@ -28,17 +29,17 @@ HorizonResult ExtSaveDataArchive::createFile(const FSPath& path, u64 size) { return Result::FS::FileTooLarge; } - Helpers::panic("ExtSaveDataArchive::OpenFile: Failed"); + Helpers::panic("ExtSaveDataArchive::CreateFile: Failed"); return Result::Success; } HorizonResult ExtSaveDataArchive::deleteFile(const FSPath& path) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) + if (path.isTextPath()) { + if (!isSafeTextPath(path)) Helpers::panic("Unsafe path in ExtSaveData::DeleteFile"); fs::path p = IOFile::getAppData() / backingFolder; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::is_directory(p)) { Helpers::panic("ExtSaveData::DeleteFile: Tried to delete directory"); @@ -65,15 +66,16 @@ HorizonResult ExtSaveDataArchive::deleteFile(const FSPath& path) { } FileDescriptor ExtSaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) + if (path.isTextPath()) { + if (!isSafeTextPath(path)) { Helpers::panic("Unsafe path in ExtSaveData::OpenFile"); + } if (perms.create()) Helpers::panic("[ExtSaveData] Can't open file with create flag"); fs::path p = IOFile::getAppData() / backingFolder; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::exists(p)) { // Return file descriptor if the file exists IOFile file(p.string().c_str(), "r+b"); // According to Citra, this ignores the OpenFlags field and always opens as r+b? TODO: Check @@ -88,7 +90,7 @@ FileDescriptor ExtSaveDataArchive::openFile(const FSPath& path, const FilePerms& } HorizonResult ExtSaveDataArchive::renameFile(const FSPath& oldPath, const FSPath& newPath) { - if (oldPath.type != PathType::UTF16 || newPath.type != PathType::UTF16) { + if (!oldPath.isUTF16() || !newPath.isUTF16()) { Helpers::panic("Invalid path type for ExtSaveData::RenameFile"); } @@ -125,15 +127,18 @@ HorizonResult ExtSaveDataArchive::renameFile(const FSPath& oldPath, const FSPath } HorizonResult ExtSaveDataArchive::createDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) { + if (path.isTextPath()) { + if (!isSafeTextPath(path)) { Helpers::panic("Unsafe path in ExtSaveData::OpenFile"); } fs::path p = IOFile::getAppData() / backingFolder; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); + + if (fs::is_directory(p)) { + return Result::FS::AlreadyExists; + } - if (fs::is_directory(p)) return Result::FS::AlreadyExists; if (fs::is_regular_file(p)) { Helpers::panic("File path passed to ExtSaveData::CreateDirectory"); } @@ -156,7 +161,7 @@ std::string ExtSaveDataArchive::getExtSaveDataPathFromBinary(const FSPath& path) } Rust::Result ExtSaveDataArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Binary || path.binary.size() != 12) { + if (!path.isBinary() || path.binary.size() != 12) { Helpers::panic("ExtSaveData accessed with an invalid path in OpenArchive"); } @@ -172,12 +177,12 @@ Rust::Result ExtSaveDataArchive::openArchive(const } Rust::Result ExtSaveDataArchive::openDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) + if (path.isTextPath()) { + if (!isSafeTextPath(path)) Helpers::panic("Unsafe path in ExtSaveData::OpenDirectory"); fs::path p = IOFile::getAppData() / backingFolder; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::is_regular_file(p)) { printf("ExtSaveData: OpenArchive used with a file path"); diff --git a/src/core/fs/archive_ncch.cpp b/src/core/fs/archive_ncch.cpp index d5a4bab5e..5844bbdae 100644 --- a/src/core/fs/archive_ncch.cpp +++ b/src/core/fs/archive_ncch.cpp @@ -32,7 +32,7 @@ HorizonResult NCCHArchive::deleteFile(const FSPath& path) { } FileDescriptor NCCHArchive::openFile(const FSPath& path, const FilePerms& perms) { - if (path.type != PathType::Binary || path.binary.size() != 20) { + if (!path.isBinary() || path.binary.size() != 20) { Helpers::panic("NCCHArchive::OpenFile: Invalid path"); } @@ -49,7 +49,7 @@ FileDescriptor NCCHArchive::openFile(const FSPath& path, const FilePerms& perms) } Rust::Result NCCHArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Binary || path.binary.size() != 16) { + if (!path.isBinary() || path.binary.size() != 16) { Helpers::panic("NCCHArchive::OpenArchive: Invalid path"); } diff --git a/src/core/fs/archive_save_data.cpp b/src/core/fs/archive_save_data.cpp index 0bdb9e01d..35bc93e4d 100644 --- a/src/core/fs/archive_save_data.cpp +++ b/src/core/fs/archive_save_data.cpp @@ -5,7 +5,7 @@ namespace fs = std::filesystem; HorizonResult SaveDataArchive::createFile(const FSPath& path, u64 size) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) Helpers::panic("Unsafe path in SaveData::CreateFile"); @@ -39,7 +39,7 @@ HorizonResult SaveDataArchive::createFile(const FSPath& path, u64 size) { } HorizonResult SaveDataArchive::createDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SaveData::OpenFile"); } @@ -63,7 +63,7 @@ HorizonResult SaveDataArchive::createDirectory(const FSPath& path) { } HorizonResult SaveDataArchive::deleteFile(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SaveData::DeleteFile"); } @@ -96,7 +96,7 @@ HorizonResult SaveDataArchive::deleteFile(const FSPath& path) { } FileDescriptor SaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SaveData::OpenFile"); } @@ -132,7 +132,7 @@ FileDescriptor SaveDataArchive::openFile(const FSPath& path, const FilePerms& pe } Rust::Result SaveDataArchive::openDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SaveData::OpenDirectory"); } @@ -193,7 +193,7 @@ void SaveDataArchive::format(const FSPath& path, const ArchiveBase::FormatInfo& } Rust::Result SaveDataArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Empty) { + if (!path.isEmptyType()) { Helpers::panic("Unimplemented path type for SaveData archive: %d\n", path.type); return Err(Result::FS::NotFoundInvalid); } diff --git a/src/core/fs/archive_sdmc.cpp b/src/core/fs/archive_sdmc.cpp index 97b02b9ed..f5f999f34 100644 --- a/src/core/fs/archive_sdmc.cpp +++ b/src/core/fs/archive_sdmc.cpp @@ -4,13 +4,13 @@ namespace fs = std::filesystem; HorizonResult SDMCArchive::createFile(const FSPath& path, u64 size) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) { + if (path.isTextPath()) { + if (!isSafeTextPath(path)) { Helpers::panic("Unsafe path in SDMC::CreateFile"); } fs::path p = IOFile::getAppData() / "SDMC"; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::exists(p)) { return Result::FS::AlreadyExists; @@ -39,13 +39,13 @@ HorizonResult SDMCArchive::createFile(const FSPath& path, u64 size) { } HorizonResult SDMCArchive::deleteFile(const FSPath& path) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) { + if (path.isTextPath()) { + if (!isSafeTextPath(path)) { Helpers::panic("Unsafe path in SDMC::DeleteFile"); } fs::path p = IOFile::getAppData() / "SDMC"; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::is_directory(p)) { Helpers::panic("SDMC::DeleteFile: Tried to delete directory"); @@ -171,13 +171,13 @@ Rust::Result SDMCArchive::openDirectory(const F return Err(Result::FS::UnexpectedFileOrDir); } - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) { + if (path.isTextPath()) { + if (!isSafeTextPath(path)) { Helpers::panic("Unsafe path in SDMC::OpenDirectory"); } fs::path p = IOFile::getAppData() / "SDMC"; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::is_regular_file(p)) { printf("SDMC: OpenDirectory used with a file path"); @@ -197,7 +197,7 @@ Rust::Result SDMCArchive::openDirectory(const F Rust::Result SDMCArchive::openArchive(const FSPath& path) { // TODO: Fail here if the SD is disabled in the connfig. - if (path.type != PathType::Empty) { + if (!path.isEmptyType()) { Helpers::panic("Unimplemented path type for SDMC::OpenArchive"); } diff --git a/src/core/fs/archive_self_ncch.cpp b/src/core/fs/archive_self_ncch.cpp index 9369152d5..4d73300c5 100644 --- a/src/core/fs/archive_self_ncch.cpp +++ b/src/core/fs/archive_self_ncch.cpp @@ -26,7 +26,7 @@ FileDescriptor SelfNCCHArchive::openFile(const FSPath& path, const FilePerms& pe return FileError; } - if (path.type != PathType::Binary || path.binary.size() != 12) { + if (!path.isBinary() || path.binary.size() != 12) { printf("Invalid SelfNCCH path type\n"); return FileError; } @@ -42,7 +42,7 @@ FileDescriptor SelfNCCHArchive::openFile(const FSPath& path, const FilePerms& pe } Rust::Result SelfNCCHArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Empty) { + if (!path.isEmptyType()) { Helpers::panic("Invalid path type for SelfNCCH archive: %d\n", path.type); return Err(Result::FS::NotFoundInvalid); } diff --git a/src/core/fs/archive_system_save_data.cpp b/src/core/fs/archive_system_save_data.cpp index 7cb454a25..038b2fc8e 100644 --- a/src/core/fs/archive_system_save_data.cpp +++ b/src/core/fs/archive_system_save_data.cpp @@ -4,7 +4,7 @@ namespace fs = std::filesystem; Rust::Result SystemSaveDataArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Binary) { + if (!path.isBinary()) { Helpers::panic("Unimplemented path type for SystemSaveData::OpenArchive"); } @@ -14,7 +14,7 @@ Rust::Result SystemSaveDataArchive::openArchive(con FileDescriptor SystemSaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) { // TODO: Validate this. Temporarily copied from SaveData archive - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SystemSaveData::OpenFile"); } @@ -50,7 +50,7 @@ FileDescriptor SystemSaveDataArchive::openFile(const FSPath& path, const FilePer } HorizonResult SystemSaveDataArchive::createFile(const FSPath& path, u64 size) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SystemSaveData::CreateFile"); } @@ -85,7 +85,7 @@ HorizonResult SystemSaveDataArchive::createFile(const FSPath& path, u64 size) { } HorizonResult SystemSaveDataArchive::createDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SystemSaveData::CreateDirectory"); } @@ -110,7 +110,7 @@ HorizonResult SystemSaveDataArchive::createDirectory(const FSPath& path) { HorizonResult SystemSaveDataArchive::deleteFile(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SystemSaveData::DeleteFile"); } @@ -143,7 +143,7 @@ HorizonResult SystemSaveDataArchive::deleteFile(const FSPath& path) { } Rust::Result SystemSaveDataArchive::openDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::warn("Unsafe path in SystemSaveData::OpenDirectory"); return Err(Result::FS::FileNotFoundAlt); diff --git a/src/core/fs/archive_twl_photo.cpp b/src/core/fs/archive_twl_photo.cpp index a1833c5cf..4d56a5d7e 100644 --- a/src/core/fs/archive_twl_photo.cpp +++ b/src/core/fs/archive_twl_photo.cpp @@ -26,7 +26,7 @@ FileDescriptor TWLPhotoArchive::openFile(const FSPath& path, const FilePerms& pe } Rust::Result TWLPhotoArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Empty) { + if (!path.isEmptyType()) { Helpers::panic("Unimplemented path type for TWLPhotoArchive::OpenArchive"); } diff --git a/src/core/fs/archive_twl_sound.cpp b/src/core/fs/archive_twl_sound.cpp index fbe98caf5..a5f86c322 100644 --- a/src/core/fs/archive_twl_sound.cpp +++ b/src/core/fs/archive_twl_sound.cpp @@ -26,7 +26,7 @@ FileDescriptor TWLSoundArchive::openFile(const FSPath& path, const FilePerms& pe } Rust::Result TWLSoundArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Empty) { + if (!path.isEmptyType()) { Helpers::panic("Unimplemented path type for TWLSoundArchive::OpenArchive"); } diff --git a/src/core/fs/archive_user_save_data.cpp b/src/core/fs/archive_user_save_data.cpp index cba9bff8a..dc5589548 100644 --- a/src/core/fs/archive_user_save_data.cpp +++ b/src/core/fs/archive_user_save_data.cpp @@ -6,13 +6,15 @@ namespace fs = std::filesystem; HorizonResult UserSaveDataArchive::createFile(const FSPath& path, u64 size) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) Helpers::panic("Unsafe path in UserSaveData::CreateFile"); fs::path p = IOFile::getAppData() / "SaveData"; p += fs::path(path.utf16_string).make_preferred(); - if (fs::exists(p)) return Result::FS::AlreadyExists; + if (fs::exists(p)) { + return Result::FS::AlreadyExists; + } IOFile file(p.string().c_str(), "wb"); @@ -37,8 +39,10 @@ HorizonResult UserSaveDataArchive::createFile(const FSPath& path, u64 size) { } HorizonResult UserSaveDataArchive::createDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) Helpers::panic("Unsafe path in UserSaveData::OpenFile"); + if (path.isUTF16()) { + if (!isPathSafe(path)) { + Helpers::panic("Unsafe path in UserSaveData::OpenFile"); + } fs::path p = IOFile::getAppData() / "SaveData"; p += fs::path(path.utf16_string).make_preferred(); @@ -56,7 +60,7 @@ HorizonResult UserSaveDataArchive::createDirectory(const FSPath& path) { } HorizonResult UserSaveDataArchive::deleteFile(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) Helpers::panic("Unsafe path in UserSaveData::DeleteFile"); fs::path p = IOFile::getAppData() / "SaveData"; @@ -87,7 +91,7 @@ HorizonResult UserSaveDataArchive::deleteFile(const FSPath& path) { } FileDescriptor UserSaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) Helpers::panic("Unsafe path in UserSaveData::OpenFile"); if (perms.raw == 0 || (perms.create() && !perms.write())) Helpers::panic("[UserSaveData] Unsupported flags for OpenFile"); @@ -119,7 +123,7 @@ FileDescriptor UserSaveDataArchive::openFile(const FSPath& path, const FilePerms } Rust::Result UserSaveDataArchive::openDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) Helpers::panic("Unsafe path in UserSaveData::OpenDirectory"); fs::path p = IOFile::getAppData() / "SaveData"; diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index 8fa88a001..e276cd23e 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -95,6 +95,7 @@ void ServiceManager::registerClient(u32 messagePointer) { // clang-format off static std::map serviceMap = { { "ac:u", KernelHandles::AC }, + { "ac:i", KernelHandles::AC }, { "act:a", KernelHandles::ACT }, { "act:u", KernelHandles::ACT }, { "am:app", KernelHandles::AM }, From 4ce0768ba1895cd288905242f947296fdb137808 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 10 Dec 2024 00:54:06 +0200 Subject: [PATCH 3/3] Qt: Handle mouse move events properly (#678) --- include/panda_qt/main_window.hpp | 3 ++ src/panda_qt/main_window.cpp | 57 +++++++++++++++++++------------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/include/panda_qt/main_window.hpp b/include/panda_qt/main_window.hpp index ed54ad84d..70e3ef755 100644 --- a/include/panda_qt/main_window.hpp +++ b/include/panda_qt/main_window.hpp @@ -146,12 +146,15 @@ class MainWindow : public QMainWindow { void closeEvent(QCloseEvent* event) override; void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; + void mousePressEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override; + void mouseMoveEvent(QMouseEvent* event) override; void loadLuaScript(const std::string& code); void reloadShader(const std::string& shader); void editCheat(u32 handle, const std::vector& cheat, const std::function& callback); void handleScreenResize(u32 width, u32 height); + void handleTouchscreenPress(QMouseEvent* event); }; diff --git a/src/panda_qt/main_window.cpp b/src/panda_qt/main_window.cpp index 784e1176e..881dc02d2 100644 --- a/src/panda_qt/main_window.cpp +++ b/src/panda_qt/main_window.cpp @@ -487,29 +487,14 @@ void MainWindow::keyReleaseEvent(QKeyEvent* event) { void MainWindow::mousePressEvent(QMouseEvent* event) { if (event->button() == Qt::MouseButton::LeftButton) { - const QPointF clickPos = event->globalPosition(); - const QPointF widgetPos = screen->mapFromGlobal(clickPos); - - // Press is inside the screen area - if (widgetPos.x() >= 0 && widgetPos.x() < screen->width() && widgetPos.y() >= 0 && widgetPos.y() < screen->height()) { - // Go from widget positions to [0, 400) for x and [0, 480) for y - uint x = (uint)std::round(widgetPos.x() / screen->width() * 400.f); - uint y = (uint)std::round(widgetPos.y() / screen->height() * 480.f); - - // Check if touch falls in the touch screen area - if (y >= 240 && y <= 480 && x >= 40 && x < 40 + 320) { - // Convert to 3DS coordinates - u16 x_converted = static_cast(x) - 40; - u16 y_converted = static_cast(y) - 240; - - EmulatorMessage message{.type = MessageType::PressTouchscreen}; - message.touchscreen.x = x_converted; - message.touchscreen.y = y_converted; - sendMessage(message); - } else { - sendMessage(EmulatorMessage{.type = MessageType::ReleaseTouchscreen}); - } - } + // We handle actual mouse press & movement logic inside the mouseMoveEvent handler + handleTouchscreenPress(event); + } +} + +void MainWindow::mouseMoveEvent(QMouseEvent* event) { + if (event->buttons().testFlag(Qt::MouseButton::LeftButton)) { + handleTouchscreenPress(event); } } @@ -519,6 +504,32 @@ void MainWindow::mouseReleaseEvent(QMouseEvent* event) { } } +void MainWindow::handleTouchscreenPress(QMouseEvent* event) { + const QPointF clickPos = event->globalPosition(); + const QPointF widgetPos = screen->mapFromGlobal(clickPos); + + // Press is inside the screen area + if (widgetPos.x() >= 0 && widgetPos.x() < screen->width() && widgetPos.y() >= 0 && widgetPos.y() < screen->height()) { + // Go from widget positions to [0, 400) for x and [0, 480) for y + uint x = (uint)std::round(widgetPos.x() / screen->width() * 400.f); + uint y = (uint)std::round(widgetPos.y() / screen->height() * 480.f); + + // Check if touch falls in the touch screen area + if (y >= 240 && y <= 480 && x >= 40 && x < 40 + 320) { + // Convert to 3DS coordinates + u16 x_converted = static_cast(x) - 40; + u16 y_converted = static_cast(y) - 240; + + EmulatorMessage message{.type = MessageType::PressTouchscreen}; + message.touchscreen.x = x_converted; + message.touchscreen.y = y_converted; + sendMessage(message); + } else { + sendMessage(EmulatorMessage{.type = MessageType::ReleaseTouchscreen}); + } + } +} + void MainWindow::loadLuaScript(const std::string& code) { EmulatorMessage message{.type = MessageType::LoadLuaScript};