Skip to content

Commit

Permalink
Add option for Never Hide Mouse Cursor
Browse files Browse the repository at this point in the history
Instead of having a single GUI checkbox for "Always Hide Mouse Cursor",
I have instead opted to use radio buttons so the user can swap between
different states of mouse visibility. "Movement" is the default
behavior, "Never" will hide the mouse cursor the entire time the game is
running, and "Always" will keep the mouse cursor always visible.
  • Loading branch information
malleoz committed Oct 13, 2021
1 parent 5145853 commit 2aa400e
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 36 deletions.
4 changes: 2 additions & 2 deletions Source/Core/Core/ConfigManager.cpp
Expand Up @@ -145,7 +145,7 @@ void SConfig::SaveInterfaceSettings(IniFile& ini)
IniFile::Section* interface = ini.GetOrCreateSection("Interface");

interface->Set("ConfirmStop", bConfirmStop);
interface->Set("HideCursor", bHideCursor);
interface->Set("CursorVisibility", m_show_cursor);
interface->Set("LockCursor", bLockCursor);
interface->Set("LanguageCode", m_InterfaceLanguage);
interface->Set("ExtendedFPSInfo", m_InterfaceExtendedFPSInfo);
Expand Down Expand Up @@ -399,7 +399,7 @@ void SConfig::LoadInterfaceSettings(IniFile& ini)
IniFile::Section* interface = ini.GetOrCreateSection("Interface");

interface->Get("ConfirmStop", &bConfirmStop, true);
interface->Get("HideCursor", &bHideCursor, false);
interface->Get("CursorVisibility", &m_show_cursor, ShowCursor::OnMovement);
interface->Get("LockCursor", &bLockCursor, false);
interface->Get("LanguageCode", &m_InterfaceLanguage, "");
interface->Get("ExtendedFPSInfo", &m_InterfaceExtendedFPSInfo, false);
Expand Down
9 changes: 8 additions & 1 deletion Source/Core/Core/ConfigManager.h
Expand Up @@ -146,7 +146,14 @@ struct SConfig

// Interface settings
bool bConfirmStop = false;
bool bHideCursor = false;

enum class ShowCursor
{
Never,
Constantly,
OnMovement,
} m_show_cursor;

bool bLockCursor = false;
std::string theme_name;

Expand Down
13 changes: 7 additions & 6 deletions Source/Core/DolphinNoGUI/PlatformX11.cpp
Expand Up @@ -70,7 +70,7 @@ PlatformX11::~PlatformX11()

if (m_display)
{
if (SConfig::GetInstance().bHideCursor)
if (SConfig::GetInstance().m_show_cursor == SConfig::ShowCursor::Never)
XFreeCursor(m_display, m_blank_cursor);

XCloseDisplay(m_display);
Expand Down Expand Up @@ -115,7 +115,7 @@ bool PlatformX11::Init()
m_xrr_config = new X11Utils::XRRConfiguration(m_display, m_window);
#endif

if (SConfig::GetInstance().bHideCursor)
if (SConfig::GetInstance().m_show_cursor == SConfig::ShowCursor::Never)
{
// make a blank cursor
Pixmap Blank;
Expand Down Expand Up @@ -200,13 +200,13 @@ void PlatformX11::ProcessEvents()
{
if (Core::GetState() == Core::State::Running)
{
if (SConfig::GetInstance().bHideCursor)
if (SConfig::GetInstance().m_show_cursor == SConfig::ShowCursor::Never)
XUndefineCursor(m_display, m_window);
Core::SetState(Core::State::Paused);
}
else
{
if (SConfig::GetInstance().bHideCursor)
if (SConfig::GetInstance().m_show_cursor == SConfig::ShowCursor::Never)
XDefineCursor(m_display, m_window, m_blank_cursor);
Core::SetState(Core::State::Running);
}
Expand Down Expand Up @@ -243,14 +243,15 @@ void PlatformX11::ProcessEvents()
case FocusIn:
{
m_window_focus = true;
if (SConfig::GetInstance().bHideCursor && Core::GetState() != Core::State::Paused)
if (SConfig::GetInstance().m_show_cursor == SConfig::ShowCursor::Never &&
Core::GetState() != Core::State::Paused)
XDefineCursor(m_display, m_window, m_blank_cursor);
}
break;
case FocusOut:
{
m_window_focus = false;
if (SConfig::GetInstance().bHideCursor)
if (SConfig::GetInstance().m_show_cursor == SConfig::ShowCursor::Never)
XUndefineCursor(m_display, m_window);
}
break;
Expand Down
21 changes: 13 additions & 8 deletions Source/Core/DolphinQt/RenderWidget.cpp
Expand Up @@ -83,7 +83,7 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
m_mouse_timer->setSingleShot(true);
setMouseTracking(true);

connect(&Settings::Instance(), &Settings::HideCursorChanged, this,
connect(&Settings::Instance(), &Settings::CursorVisibilityChanged, this,
&RenderWidget::OnHideCursorChanged);
connect(&Settings::Instance(), &Settings::LockCursorChanged, this,
&RenderWidget::OnLockCursorChanged);
Expand Down Expand Up @@ -139,6 +139,7 @@ void RenderWidget::OnHideCursorChanged()
{
UpdateCursor();
}

void RenderWidget::OnLockCursorChanged()
{
SetCursorLocked(false);
Expand All @@ -155,14 +156,16 @@ void RenderWidget::UpdateCursor()
// on top of the game window in the background
const bool keep_on_top = (windowFlags() & Qt::WindowStaysOnTopHint) != 0;
const bool should_hide =
Settings::Instance().GetHideCursor() &&
(Settings::Instance().GetCursorVisibility() == SConfig::ShowCursor::Never) &&
(keep_on_top || SConfig::GetInstance().m_BackgroundInput || isActiveWindow());
setCursor(should_hide ? Qt::BlankCursor : Qt::ArrowCursor);
}
else
{
setCursor((m_cursor_locked && Settings::Instance().GetHideCursor()) ? Qt::BlankCursor :
Qt::ArrowCursor);
setCursor((m_cursor_locked &&
Settings::Instance().GetCursorVisibility() == SConfig::ShowCursor::Never) ?
Qt::BlankCursor :
Qt::ArrowCursor);
}
}

Expand All @@ -185,7 +188,8 @@ void RenderWidget::HandleCursorTimer()
{
if (!isActiveWindow())
return;
if (!Settings::Instance().GetLockCursor() || m_cursor_locked)
if ((!Settings::Instance().GetLockCursor() || m_cursor_locked) &&
Settings::Instance().GetCursorVisibility() == SConfig::ShowCursor::OnMovement)
{
setCursor(Qt::BlankCursor);
}
Expand Down Expand Up @@ -268,7 +272,7 @@ void RenderWidget::SetCursorLocked(bool locked, bool follow_aspect_ratio)
{
m_cursor_locked = true;

if (Settings::Instance().GetHideCursor())
if (Settings::Instance().GetCursorVisibility() != SConfig::ShowCursor::Constantly)
{
setCursor(Qt::BlankCursor);
}
Expand Down Expand Up @@ -370,7 +374,7 @@ bool RenderWidget::event(QEvent* event)
break;
case QEvent::MouseMove:
// Unhide on movement
if (!Settings::Instance().GetHideCursor())
if (Settings::Instance().GetCursorVisibility() == SConfig::ShowCursor::OnMovement)
{
setCursor(Qt::ArrowCursor);
m_mouse_timer->start(MOUSE_HIDE_DELAY);
Expand All @@ -381,7 +385,8 @@ bool RenderWidget::event(QEvent* event)
break;
case QEvent::Show:
// Don't do if "stay on top" changed (or was true)
if (Settings::Instance().GetLockCursor() && Settings::Instance().GetHideCursor() &&
if (Settings::Instance().GetLockCursor() &&
Settings::Instance().GetCursorVisibility() != SConfig::ShowCursor::Constantly &&
!m_dont_lock_cursor_on_show)
{
// Auto lock when this window is shown (it was hidden)
Expand Down
1 change: 1 addition & 0 deletions Source/Core/DolphinQt/RenderWidget.h
Expand Up @@ -35,6 +35,7 @@ class RenderWidget final : public QWidget
private:
void HandleCursorTimer();
void OnHideCursorChanged();
void OnNeverHideCursorChanged();
void OnLockCursorChanged();
void OnKeepOnTopChanged(bool top);
void UpdateCursor();
Expand Down
12 changes: 7 additions & 5 deletions Source/Core/DolphinQt/Settings.cpp
Expand Up @@ -10,6 +10,7 @@
#include <QFile>
#include <QFileInfo>
#include <QFontDatabase>
#include <QRadioButton>
#include <QSize>
#include <QWidget>

Expand Down Expand Up @@ -325,15 +326,16 @@ void Settings::SetStateSlot(int slot)
GetQSettings().setValue(QStringLiteral("Emulation/StateSlot"), slot);
}

void Settings::SetHideCursor(bool hide_cursor)
void Settings::SetCursorVisibility(SConfig::ShowCursor hideCursor)
{
SConfig::GetInstance().bHideCursor = hide_cursor;
emit HideCursorChanged();
SConfig::GetInstance().m_show_cursor = hideCursor;

emit CursorVisibilityChanged();
}

bool Settings::GetHideCursor() const
SConfig::ShowCursor Settings::GetCursorVisibility() const
{
return SConfig::GetInstance().bHideCursor;
return SConfig::GetInstance().m_show_cursor;
}

void Settings::SetLockCursor(bool lock_cursor)
Expand Down
8 changes: 5 additions & 3 deletions Source/Core/DolphinQt/Settings.h
Expand Up @@ -7,8 +7,10 @@

#include <QFont>
#include <QObject>
#include <QRadioButton>
#include <QSettings>

#include "Core/ConfigManager.h"
#include "DiscIO/Enums.h"

namespace Core
Expand Down Expand Up @@ -97,8 +99,8 @@ class Settings final : public QObject
void SetUSBKeyboardConnected(bool connected);

// Graphics
void SetHideCursor(bool hide_cursor);
bool GetHideCursor() const;
void SetCursorVisibility(SConfig::ShowCursor hideCursor);
SConfig::ShowCursor GetCursorVisibility() const;
void SetLockCursor(bool lock_cursor);
bool GetLockCursor() const;
void SetKeepWindowOnTop(bool top);
Expand Down Expand Up @@ -168,7 +170,7 @@ class Settings final : public QObject
void MetadataRefreshRequested();
void MetadataRefreshCompleted();
void AutoRefreshToggled(bool enabled);
void HideCursorChanged();
void CursorVisibilityChanged();
void LockCursorChanged();
void KeepWindowOnTopChanged(bool top);
void VolumeChanged(int volume);
Expand Down
59 changes: 49 additions & 10 deletions Source/Core/DolphinQt/Settings/InterfacePane.cpp
Expand Up @@ -9,6 +9,7 @@
#include <QFormLayout>
#include <QGroupBox>
#include <QLabel>
#include <QRadioButton>
#include <QVBoxLayout>
#include <QWidget>

Expand Down Expand Up @@ -169,23 +170,36 @@ void InterfacePane::CreateInGame()
m_checkbox_enable_osd = new QCheckBox(tr("Show On-Screen Display Messages"));
m_checkbox_show_active_title = new QCheckBox(tr("Show Active Title in Window Title"));
m_checkbox_pause_on_focus_lost = new QCheckBox(tr("Pause on Focus Loss"));
m_checkbox_hide_mouse = new QCheckBox(tr("Always Hide Mouse Cursor"));
m_checkbox_lock_mouse = new QCheckBox(tr("Lock Mouse Cursor"));

m_checkbox_hide_mouse->setToolTip(
tr("Will immediately hide the Mouse Cursor when it hovers on top of the Render Widget, "
"otherwise "
"there is a delay.\nIf \"Lock Mouse Cursor\" is enabled, it will hide on Mouse locked"));
auto* mouse_groupbox = new QGroupBox(tr("Mouse Cursor Visibility"));
auto* m_vboxlayout_hide_mouse = new QVBoxLayout;
mouse_groupbox->setLayout(m_vboxlayout_hide_mouse);

m_radio_cursor_visible_movement = new QRadioButton(tr("On Movement"));
m_radio_cursor_visible_movement->setToolTip(
tr("Mouse Cursor hides after inactivity and returns upon Mouse Cursor movement."));
m_radio_cursor_visible_never = new QRadioButton(tr("Never"));
m_radio_cursor_visible_never->setToolTip(
tr("Mouse Cursor will never be visible while a game is running."));
m_radio_cursor_visible_always = new QRadioButton(tr("Always"));
m_radio_cursor_visible_always->setToolTip(tr("Mouse Cursor will always be visible."));

m_vboxlayout_hide_mouse->addWidget(m_radio_cursor_visible_movement);
m_vboxlayout_hide_mouse->addWidget(m_radio_cursor_visible_never);
m_vboxlayout_hide_mouse->addWidget(m_radio_cursor_visible_always);

m_checkbox_lock_mouse = new QCheckBox(tr("Lock Mouse Cursor"));
m_checkbox_lock_mouse->setToolTip(tr("Will lock the Mouse Cursor to the Render Widget as long as "
"it has focus. You can set a hotkey to unlock it."));

mouse_groupbox->setLayout(m_vboxlayout_hide_mouse);
groupbox_layout->addWidget(m_checkbox_top_window);
groupbox_layout->addWidget(m_checkbox_confirm_on_stop);
groupbox_layout->addWidget(m_checkbox_use_panic_handlers);
groupbox_layout->addWidget(m_checkbox_enable_osd);
groupbox_layout->addWidget(m_checkbox_show_active_title);
groupbox_layout->addWidget(m_checkbox_pause_on_focus_lost);
groupbox_layout->addWidget(m_checkbox_hide_mouse);
groupbox_layout->addWidget(mouse_groupbox);
#ifdef _WIN32
groupbox_layout->addWidget(m_checkbox_lock_mouse);
#endif
Expand All @@ -211,8 +225,12 @@ void InterfacePane::ConnectLayout()
connect(m_checkbox_show_active_title, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
connect(m_checkbox_enable_osd, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
connect(m_checkbox_pause_on_focus_lost, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
connect(m_checkbox_hide_mouse, &QCheckBox::toggled, &Settings::Instance(),
&Settings::SetHideCursor);
connect(m_radio_cursor_visible_movement, &QRadioButton::toggled, this,
&InterfacePane::OnCursorVisibleMovement);
connect(m_radio_cursor_visible_never, &QRadioButton::toggled, this,
&InterfacePane::OnCursorVisibleNever);
connect(m_radio_cursor_visible_always, &QRadioButton::toggled, this,
&InterfacePane::OnCursorVisibleAlways);
connect(m_checkbox_lock_mouse, &QCheckBox::toggled, &Settings::Instance(),
&Settings::SetLockCursor);
connect(m_checkbox_use_userstyle, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
Expand Down Expand Up @@ -250,7 +268,13 @@ void InterfacePane::LoadConfig()
m_checkbox_pause_on_focus_lost->setChecked(startup_params.m_PauseOnFocusLost);
m_checkbox_use_covers->setChecked(Config::Get(Config::MAIN_USE_GAME_COVERS));
m_checkbox_focused_hotkeys->setChecked(Config::Get(Config::MAIN_FOCUSED_HOTKEYS));
m_checkbox_hide_mouse->setChecked(Settings::Instance().GetHideCursor());
m_radio_cursor_visible_movement->setChecked(Settings::Instance().GetCursorVisibility() ==
SConfig::ShowCursor::OnMovement);
m_radio_cursor_visible_always->setChecked(Settings::Instance().GetCursorVisibility() ==
SConfig::ShowCursor::Constantly);
m_radio_cursor_visible_never->setChecked(Settings::Instance().GetCursorVisibility() ==
SConfig::ShowCursor::Never);

m_checkbox_lock_mouse->setChecked(Settings::Instance().GetLockCursor());
m_checkbox_disable_screensaver->setChecked(Config::Get(Config::MAIN_DISABLE_SCREENSAVER));
}
Expand Down Expand Up @@ -300,3 +324,18 @@ void InterfacePane::OnSaveConfig()

settings.SaveSettings();
}

void InterfacePane::OnCursorVisibleMovement()
{
Settings::Instance().SetCursorVisibility(SConfig::ShowCursor::OnMovement);
}

void InterfacePane::OnCursorVisibleNever()
{
Settings::Instance().SetCursorVisibility(SConfig::ShowCursor::Never);
}

void InterfacePane::OnCursorVisibleAlways()
{
Settings::Instance().SetCursorVisibility(SConfig::ShowCursor::Constantly);
}
8 changes: 7 additions & 1 deletion Source/Core/DolphinQt/Settings/InterfacePane.h
Expand Up @@ -8,6 +8,7 @@
class QCheckBox;
class QComboBox;
class QLabel;
class QRadioButton;
class QVBoxLayout;

class InterfacePane final : public QWidget
Expand All @@ -23,6 +24,9 @@ class InterfacePane final : public QWidget
void ConnectLayout();
void LoadConfig();
void OnSaveConfig();
void OnCursorVisibleMovement();
void OnCursorVisibleNever();
void OnCursorVisibleAlways();

QVBoxLayout* m_main_layout;
QComboBox* m_combobox_language;
Expand All @@ -43,6 +47,8 @@ class InterfacePane final : public QWidget
QCheckBox* m_checkbox_enable_osd;
QCheckBox* m_checkbox_show_active_title;
QCheckBox* m_checkbox_pause_on_focus_lost;
QCheckBox* m_checkbox_hide_mouse;
QRadioButton* m_radio_cursor_visible_movement;
QRadioButton* m_radio_cursor_visible_never;
QRadioButton* m_radio_cursor_visible_always;
QCheckBox* m_checkbox_lock_mouse;
};

0 comments on commit 2aa400e

Please sign in to comment.