mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-01-31 11:55:37 +00:00
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) {}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ public:
|
|||
virtual void LoadSettings(const char* section);
|
||||
|
||||
/// 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.
|
||||
static std::unique_ptr<Controller> Create(ControllerType type, u32 index);
|
||||
|
|
|
@ -917,20 +917,28 @@ void HostInterface::UpdateSoftwareCursor()
|
|||
{
|
||||
if (System::IsShutdown())
|
||||
{
|
||||
SetMouseMode(false, false);
|
||||
m_display->ClearSoftwareCursor();
|
||||
return;
|
||||
}
|
||||
|
||||
const Common::RGBA8Image* image = nullptr;
|
||||
float image_scale = 1.0f;
|
||||
bool relative_mode = false;
|
||||
bool hide_cursor = false;
|
||||
|
||||
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; 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;
|
||||
}
|
||||
}
|
||||
|
||||
SetMouseMode(relative_mode, hide_cursor);
|
||||
|
||||
if (image && image->IsValid())
|
||||
{
|
||||
m_display->SetSoftwareCursor(image->GetPixels(), image->GetWidth(), image->GetHeight(), image->GetByteStride(),
|
||||
|
@ -967,6 +975,8 @@ void HostInterface::RecreateSystem()
|
|||
System::ResetPerformanceCounters();
|
||||
}
|
||||
|
||||
void HostInterface::SetMouseMode(bool relative, bool hide_cursor) {}
|
||||
|
||||
void HostInterface::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/, int progress_max /*= -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).
|
||||
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".
|
||||
void SetUserDirectoryToProgramDirectory();
|
||||
|
||||
|
|
|
@ -280,12 +280,13 @@ void NamcoGunCon::LoadSettings(const char* section)
|
|||
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())
|
||||
return false;
|
||||
|
||||
*image = &m_crosshair_image;
|
||||
*image_scale = m_crosshair_image_scale;
|
||||
*relative_mode = false;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
void Reset() override;
|
||||
bool DoState(StateWrapper& sw, bool apply_input_state) 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 SetButtonState(s32 button_code, bool pressed) override;
|
||||
|
|
|
@ -39,6 +39,8 @@ public:
|
|||
|
||||
void SetButtonState(Button button, bool pressed);
|
||||
|
||||
bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode) override;
|
||||
|
||||
private:
|
||||
void UpdatePosition();
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue