From dcccf28bde819397cceccd6f101f76b224787293 Mon Sep 17 00:00:00 2001 From: BearOso Date: Tue, 30 Apr 2024 16:28:45 -0500 Subject: [PATCH] Qt: Add mouse support. --- qt/src/EmuApplication.cpp | 20 +++++++++++++++++ qt/src/EmuApplication.hpp | 2 ++ qt/src/EmuBinding.hpp | 6 ++++- qt/src/EmuMainWindow.cpp | 45 +++++++++++++++++++++++++++++++++++-- qt/src/EmuMainWindow.hpp | 2 ++ qt/src/Snes9xController.cpp | 27 ++++++++++++++++++++++ qt/src/Snes9xController.hpp | 4 +++- 7 files changed, 102 insertions(+), 4 deletions(-) diff --git a/qt/src/EmuApplication.cpp b/qt/src/EmuApplication.cpp index 477a0b91..9b6668cb 100644 --- a/qt/src/EmuApplication.cpp +++ b/qt/src/EmuApplication.cpp @@ -370,6 +370,12 @@ void EmuApplication::handleBinding(std::string name, bool pressed) memcpy(config->binding.controller[1].buttons, temp, sizeof(temp)); updateBindings(); } + else if (name == "GrabMouse") + { + if (config->port_configuration == EmuConfig::eMousePlusController || + config->port_configuration == EmuConfig::eSuperScopePlusController) + window->toggleMouseGrab(); + } } } @@ -466,6 +472,20 @@ void EmuApplication::pollJoysticks() } } +void EmuApplication::reportPointer(int x, int y) +{ + emu_thread->runOnThread([&, x, y] { + core->reportPointer(x, y); + }); +} + +void EmuApplication::reportMouseButton(int button, bool pressed) +{ + emu_thread->runOnThread([&, button, pressed] { + core->reportMouseButton(button, pressed); + }); +} + void EmuApplication::startInputTimer() { poll_input_timer = std::make_unique(); diff --git a/qt/src/EmuApplication.hpp b/qt/src/EmuApplication.hpp index 115fa7fa..d23ac9e5 100644 --- a/qt/src/EmuApplication.hpp +++ b/qt/src/EmuApplication.hpp @@ -62,6 +62,8 @@ struct EmuApplication void reportBinding(EmuBinding b, bool active); void startInputTimer(); void pollJoysticks(); + void reportPointer(int x, int y); + void reportMouseButton(int button, bool pressed); void restartAudio(); void writeSamples(int16_t *data, int samples); void mainLoop(); diff --git a/qt/src/EmuBinding.hpp b/qt/src/EmuBinding.hpp index ed2a7f3d..2925bf51 100644 --- a/qt/src/EmuBinding.hpp +++ b/qt/src/EmuBinding.hpp @@ -2,7 +2,6 @@ #define __EMU_BINDING_HPP #include #include -#include struct EmuBinding { @@ -16,6 +15,11 @@ struct EmuBinding std::string to_config_string(); bool operator==(const EmuBinding &); + static const uint32_t MOUSE_POINTER = 0x0f000000; + static const uint32_t MOUSE_BUTTON1 = 0x0f000001; + static const uint32_t MOUSE_BUTTON2 = 0x0f000002; + static const uint32_t MOUSE_BUTTON3 = 0x0f000003; + enum Type { None = 0, diff --git a/qt/src/EmuMainWindow.cpp b/qt/src/EmuMainWindow.cpp index 9460f98c..83bc36c9 100644 --- a/qt/src/EmuMainWindow.cpp +++ b/qt/src/EmuMainWindow.cpp @@ -526,6 +526,8 @@ bool EmuMainWindow::event(QEvent *event) } break; case QEvent::WindowDeactivate: + if (mouse_grabbed) + toggleMouseGrab(); if (app->config->pause_emulation_when_unfocused && !focus_pause) { focus_pause = true; @@ -548,10 +550,27 @@ bool EmuMainWindow::event(QEvent *event) break; } + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + { + if (!mouse_grabbed) + break; + auto mouse_event = (QMouseEvent *)event; + app->reportMouseButton(mouse_event->button(), event->type() == QEvent::MouseButtonPress); + break; + } case QEvent::MouseMove: + if (mouse_grabbed) + { + auto center = mapToGlobal(rect().center()); + auto pos = QCursor::pos(); + auto delta = pos - center; + app->reportPointer(delta.x(), delta.y()); + QCursor::setPos(center); + } if (!cursor_visible) { - if (canvas) + if (canvas && !mouse_grabbed) canvas->setCursor(QCursor(Qt::ArrowCursor)); cursor_visible = true; mouse_timer.start(); @@ -584,6 +603,7 @@ void EmuMainWindow::toggleFullscreen() app->config->setVRRConfig(true); app->updateSettings(); } + QCursor::setPos(mapToGlobal(rect().center())); showFullScreen(); menuBar()->setVisible(false); setBypassCompositor(true); @@ -620,7 +640,13 @@ bool EmuMainWindow::eventFilter(QObject *watched, QEvent *event) auto key_event = (QKeyEvent *)event; - if (isFullScreen() && key_event->key() == Qt::Key_Escape) + if (mouse_grabbed && key_event->key() == Qt::Key_Escape && event->type() == QEvent::KeyPress) + { + toggleMouseGrab(); + return true; + } + + if (isFullScreen() && key_event->key() == Qt::Key_Escape && event->type() == QEvent::KeyPress) { toggleFullscreen(); return true; @@ -695,4 +721,19 @@ void EmuMainWindow::gameChanging() { if (cheats_dialog) cheats_dialog->close(); +} + +void EmuMainWindow::toggleMouseGrab() +{ + mouse_grabbed = !mouse_grabbed; + + if (mouse_grabbed) + { + canvas->setCursor(QCursor(Qt::CursorShape::BlankCursor)); + QCursor::setPos(mapToGlobal(rect().center())); + } + else + { + canvas->setCursor(QCursor(Qt::CursorShape::ArrowCursor)); + } } \ No newline at end of file diff --git a/qt/src/EmuMainWindow.hpp b/qt/src/EmuMainWindow.hpp index c00b09cb..687b229b 100644 --- a/qt/src/EmuMainWindow.hpp +++ b/qt/src/EmuMainWindow.hpp @@ -37,6 +37,7 @@ class EmuMainWindow : public QMainWindow void recreateUIAssets(); void shaderChanged(); void gameChanging(); + void toggleMouseGrab(); std::vector getDisplayDeviceList(); EmuApplication *app; EmuCanvas *canvas; @@ -54,6 +55,7 @@ class EmuMainWindow : public QMainWindow bool focus_pause = false; bool minimized_pause = false; bool using_stacked_widget = false; + bool mouse_grabbed = false; QMenu *load_state_menu; QMenu *save_state_menu; QMenu *recent_menu; diff --git a/qt/src/Snes9xController.cpp b/qt/src/Snes9xController.cpp index efe533ae..83373e23 100644 --- a/qt/src/Snes9xController.cpp +++ b/qt/src/Snes9xController.cpp @@ -663,6 +663,21 @@ void Snes9xController::updateBindings(const EmuConfig *const config) S9xMapButton(binding.hash(), command, false); } } + + auto cmd = S9xGetCommandT("Pointer Mouse1+Superscope+Justifier1"); + S9xMapPointer(EmuBinding::MOUSE_POINTER, cmd, false); + mouse_x = mouse_y = 0; + S9xReportPointer(EmuBinding::MOUSE_POINTER, mouse_x, mouse_y); + + cmd = S9xGetCommandT("{Mouse1 L,Superscope Fire,Justifier1 Trigger}"); + S9xMapButton(EmuBinding::MOUSE_BUTTON1, cmd, false); + + cmd = S9xGetCommandT("{Justifier1 AimOffscreen Trigger,Superscope AimOffscreen}"); + S9xMapButton(EmuBinding::MOUSE_BUTTON3, cmd, false); + + cmd = S9xGetCommandT("{Mouse1 R,Superscope Cursor,Justifier1 Start}"); + S9xMapButton(EmuBinding::MOUSE_BUTTON2, cmd, false); + } void Snes9xController::reportBinding(EmuBinding b, bool active) @@ -670,6 +685,18 @@ void Snes9xController::reportBinding(EmuBinding b, bool active) S9xReportButton(b.hash(), active); } +void Snes9xController::reportMouseButton(int button, bool pressed) +{ + S9xReportButton(EmuBinding::MOUSE_POINTER + button, pressed); +} + +void Snes9xController::reportPointer(int x, int y) +{ + mouse_x += x; + mouse_y += y; + S9xReportPointer(EmuBinding::MOUSE_POINTER, mouse_x, mouse_y); +} + static fs::path save_slot_path(int slot) { std::string extension = std::to_string(slot); diff --git a/qt/src/Snes9xController.hpp b/qt/src/Snes9xController.hpp index 9948062c..fac58945 100644 --- a/qt/src/Snes9xController.hpp +++ b/qt/src/Snes9xController.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include "EmuConfig.hpp" @@ -27,6 +26,8 @@ class Snes9xController void updateSettings(const EmuConfig * const config); void updateBindings(const EmuConfig * const config); void reportBinding(EmuBinding b, bool active); + void reportMouseButton(int button, bool pressed); + void reportPointer(int x, int y); void updateSoundBufferLevel(int, int); bool acceptsCommand(const char *command); bool isAbnormalSpeed(); @@ -54,6 +55,7 @@ class Snes9xController std::string cheat_folder; std::string patch_folder; std::string export_folder; + int16_t mouse_x, mouse_y; int high_resolution_effect; int rewind_buffer_size; int rewind_frame_interval;