From d1cde4d0a758ee3729dd419f113c8e83b04d89c9 Mon Sep 17 00:00:00 2001 From: Robbie Date: Wed, 12 Jul 2017 09:07:40 -0500 Subject: [PATCH] Perform refactoring of pads to remove the ugly pad initialization. --- rpcs3/basic_keyboard_handler.cpp | 28 ++++++++++--- rpcs3/basic_keyboard_handler.h | 7 ++-- rpcs3/basic_mouse_handler.cpp | 28 ++++++++++--- rpcs3/basic_mouse_handler.h | 6 ++- rpcs3/keyboard_pad_handler.cpp | 27 ++++++++++-- rpcs3/keyboard_pad_handler.h | 7 ++-- rpcs3/rpcs3_app.cpp | 70 ++++++++++++++++++++------------ rpcs3/rpcs3_app.h | 7 +--- 8 files changed, 127 insertions(+), 53 deletions(-) diff --git a/rpcs3/basic_keyboard_handler.cpp b/rpcs3/basic_keyboard_handler.cpp index 53ba5e79c3..aeee594934 100644 --- a/rpcs3/basic_keyboard_handler.cpp +++ b/rpcs3/basic_keyboard_handler.cpp @@ -1,5 +1,6 @@ #include "basic_keyboard_handler.h" +#include #include void basic_keyboard_handler::Init(const u32 max_connect) @@ -17,16 +18,33 @@ void basic_keyboard_handler::Init(const u32 max_connect) m_info.status[0] = CELL_KB_STATUS_CONNECTED; // (TODO: Support for more keyboards) } -basic_keyboard_handler::basic_keyboard_handler(QObject* target, QObject* parent) : QObject(parent), m_target(target) +basic_keyboard_handler::basic_keyboard_handler() : QObject() { - // Adds event filter to the target to filter keyevents. - target->installEventFilter(this); } +/* Sets the target window for the event handler, and also installs an event filter on the target. */ +void basic_keyboard_handler::SetTargetWindow(QWindow* target) +{ + if (target != nullptr) + { + m_target = target; + target->installEventFilter(this); + } + else + { + // If this is hit, it probably means that some refactoring occurs because currently a gsframe is created in Load. + // We still want events so filter from application instead since target is null. + QApplication::instance()->installEventFilter(this); + LOG_ERROR(GENERAL, "Trying to set keyboard handler to a null target window."); + } +} + + bool basic_keyboard_handler::eventFilter(QObject* target, QEvent* ev) { - // Commenting target since I don't know how to target game window yet. - //if (target == m_target) + // !m_target is for future proofing when gsrender isn't automatically initialized on load. + // !m_target->isVisible() is a hack since currently a guiless application will STILL inititialize a gsrender (providing a valid target) + if (!m_target || !m_target->isVisible() || target == m_target) { if (ev->type() == QEvent::KeyPress) { diff --git a/rpcs3/basic_keyboard_handler.h b/rpcs3/basic_keyboard_handler.h index ca8414c754..e86f293384 100644 --- a/rpcs3/basic_keyboard_handler.h +++ b/rpcs3/basic_keyboard_handler.h @@ -3,8 +3,8 @@ #include "stdafx.h" #include "Emu/Io/KeyboardHandler.h" -#include #include +#include class basic_keyboard_handler final : public QObject, public KeyboardHandlerBase { @@ -12,12 +12,13 @@ class basic_keyboard_handler final : public QObject, public KeyboardHandlerBase public: virtual void Init(const u32 max_connect) override; - explicit basic_keyboard_handler(QObject* target = nullptr, QObject* parent = nullptr); + explicit basic_keyboard_handler(); + void SetTargetWindow(QWindow* target); bool eventFilter(QObject* obj, QEvent* ev); void keyPressEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event); void LoadSettings(); private: - QObject* m_target; + QWindow* m_target = nullptr; }; diff --git a/rpcs3/basic_mouse_handler.cpp b/rpcs3/basic_mouse_handler.cpp index ee33db3a61..721f40a4f8 100644 --- a/rpcs3/basic_mouse_handler.cpp +++ b/rpcs3/basic_mouse_handler.cpp @@ -1,5 +1,7 @@ #include "basic_mouse_handler.h" +#include + void basic_mouse_handler::Init(const u32 max_connect) { m_mice.emplace_back(Mouse()); @@ -13,15 +15,31 @@ void basic_mouse_handler::Init(const u32 max_connect) m_info.product_id[0] = 0x1234; } -basic_mouse_handler::basic_mouse_handler(QObject* target, QObject* parent) : QObject(parent), m_target(target) +basic_mouse_handler::basic_mouse_handler() : QObject() +{} + +/* Sets the target window for the event handler, and also installs an event filter on the target. */ +void basic_mouse_handler::SetTargetWindow(QWindow* target) { - target->installEventFilter(this); + if (target != nullptr) + { + m_target = target; + target->installEventFilter(this); + } + else + { + // If this is hit, it probably means that some refactoring occurs because currently a gsframe is created in Load. + // We still want events so filter from application instead since target is null. + QApplication::instance()->installEventFilter(this); + LOG_ERROR(GENERAL, "Trying to set mouse handler to a null target window."); + } } -bool basic_mouse_handler::eventFilter(QObject* obj, QEvent* ev) +bool basic_mouse_handler::eventFilter(QObject* target, QEvent* ev) { - // Commenting target since I don't know how to target game window yet. - //if (m_target == obj) + // !m_target is for future proofing when gsrender isn't automatically initialized on load to ensure events still occur + // !m_target->isVisible() is a hack since currently a guiless application will STILL inititialize a gsrender (providing a valid target) + if (!m_target || !m_target->isVisible() || target == m_target) { switch (ev->type()) { diff --git a/rpcs3/basic_mouse_handler.h b/rpcs3/basic_mouse_handler.h index 9c3a95c3ae..7caea23c23 100644 --- a/rpcs3/basic_mouse_handler.h +++ b/rpcs3/basic_mouse_handler.h @@ -3,6 +3,7 @@ #include "stdafx.h" #include "Emu/Io/MouseHandler.h" +#include #include #include @@ -12,8 +13,9 @@ class basic_mouse_handler final : public QObject, public MouseHandlerBase public: virtual void Init(const u32 max_connect) override; - basic_mouse_handler(QObject* target, QObject* parent); + basic_mouse_handler(); + void SetTargetWindow(QWindow* target); void MouseButtonDown(QMouseEvent* event); void MouseButtonUp(QMouseEvent* event); void MouseScroll(QWheelEvent* event); @@ -21,5 +23,5 @@ public: bool eventFilter(QObject* obj, QEvent* ev); private: - QObject* m_target; + QWindow* m_target = nullptr; }; diff --git a/rpcs3/keyboard_pad_handler.cpp b/rpcs3/keyboard_pad_handler.cpp index fa942ac9ec..53814b3f80 100644 --- a/rpcs3/keyboard_pad_handler.cpp +++ b/rpcs3/keyboard_pad_handler.cpp @@ -2,6 +2,8 @@ #include "keyboard_pad_handler.h" +#include + keyboard_pad_config g_kbpad_config; void keyboard_pad_handler::Init(const u32 max_connect) @@ -12,15 +14,15 @@ void keyboard_pad_handler::Init(const u32 max_connect) m_info.now_connect = std::min(m_pads.size(), (size_t)max_connect); } -keyboard_pad_handler::keyboard_pad_handler(QObject* target, QObject* parent) : QObject(parent), m_target(target) +keyboard_pad_handler::keyboard_pad_handler() : QObject() { - target->installEventFilter(this); } bool keyboard_pad_handler::eventFilter(QObject* target, QEvent* ev) { - // Commenting target since I don't know how to target game window yet. - //if (target == m_target) + // !m_target is for future proofing when gsrender isn't automatically initialized on load. + // !m_target->isVisible() is a hack since currently a guiless application will STILL inititialize a gsrender (providing a valid target) + if (!m_target || !m_target->isVisible()|| target == m_target) { if (ev->type() == QEvent::KeyPress) { @@ -34,6 +36,23 @@ bool keyboard_pad_handler::eventFilter(QObject* target, QEvent* ev) return false; } +/* Sets the target window for the event handler, and also installs an event filter on the target. */ +void keyboard_pad_handler::SetTargetWindow(QWindow* target) +{ + if (target != nullptr) + { + m_target = target; + target->installEventFilter(this); + } + else + { + QApplication::instance()->installEventFilter(this); + // If this is hit, it probably means that some refactoring occurs because currently a gsframe is created in Load. + // We still want events so filter from application instead since target is null. + LOG_ERROR(GENERAL, "Trying to set pad handler to a null target window."); + } +} + void keyboard_pad_handler::keyPressEvent(QKeyEvent* event) { if (event->isAutoRepeat()) diff --git a/rpcs3/keyboard_pad_handler.h b/rpcs3/keyboard_pad_handler.h index 0a1dfc0b65..a94d215aa2 100644 --- a/rpcs3/keyboard_pad_handler.h +++ b/rpcs3/keyboard_pad_handler.h @@ -5,8 +5,8 @@ #include "stdafx.h" #include "Emu/System.h" +#include #include -#include struct keyboard_pad_config final : cfg::node { @@ -58,13 +58,14 @@ class keyboard_pad_handler final : public QObject, public PadHandlerBase public: virtual void Init(const u32 max_connect) override; - keyboard_pad_handler(QObject* target, QObject* parent); + keyboard_pad_handler(); + void SetTargetWindow(QWindow* target); void keyPressEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event); void LoadSettings(); bool eventFilter(QObject* obj, QEvent* ev); private: - QObject* m_target; + QWindow* m_target = nullptr; }; diff --git a/rpcs3/rpcs3_app.cpp b/rpcs3/rpcs3_app.cpp index 9982298534..9c50f036a6 100644 --- a/rpcs3/rpcs3_app.cpp +++ b/rpcs3/rpcs3_app.cpp @@ -63,9 +63,6 @@ void rpcs3_app::Init() // Create the main window RPCS3MainWin = new main_window(guiSettings, nullptr); - // Reset the pads -- see the method for why this is currently needed. - ResetPads(); - // Create callbacks from the emulator, which reference the handlers. InitializeCallbacks(); @@ -113,7 +110,13 @@ void rpcs3_app::InitializeCallbacks() switch (keyboard_handler type = g_cfg.io.keyboard) { case keyboard_handler::null: return std::make_shared(); - case keyboard_handler::basic: return m_basicKeyboardHandler; + case keyboard_handler::basic: + { + basic_keyboard_handler* ret = new basic_keyboard_handler(); + ret->moveToThread(thread()); + ret->SetTargetWindow(gameWindow); + return std::shared_ptr(ret); + } default: fmt::throw_exception("Invalid keyboard handler: %s", type); } }; @@ -123,7 +126,13 @@ void rpcs3_app::InitializeCallbacks() switch (mouse_handler type = g_cfg.io.mouse) { case mouse_handler::null: return std::make_shared(); - case mouse_handler::basic: return m_basicMouseHandler; + case mouse_handler::basic: + { + basic_mouse_handler* ret = new basic_mouse_handler(); + ret->moveToThread(thread()); + ret->SetTargetWindow(gameWindow); + return std::shared_ptr(ret); + } default: fmt::throw_exception("Invalid mouse handler: %s", type); } }; @@ -133,7 +142,13 @@ void rpcs3_app::InitializeCallbacks() switch (pad_handler type = g_cfg.io.pad) { case pad_handler::null: return std::make_shared(); - case pad_handler::keyboard: return m_keyboardPadHandler; + case pad_handler::keyboard: + { + keyboard_pad_handler* ret = new keyboard_pad_handler(); + ret->moveToThread(thread()); + ret->SetTargetWindow(gameWindow); + return std::shared_ptr(ret); + } case pad_handler::ds4: return std::make_shared(); #ifdef _MSC_VER case pad_handler::xinput: return std::make_shared(); @@ -166,11 +181,31 @@ void rpcs3_app::InitializeCallbacks() switch (video_renderer type = g_cfg.video.renderer) { - case video_renderer::null: return std::make_unique("Null", w, h, RPCS3MainWin->GetAppIcon(), disableMouse); - case video_renderer::opengl: return std::make_unique(w, h, RPCS3MainWin->GetAppIcon(), disableMouse); - case video_renderer::vulkan: return std::make_unique("Vulkan", w, h, RPCS3MainWin->GetAppIcon(), disableMouse); + case video_renderer::null: + { + gs_frame* ret = new gs_frame("Null", size.first, size.second, RPCS3MainWin->GetAppIcon(), disableMouse); + gameWindow = ret; + return std::unique_ptr(ret); + } + case video_renderer::opengl: + { + gl_gs_frame* ret = new gl_gs_frame(size.first, size.second, RPCS3MainWin->GetAppIcon(), disableMouse); + gameWindow = ret; + return std::unique_ptr(ret); + } + case video_renderer::vulkan: + { + gs_frame* ret = new gs_frame("Vulkan", size.first, size.second, RPCS3MainWin->GetAppIcon(), disableMouse); + gameWindow = ret; + return std::unique_ptr(ret); + } #ifdef _MSC_VER - case video_renderer::dx12: return std::make_unique("DirectX 12", w, h, RPCS3MainWin->GetAppIcon(), disableMouse); + case video_renderer::dx12: + { + gs_frame* ret = new gs_frame("DirectX 12", size.first, size.second, RPCS3MainWin->GetAppIcon(), disableMouse); + gameWindow = ret; + return std::unique_ptr(ret); + } #endif default: fmt::throw_exception("Invalid video renderer: %s" HERE, type); } @@ -237,7 +272,6 @@ void rpcs3_app::InitializeConnects() connect(this, &rpcs3_app::RequestCallAfter, this, &rpcs3_app::HandleCallAfter); connect(this, &rpcs3_app::OnEmulatorRun, RPCS3MainWin, &main_window::OnEmuRun); - connect(this, &rpcs3_app::OnEmulatorStop, this, &rpcs3_app::ResetPads); connect(this, &rpcs3_app::OnEmulatorStop, RPCS3MainWin, &main_window::OnEmuStop); connect(this, &rpcs3_app::OnEmulatorPause, RPCS3MainWin, &main_window::OnEmuPause); connect(this, &rpcs3_app::OnEmulatorResume, RPCS3MainWin, &main_window::OnEmuResume); @@ -269,17 +303,3 @@ void rpcs3_app::HandleCallAfter(const std::function& func) { func(); } - -/** - * We need to make this in the main thread to receive events from the main thread. - * This leads to the tricky situation. Creating it while booting leads to deadlock with a blocking connection. - * So, I need to make them before, but when? - * I opted to reset them when the Emu stops and on first init. Potentially a race condition on restart? Never encountered issues. - * The other tricky issue is that I don't want Init to be called twice on the same object. Reseting the pointer on emu stop should handle this as well! -*/ -void rpcs3_app::ResetPads() -{ - m_basicKeyboardHandler.reset(new basic_keyboard_handler(this, this)); - m_basicMouseHandler.reset(new basic_mouse_handler(this, this)); - m_keyboardPadHandler.reset(new keyboard_pad_handler(this, this)); -} diff --git a/rpcs3/rpcs3_app.h b/rpcs3/rpcs3_app.h index 430aebe756..fdb620cfaf 100644 --- a/rpcs3/rpcs3_app.h +++ b/rpcs3/rpcs3_app.h @@ -41,17 +41,12 @@ Q_SIGNALS: private Q_SLOTS: void OnChangeStyleSheetRequest(const QString& path); void HandleCallAfter(const std::function& func); - void ResetPads(); private: void InitializeCallbacks(); void InitializeConnects(); - // See ResetPads() for why these shared pointers exist. - std::shared_ptr m_keyboardPadHandler; - std::shared_ptr m_basicKeyboardHandler; - std::shared_ptr m_basicMouseHandler; - main_window* RPCS3MainWin; std::shared_ptr guiSettings; + QWindow* gameWindow = nullptr; //! (Currently) only needed so that pad handlers have a valid target for event filtering. };