Perform refactoring of pads to remove the ugly pad initialization.

This commit is contained in:
Robbie 2017-07-12 09:07:40 -05:00 committed by Ivan
parent b01e7e3362
commit d1cde4d0a7
8 changed files with 127 additions and 53 deletions

View file

@ -1,5 +1,6 @@
#include "basic_keyboard_handler.h" #include "basic_keyboard_handler.h"
#include <QApplication>
#include <QKeyEvent> #include <QKeyEvent>
void basic_keyboard_handler::Init(const u32 max_connect) 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) 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) bool basic_keyboard_handler::eventFilter(QObject* target, QEvent* ev)
{ {
// Commenting target since I don't know how to target game window yet. // !m_target is for future proofing when gsrender isn't automatically initialized on load.
//if (target == m_target) // !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) if (ev->type() == QEvent::KeyPress)
{ {

View file

@ -3,8 +3,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Io/KeyboardHandler.h" #include "Emu/Io/KeyboardHandler.h"
#include <QObject>
#include <QKeyEvent> #include <QKeyEvent>
#include <QWindow>
class basic_keyboard_handler final : public QObject, public KeyboardHandlerBase class basic_keyboard_handler final : public QObject, public KeyboardHandlerBase
{ {
@ -12,12 +12,13 @@ class basic_keyboard_handler final : public QObject, public KeyboardHandlerBase
public: public:
virtual void Init(const u32 max_connect) override; 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); bool eventFilter(QObject* obj, QEvent* ev);
void keyPressEvent(QKeyEvent* event); void keyPressEvent(QKeyEvent* event);
void keyReleaseEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event);
void LoadSettings(); void LoadSettings();
private: private:
QObject* m_target; QWindow* m_target = nullptr;
}; };

View file

@ -1,5 +1,7 @@
#include "basic_mouse_handler.h" #include "basic_mouse_handler.h"
#include <QApplication>
void basic_mouse_handler::Init(const u32 max_connect) void basic_mouse_handler::Init(const u32 max_connect)
{ {
m_mice.emplace_back(Mouse()); m_mice.emplace_back(Mouse());
@ -13,15 +15,31 @@ void basic_mouse_handler::Init(const u32 max_connect)
m_info.product_id[0] = 0x1234; 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. // !m_target is for future proofing when gsrender isn't automatically initialized on load to ensure events still occur
//if (m_target == obj) // !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()) switch (ev->type())
{ {

View file

@ -3,6 +3,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Io/MouseHandler.h" #include "Emu/Io/MouseHandler.h"
#include <QWindow>
#include <QMouseEvent> #include <QMouseEvent>
#include <QWheelEvent> #include <QWheelEvent>
@ -12,8 +13,9 @@ class basic_mouse_handler final : public QObject, public MouseHandlerBase
public: public:
virtual void Init(const u32 max_connect) override; 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 MouseButtonDown(QMouseEvent* event);
void MouseButtonUp(QMouseEvent* event); void MouseButtonUp(QMouseEvent* event);
void MouseScroll(QWheelEvent* event); void MouseScroll(QWheelEvent* event);
@ -21,5 +23,5 @@ public:
bool eventFilter(QObject* obj, QEvent* ev); bool eventFilter(QObject* obj, QEvent* ev);
private: private:
QObject* m_target; QWindow* m_target = nullptr;
}; };

View file

@ -2,6 +2,8 @@
#include "keyboard_pad_handler.h" #include "keyboard_pad_handler.h"
#include <QApplication>
keyboard_pad_config g_kbpad_config; keyboard_pad_config g_kbpad_config;
void keyboard_pad_handler::Init(const u32 max_connect) 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); 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) bool keyboard_pad_handler::eventFilter(QObject* target, QEvent* ev)
{ {
// Commenting target since I don't know how to target game window yet. // !m_target is for future proofing when gsrender isn't automatically initialized on load.
//if (target == m_target) // !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) if (ev->type() == QEvent::KeyPress)
{ {
@ -34,6 +36,23 @@ bool keyboard_pad_handler::eventFilter(QObject* target, QEvent* ev)
return false; 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) void keyboard_pad_handler::keyPressEvent(QKeyEvent* event)
{ {
if (event->isAutoRepeat()) if (event->isAutoRepeat())

View file

@ -5,8 +5,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include <QWindow>
#include <QKeyEvent> #include <QKeyEvent>
#include <QObject>
struct keyboard_pad_config final : cfg::node struct keyboard_pad_config final : cfg::node
{ {
@ -58,13 +58,14 @@ class keyboard_pad_handler final : public QObject, public PadHandlerBase
public: public:
virtual void Init(const u32 max_connect) override; 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 keyPressEvent(QKeyEvent* event);
void keyReleaseEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event);
void LoadSettings(); void LoadSettings();
bool eventFilter(QObject* obj, QEvent* ev); bool eventFilter(QObject* obj, QEvent* ev);
private: private:
QObject* m_target; QWindow* m_target = nullptr;
}; };

View file

@ -63,9 +63,6 @@ void rpcs3_app::Init()
// Create the main window // Create the main window
RPCS3MainWin = new main_window(guiSettings, nullptr); 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. // Create callbacks from the emulator, which reference the handlers.
InitializeCallbacks(); InitializeCallbacks();
@ -113,7 +110,13 @@ void rpcs3_app::InitializeCallbacks()
switch (keyboard_handler type = g_cfg.io.keyboard) switch (keyboard_handler type = g_cfg.io.keyboard)
{ {
case keyboard_handler::null: return std::make_shared<NullKeyboardHandler>(); case keyboard_handler::null: return std::make_shared<NullKeyboardHandler>();
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<KeyboardHandlerBase>(ret);
}
default: fmt::throw_exception("Invalid keyboard handler: %s", type); 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) switch (mouse_handler type = g_cfg.io.mouse)
{ {
case mouse_handler::null: return std::make_shared<NullMouseHandler>(); case mouse_handler::null: return std::make_shared<NullMouseHandler>();
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<MouseHandlerBase>(ret);
}
default: fmt::throw_exception("Invalid mouse handler: %s", type); 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) switch (pad_handler type = g_cfg.io.pad)
{ {
case pad_handler::null: return std::make_shared<NullPadHandler>(); case pad_handler::null: return std::make_shared<NullPadHandler>();
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<PadHandlerBase>(ret);
}
case pad_handler::ds4: return std::make_shared<ds4_pad_handler>(); case pad_handler::ds4: return std::make_shared<ds4_pad_handler>();
#ifdef _MSC_VER #ifdef _MSC_VER
case pad_handler::xinput: return std::make_shared<xinput_pad_handler>(); case pad_handler::xinput: return std::make_shared<xinput_pad_handler>();
@ -166,11 +181,31 @@ void rpcs3_app::InitializeCallbacks()
switch (video_renderer type = g_cfg.video.renderer) switch (video_renderer type = g_cfg.video.renderer)
{ {
case video_renderer::null: return std::make_unique<gs_frame>("Null", w, h, RPCS3MainWin->GetAppIcon(), disableMouse); case video_renderer::null:
case video_renderer::opengl: return std::make_unique<gl_gs_frame>(w, h, RPCS3MainWin->GetAppIcon(), disableMouse); {
case video_renderer::vulkan: return std::make_unique<gs_frame>("Vulkan", w, h, RPCS3MainWin->GetAppIcon(), disableMouse); gs_frame* ret = new gs_frame("Null", size.first, size.second, RPCS3MainWin->GetAppIcon(), disableMouse);
gameWindow = ret;
return std::unique_ptr<gs_frame>(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<gl_gs_frame>(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<gs_frame>(ret);
}
#ifdef _MSC_VER #ifdef _MSC_VER
case video_renderer::dx12: return std::make_unique<gs_frame>("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<gs_frame>(ret);
}
#endif #endif
default: fmt::throw_exception("Invalid video renderer: %s" HERE, type); 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::RequestCallAfter, this, &rpcs3_app::HandleCallAfter);
connect(this, &rpcs3_app::OnEmulatorRun, RPCS3MainWin, &main_window::OnEmuRun); 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::OnEmulatorStop, RPCS3MainWin, &main_window::OnEmuStop);
connect(this, &rpcs3_app::OnEmulatorPause, RPCS3MainWin, &main_window::OnEmuPause); connect(this, &rpcs3_app::OnEmulatorPause, RPCS3MainWin, &main_window::OnEmuPause);
connect(this, &rpcs3_app::OnEmulatorResume, RPCS3MainWin, &main_window::OnEmuResume); connect(this, &rpcs3_app::OnEmulatorResume, RPCS3MainWin, &main_window::OnEmuResume);
@ -269,17 +303,3 @@ void rpcs3_app::HandleCallAfter(const std::function<void()>& func)
{ {
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));
}

View file

@ -41,17 +41,12 @@ Q_SIGNALS:
private Q_SLOTS: private Q_SLOTS:
void OnChangeStyleSheetRequest(const QString& path); void OnChangeStyleSheetRequest(const QString& path);
void HandleCallAfter(const std::function<void()>& func); void HandleCallAfter(const std::function<void()>& func);
void ResetPads();
private: private:
void InitializeCallbacks(); void InitializeCallbacks();
void InitializeConnects(); void InitializeConnects();
// See ResetPads() for why these shared pointers exist.
std::shared_ptr<keyboard_pad_handler> m_keyboardPadHandler;
std::shared_ptr<basic_keyboard_handler> m_basicKeyboardHandler;
std::shared_ptr<basic_mouse_handler> m_basicMouseHandler;
main_window* RPCS3MainWin; main_window* RPCS3MainWin;
std::shared_ptr<gui_settings> guiSettings; std::shared_ptr<gui_settings> guiSettings;
QWindow* gameWindow = nullptr; //! (Currently) only needed so that pad handlers have a valid target for event filtering.
}; };