Qt: Implement relative mouse mode

This commit is contained in:
Connor McLaughlin
2020-12-27 14:08:13 +10:00
parent 114d4a2c1d
commit ca42d027ac
13 changed files with 116 additions and 8 deletions

View File

@ -290,6 +290,22 @@ void MainWindow::focusDisplayWidget()
m_display_widget->setFocus();
}
void MainWindow::onMouseModeRequested(bool relative_mode, bool hide_cursor)
{
if (!m_display_widget)
return;
const bool paused = System::IsPaused();
if (hide_cursor)
m_display_widget->setCursor(Qt::BlankCursor);
else
m_display_widget->unsetCursor();
m_relative_mouse_mode = relative_mode;
m_display_widget->setRelativeMode(!paused && relative_mode);
}
void MainWindow::onEmulationStarting()
{
m_emulation_running = true;
@ -327,6 +343,9 @@ void MainWindow::onEmulationPaused(bool paused)
{
QSignalBlocker blocker(m_ui.actionPause);
m_ui.actionPause->setChecked(paused);
if (m_display_widget)
m_display_widget->setRelativeMode(!paused && m_relative_mouse_mode);
}
void MainWindow::onStateSaved(const QString& game_code, bool global, qint32 slot)
@ -372,6 +391,9 @@ void MainWindow::onApplicationStateChanged(Qt::ApplicationState state)
{
m_host_interface->pauseSystem(true);
m_was_paused_by_focus_loss = true;
if (m_display_widget)
m_display_widget->setRelativeMode(false);
}
}
else
@ -381,6 +403,9 @@ void MainWindow::onApplicationStateChanged(Qt::ApplicationState state)
if (System::IsPaused())
m_host_interface->pauseSystem(false);
m_was_paused_by_focus_loss = false;
if (m_display_widget)
m_display_widget->setRelativeMode(m_relative_mouse_mode);
}
}
}
@ -974,6 +999,7 @@ void MainWindow::connectSignals()
&MainWindow::onSystemPerformanceCountersUpdated);
connect(m_host_interface, &QtHostInterface::runningGameChanged, this, &MainWindow::onRunningGameChanged);
connect(m_host_interface, &QtHostInterface::exitRequested, this, &MainWindow::close);
connect(m_host_interface, &QtHostInterface::mouseModeRequested, this, &MainWindow::onMouseModeRequested);
// These need to be queued connections to stop crashing due to menus opening/closing and switching focus.
connect(m_game_list_widget, &GameListWidget::entrySelected, this, &MainWindow::onGameListEntrySelected,

View File

@ -52,6 +52,7 @@ private Q_SLOTS:
void displaySizeRequested(qint32 width, qint32 height);
void destroyDisplay();
void focusDisplayWidget();
void onMouseModeRequested(bool relative_mode, bool hide_cursor);
void setTheme(const QString& theme);
void updateTheme();
@ -148,6 +149,7 @@ private:
bool m_emulation_running = false;
bool m_was_paused_by_focus_loss = false;
bool m_open_debugger_on_start = false;
bool m_relative_mouse_mode = false;
GDBServer* m_gdb_server = nullptr;
};

View File

@ -92,6 +92,29 @@ std::optional<WindowInfo> QtDisplayWidget::getWindowInfo() const
return wi;
}
void QtDisplayWidget::setRelativeMode(bool enabled)
{
if (m_relative_mouse_enabled == enabled)
return;
if (enabled)
{
m_relative_mouse_start_position = QCursor::pos();
const QPoint center_pos = mapToGlobal(QPoint(width() / 2, height() / 2));
QCursor::setPos(center_pos);
m_relative_mouse_last_position = center_pos;
grabMouse();
}
else
{
QCursor::setPos(m_relative_mouse_start_position);
releaseMouse();
}
m_relative_mouse_enabled = enabled;
}
QPaintEngine* QtDisplayWidget::paintEngine() const
{
return nullptr;
@ -113,10 +136,35 @@ bool QtDisplayWidget::event(QEvent* event)
case QEvent::MouseMove:
{
const qreal dpr = devicePixelRatioFromScreen();
const QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
emit windowMouseMoveEvent(static_cast<int>(static_cast<double>(mouse_event->x()) * dpr),
static_cast<int>(static_cast<double>(mouse_event->y()) * dpr));
if (!m_relative_mouse_enabled)
{
const qreal dpr = devicePixelRatioFromScreen();
const int scaled_x = static_cast<int>(static_cast<qreal>(mouse_event->x()) * dpr);
const int scaled_y = static_cast<int>(static_cast<qreal>(mouse_event->y()) * dpr);
windowMouseMoveEvent(scaled_x, scaled_y);
}
else
{
const QPoint center_pos = mapToGlobal(QPoint((width() + 1) / 2, (height() + 1) / 2));
const QPoint mouse_pos = mapToGlobal(mouse_event->pos());
const int dx = mouse_pos.x() - center_pos.x();
const int dy = mouse_pos.y() - center_pos.y();
m_relative_mouse_last_position.setX(m_relative_mouse_last_position.x() + dx);
m_relative_mouse_last_position.setY(m_relative_mouse_last_position.y() + dy);
windowMouseMoveEvent(m_relative_mouse_last_position.x(), m_relative_mouse_last_position.y());
QCursor::setPos(center_pos);
#if 0
qCritical() << "center" << center_pos.x() << "," << center_pos.y();
qCritical() << "mouse" << mouse_pos.x() << "," << mouse_pos.y();
qCritical() << "dxdy" << dx << "," << dy;
#endif
}
return true;
}

View File

@ -20,6 +20,8 @@ public:
std::optional<WindowInfo> getWindowInfo() const;
void setRelativeMode(bool enabled);
Q_SIGNALS:
void windowResizedEvent(int width, int height);
void windowRestoredEvent();
@ -30,4 +32,9 @@ Q_SIGNALS:
protected:
bool event(QEvent* event) override;
private:
QPoint m_relative_mouse_start_position{};
QPoint m_relative_mouse_last_position{};
bool m_relative_mouse_enabled = false;
};

View File

@ -577,6 +577,7 @@ void QtHostInterface::updateDisplayState()
if (!System::IsShutdown())
{
g_gpu->UpdateResolutionScale();
UpdateSoftwareCursor();
redrawDisplayWindow();
}
UpdateSpeedLimiterState();
@ -736,6 +737,11 @@ void QtHostInterface::UpdateInputMap()
updateInputMap();
}
void QtHostInterface::SetMouseMode(bool relative, bool hide_cursor)
{
emit mouseModeRequested(relative, hide_cursor);
}
void QtHostInterface::updateInputMap()
{
if (!isOnWorkerThread())

View File

@ -139,6 +139,7 @@ Q_SIGNALS:
void runningGameChanged(const QString& filename, const QString& game_code, const QString& game_title);
void exitRequested();
void inputProfileLoaded();
void mouseModeRequested(bool relative, bool hide_cursor);
public Q_SLOTS:
void setDefaultSettings();
@ -203,6 +204,8 @@ protected:
void SetDefaultSettings(SettingsInterface& si) override;
void UpdateInputMap() override;
void SetMouseMode(bool relative, bool hide_cursor) override;
private:
enum : u32
{