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 <QApplication>
#include <QKeyEvent>
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.
}
/* 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)
{

View File

@ -3,8 +3,8 @@
#include "stdafx.h"
#include "Emu/Io/KeyboardHandler.h"
#include <QObject>
#include <QKeyEvent>
#include <QWindow>
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;
};

View File

@ -1,5 +1,7 @@
#include "basic_mouse_handler.h"
#include <QApplication>
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)
{
if (target != nullptr)
{
m_target = target;
target->installEventFilter(this);
}
bool basic_mouse_handler::eventFilter(QObject* obj, QEvent* ev)
else
{
// Commenting target since I don't know how to target game window yet.
//if (m_target == obj)
// 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* target, QEvent* ev)
{
// !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())
{

View File

@ -3,6 +3,7 @@
#include "stdafx.h"
#include "Emu/Io/MouseHandler.h"
#include <QWindow>
#include <QMouseEvent>
#include <QWheelEvent>
@ -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;
};

View File

@ -2,6 +2,8 @@
#include "keyboard_pad_handler.h"
#include <QApplication>
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())

View File

@ -5,8 +5,8 @@
#include "stdafx.h"
#include "Emu/System.h"
#include <QWindow>
#include <QKeyEvent>
#include <QObject>
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;
};

View File

@ -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<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);
}
};
@ -123,7 +126,13 @@ void rpcs3_app::InitializeCallbacks()
switch (mouse_handler type = g_cfg.io.mouse)
{
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);
}
};
@ -133,7 +142,13 @@ void rpcs3_app::InitializeCallbacks()
switch (pad_handler type = g_cfg.io.pad)
{
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>();
#ifdef _MSC_VER
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)
{
case video_renderer::null: return std::make_unique<gs_frame>("Null", w, h, RPCS3MainWin->GetAppIcon(), disableMouse);
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);
case video_renderer::null:
{
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
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
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<void()>& 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:
void OnChangeStyleSheetRequest(const QString& path);
void HandleCallAfter(const std::function<void()>& func);
void ResetPads();
private:
void InitializeCallbacks();
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;
std::shared_ptr<gui_settings> guiSettings;
QWindow* gameWindow = nullptr; //! (Currently) only needed so that pad handlers have a valid target for event filtering.
};