Qt: Implement relative mouse mode
This commit is contained in:
parent
114d4a2c1d
commit
ca42d027ac
|
@ -47,7 +47,7 @@ float Controller::GetVibrationMotorStrength(u32 motor)
|
||||||
|
|
||||||
void Controller::LoadSettings(const char* section) {}
|
void Controller::LoadSettings(const char* section) {}
|
||||||
|
|
||||||
bool Controller::GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale)
|
bool Controller::GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ public:
|
||||||
virtual void LoadSettings(const char* section);
|
virtual void LoadSettings(const char* section);
|
||||||
|
|
||||||
/// Returns the software cursor to use for this controller, if any.
|
/// Returns the software cursor to use for this controller, if any.
|
||||||
virtual bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale);
|
virtual bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode);
|
||||||
|
|
||||||
/// Creates a new controller of the specified type.
|
/// Creates a new controller of the specified type.
|
||||||
static std::unique_ptr<Controller> Create(ControllerType type, u32 index);
|
static std::unique_ptr<Controller> Create(ControllerType type, u32 index);
|
||||||
|
|
|
@ -917,20 +917,28 @@ void HostInterface::UpdateSoftwareCursor()
|
||||||
{
|
{
|
||||||
if (System::IsShutdown())
|
if (System::IsShutdown())
|
||||||
{
|
{
|
||||||
|
SetMouseMode(false, false);
|
||||||
m_display->ClearSoftwareCursor();
|
m_display->ClearSoftwareCursor();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Common::RGBA8Image* image = nullptr;
|
const Common::RGBA8Image* image = nullptr;
|
||||||
float image_scale = 1.0f;
|
float image_scale = 1.0f;
|
||||||
|
bool relative_mode = false;
|
||||||
|
bool hide_cursor = false;
|
||||||
|
|
||||||
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
|
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
|
||||||
{
|
{
|
||||||
Controller* controller = System::GetController(i);
|
Controller* controller = System::GetController(i);
|
||||||
if (controller && controller->GetSoftwareCursor(&image, &image_scale))
|
if (controller && controller->GetSoftwareCursor(&image, &image_scale, &relative_mode))
|
||||||
|
{
|
||||||
|
hide_cursor = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetMouseMode(relative_mode, hide_cursor);
|
||||||
|
|
||||||
if (image && image->IsValid())
|
if (image && image->IsValid())
|
||||||
{
|
{
|
||||||
m_display->SetSoftwareCursor(image->GetPixels(), image->GetWidth(), image->GetHeight(), image->GetByteStride(),
|
m_display->SetSoftwareCursor(image->GetPixels(), image->GetWidth(), image->GetHeight(), image->GetByteStride(),
|
||||||
|
@ -967,6 +975,8 @@ void HostInterface::RecreateSystem()
|
||||||
System::ResetPerformanceCounters();
|
System::ResetPerformanceCounters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HostInterface::SetMouseMode(bool relative, bool hide_cursor) {}
|
||||||
|
|
||||||
void HostInterface::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/, int progress_max /*= -1*/,
|
void HostInterface::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/, int progress_max /*= -1*/,
|
||||||
int progress_value /*= -1*/)
|
int progress_value /*= -1*/)
|
||||||
{
|
{
|
||||||
|
|
|
@ -175,6 +175,9 @@ protected:
|
||||||
/// Switches the GPU renderer by saving state, recreating the display window, and restoring state (if needed).
|
/// Switches the GPU renderer by saving state, recreating the display window, and restoring state (if needed).
|
||||||
virtual void RecreateSystem();
|
virtual void RecreateSystem();
|
||||||
|
|
||||||
|
/// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates.
|
||||||
|
virtual void SetMouseMode(bool relative, bool hide_cursor);
|
||||||
|
|
||||||
/// Sets the user directory to the program directory, i.e. "portable mode".
|
/// Sets the user directory to the program directory, i.e. "portable mode".
|
||||||
void SetUserDirectoryToProgramDirectory();
|
void SetUserDirectoryToProgramDirectory();
|
||||||
|
|
||||||
|
|
|
@ -280,12 +280,13 @@ void NamcoGunCon::LoadSettings(const char* section)
|
||||||
m_x_scale = g_host_interface->GetFloatSettingValue(section, "XScale", 1.0f);
|
m_x_scale = g_host_interface->GetFloatSettingValue(section, "XScale", 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NamcoGunCon::GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale)
|
bool NamcoGunCon::GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode)
|
||||||
{
|
{
|
||||||
if (!m_crosshair_image.IsValid())
|
if (!m_crosshair_image.IsValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*image = &m_crosshair_image;
|
*image = &m_crosshair_image;
|
||||||
*image_scale = m_crosshair_image_scale;
|
*image_scale = m_crosshair_image_scale;
|
||||||
|
*relative_mode = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ public:
|
||||||
void Reset() override;
|
void Reset() override;
|
||||||
bool DoState(StateWrapper& sw, bool apply_input_state) override;
|
bool DoState(StateWrapper& sw, bool apply_input_state) override;
|
||||||
void LoadSettings(const char* section) override;
|
void LoadSettings(const char* section) override;
|
||||||
bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale) override;
|
bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode) override;
|
||||||
|
|
||||||
void SetAxisState(s32 axis_code, float value) override;
|
void SetAxisState(s32 axis_code, float value) override;
|
||||||
void SetButtonState(s32 button_code, bool pressed) override;
|
void SetButtonState(s32 button_code, bool pressed) override;
|
||||||
|
|
|
@ -39,6 +39,8 @@ public:
|
||||||
|
|
||||||
void SetButtonState(Button button, bool pressed);
|
void SetButtonState(Button button, bool pressed);
|
||||||
|
|
||||||
|
bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdatePosition();
|
void UpdatePosition();
|
||||||
|
|
||||||
|
|
|
@ -290,6 +290,22 @@ void MainWindow::focusDisplayWidget()
|
||||||
m_display_widget->setFocus();
|
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()
|
void MainWindow::onEmulationStarting()
|
||||||
{
|
{
|
||||||
m_emulation_running = true;
|
m_emulation_running = true;
|
||||||
|
@ -327,6 +343,9 @@ void MainWindow::onEmulationPaused(bool paused)
|
||||||
{
|
{
|
||||||
QSignalBlocker blocker(m_ui.actionPause);
|
QSignalBlocker blocker(m_ui.actionPause);
|
||||||
m_ui.actionPause->setChecked(paused);
|
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)
|
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_host_interface->pauseSystem(true);
|
||||||
m_was_paused_by_focus_loss = true;
|
m_was_paused_by_focus_loss = true;
|
||||||
|
|
||||||
|
if (m_display_widget)
|
||||||
|
m_display_widget->setRelativeMode(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -381,6 +403,9 @@ void MainWindow::onApplicationStateChanged(Qt::ApplicationState state)
|
||||||
if (System::IsPaused())
|
if (System::IsPaused())
|
||||||
m_host_interface->pauseSystem(false);
|
m_host_interface->pauseSystem(false);
|
||||||
m_was_paused_by_focus_loss = 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);
|
&MainWindow::onSystemPerformanceCountersUpdated);
|
||||||
connect(m_host_interface, &QtHostInterface::runningGameChanged, this, &MainWindow::onRunningGameChanged);
|
connect(m_host_interface, &QtHostInterface::runningGameChanged, this, &MainWindow::onRunningGameChanged);
|
||||||
connect(m_host_interface, &QtHostInterface::exitRequested, this, &MainWindow::close);
|
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.
|
// 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,
|
connect(m_game_list_widget, &GameListWidget::entrySelected, this, &MainWindow::onGameListEntrySelected,
|
||||||
|
|
|
@ -52,6 +52,7 @@ private Q_SLOTS:
|
||||||
void displaySizeRequested(qint32 width, qint32 height);
|
void displaySizeRequested(qint32 width, qint32 height);
|
||||||
void destroyDisplay();
|
void destroyDisplay();
|
||||||
void focusDisplayWidget();
|
void focusDisplayWidget();
|
||||||
|
void onMouseModeRequested(bool relative_mode, bool hide_cursor);
|
||||||
|
|
||||||
void setTheme(const QString& theme);
|
void setTheme(const QString& theme);
|
||||||
void updateTheme();
|
void updateTheme();
|
||||||
|
@ -148,6 +149,7 @@ private:
|
||||||
bool m_emulation_running = false;
|
bool m_emulation_running = false;
|
||||||
bool m_was_paused_by_focus_loss = false;
|
bool m_was_paused_by_focus_loss = false;
|
||||||
bool m_open_debugger_on_start = false;
|
bool m_open_debugger_on_start = false;
|
||||||
|
bool m_relative_mouse_mode = false;
|
||||||
|
|
||||||
GDBServer* m_gdb_server = nullptr;
|
GDBServer* m_gdb_server = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -92,6 +92,29 @@ std::optional<WindowInfo> QtDisplayWidget::getWindowInfo() const
|
||||||
return wi;
|
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
|
QPaintEngine* QtDisplayWidget::paintEngine() const
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -113,10 +136,35 @@ bool QtDisplayWidget::event(QEvent* event)
|
||||||
|
|
||||||
case QEvent::MouseMove:
|
case QEvent::MouseMove:
|
||||||
{
|
{
|
||||||
const qreal dpr = devicePixelRatioFromScreen();
|
|
||||||
const QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ public:
|
||||||
|
|
||||||
std::optional<WindowInfo> getWindowInfo() const;
|
std::optional<WindowInfo> getWindowInfo() const;
|
||||||
|
|
||||||
|
void setRelativeMode(bool enabled);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void windowResizedEvent(int width, int height);
|
void windowResizedEvent(int width, int height);
|
||||||
void windowRestoredEvent();
|
void windowRestoredEvent();
|
||||||
|
@ -30,4 +32,9 @@ Q_SIGNALS:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool event(QEvent* event) override;
|
bool event(QEvent* event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPoint m_relative_mouse_start_position{};
|
||||||
|
QPoint m_relative_mouse_last_position{};
|
||||||
|
bool m_relative_mouse_enabled = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -577,6 +577,7 @@ void QtHostInterface::updateDisplayState()
|
||||||
if (!System::IsShutdown())
|
if (!System::IsShutdown())
|
||||||
{
|
{
|
||||||
g_gpu->UpdateResolutionScale();
|
g_gpu->UpdateResolutionScale();
|
||||||
|
UpdateSoftwareCursor();
|
||||||
redrawDisplayWindow();
|
redrawDisplayWindow();
|
||||||
}
|
}
|
||||||
UpdateSpeedLimiterState();
|
UpdateSpeedLimiterState();
|
||||||
|
@ -736,6 +737,11 @@ void QtHostInterface::UpdateInputMap()
|
||||||
updateInputMap();
|
updateInputMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QtHostInterface::SetMouseMode(bool relative, bool hide_cursor)
|
||||||
|
{
|
||||||
|
emit mouseModeRequested(relative, hide_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
void QtHostInterface::updateInputMap()
|
void QtHostInterface::updateInputMap()
|
||||||
{
|
{
|
||||||
if (!isOnWorkerThread())
|
if (!isOnWorkerThread())
|
||||||
|
|
|
@ -139,6 +139,7 @@ Q_SIGNALS:
|
||||||
void runningGameChanged(const QString& filename, const QString& game_code, const QString& game_title);
|
void runningGameChanged(const QString& filename, const QString& game_code, const QString& game_title);
|
||||||
void exitRequested();
|
void exitRequested();
|
||||||
void inputProfileLoaded();
|
void inputProfileLoaded();
|
||||||
|
void mouseModeRequested(bool relative, bool hide_cursor);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void setDefaultSettings();
|
void setDefaultSettings();
|
||||||
|
@ -203,6 +204,8 @@ protected:
|
||||||
void SetDefaultSettings(SettingsInterface& si) override;
|
void SetDefaultSettings(SettingsInterface& si) override;
|
||||||
void UpdateInputMap() override;
|
void UpdateInputMap() override;
|
||||||
|
|
||||||
|
void SetMouseMode(bool relative, bool hide_cursor) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue