mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-22 04:24:44 +00:00
imgui/renderer: Hide Cursor on Idle Implementation
Implement hide cursor on idle w/ idle timeout duration (configurable via GUI). While at it add always and never to hide the cursor options as well. * Revert commit #1211 as to not interfere with the cursor states. * Make hide cursor on idle as the default setting w/ timeout duration of 5 seconds to hide. * Add an input tab in the settings page to add the hide cursor setting, with hiding the idle timeout box with respect to the cursor hide option.
This commit is contained in:
parent
4ce95e55e0
commit
d4627fd2e1
7 changed files with 296 additions and 12 deletions
|
@ -56,6 +56,8 @@ static bool vkValidationGpu = false;
|
|||
static bool rdocEnable = false;
|
||||
static bool vkMarkers = false;
|
||||
static bool vkCrashDiagnostic = false;
|
||||
static s16 cursorState = HideCursorState::Idle;
|
||||
static int cursorHideTimeout = 5; // 5 seconds (default)
|
||||
|
||||
// Gui
|
||||
std::filesystem::path settings_install_dir = {};
|
||||
|
@ -95,6 +97,14 @@ int getBGMvolume() {
|
|||
return BGMvolume;
|
||||
}
|
||||
|
||||
s16 getCursorState() {
|
||||
return cursorState;
|
||||
}
|
||||
|
||||
int getCursorHideTimeout() {
|
||||
return cursorHideTimeout;
|
||||
}
|
||||
|
||||
u32 getScreenWidth() {
|
||||
return screenWidth;
|
||||
}
|
||||
|
@ -251,6 +261,14 @@ void setBGMvolume(int volume) {
|
|||
BGMvolume = volume;
|
||||
}
|
||||
|
||||
void setCursorState(s16 newCursorState) {
|
||||
cursorState = newCursorState;
|
||||
}
|
||||
|
||||
void setCursorHideTimeout(int newcursorHideTimeout) {
|
||||
cursorHideTimeout = newcursorHideTimeout;
|
||||
}
|
||||
|
||||
void setLanguage(u32 language) {
|
||||
m_language = language;
|
||||
}
|
||||
|
@ -440,6 +458,8 @@ void load(const std::filesystem::path& path) {
|
|||
if (data.contains("Input")) {
|
||||
const toml::value& input = data.at("Input");
|
||||
|
||||
cursorState = toml::find_or<int>(input, "cursorState", HideCursorState::Idle);
|
||||
cursorHideTimeout = toml::find_or<int>(input, "cursorHideTimeout", 5);
|
||||
useSpecialPad = toml::find_or<bool>(input, "useSpecialPad", false);
|
||||
specialPadClass = toml::find_or<int>(input, "specialPadClass", 1);
|
||||
}
|
||||
|
@ -533,6 +553,8 @@ void save(const std::filesystem::path& path) {
|
|||
data["General"]["updateChannel"] = updateChannel;
|
||||
data["General"]["showSplash"] = isShowSplash;
|
||||
data["General"]["autoUpdate"] = isAutoUpdate;
|
||||
data["Input"]["cursorState"] = cursorState;
|
||||
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
|
||||
data["Input"]["useSpecialPad"] = useSpecialPad;
|
||||
data["Input"]["specialPadClass"] = specialPadClass;
|
||||
data["GPU"]["screenWidth"] = screenWidth;
|
||||
|
@ -581,6 +603,8 @@ void setDefaultValues() {
|
|||
isFullscreen = false;
|
||||
playBGM = false;
|
||||
BGMvolume = 50;
|
||||
cursorState = HideCursorState::Idle;
|
||||
cursorHideTimeout = 5;
|
||||
screenWidth = 1280;
|
||||
screenHeight = 720;
|
||||
logFilter = "";
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
#include "types.h"
|
||||
|
||||
namespace Config {
|
||||
|
||||
enum HideCursorState : s16 { Never, Idle, Always };
|
||||
|
||||
void load(const std::filesystem::path& path);
|
||||
void save(const std::filesystem::path& path);
|
||||
|
||||
|
@ -16,6 +19,9 @@ bool isFullscreenMode();
|
|||
bool getPlayBGM();
|
||||
int getBGMvolume();
|
||||
|
||||
s16 getCursorState();
|
||||
int getCursorHideTimeout();
|
||||
|
||||
std::string getLogFilter();
|
||||
std::string getLogType();
|
||||
std::string getUserName();
|
||||
|
@ -50,6 +56,8 @@ void setScreenHeight(u32 height);
|
|||
void setFullscreenMode(bool enable);
|
||||
void setPlayBGM(bool enable);
|
||||
void setBGMvolume(int volume);
|
||||
void setCursorState(s16 cursorState);
|
||||
void setCursorHideTimeout(int newcursorHideTimeout);
|
||||
void setLanguage(u32 language);
|
||||
void setNeoMode(bool enable);
|
||||
void setUserName(const std::string& type);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
// Based on imgui_impl_sdl3.cpp from Dear ImGui repository
|
||||
|
||||
#include <imgui.h>
|
||||
#include "common/config.h"
|
||||
#include "imgui_impl_sdl3.h"
|
||||
|
||||
// SDL
|
||||
|
@ -36,6 +37,8 @@ struct SdlData {
|
|||
SDL_Cursor* mouse_cursors[ImGuiMouseCursor_COUNT]{};
|
||||
SDL_Cursor* mouse_last_cursor{};
|
||||
int mouse_pending_leave_frame{};
|
||||
ImVec2 prev_mouse_pos{0, 0};
|
||||
Uint64 lastCursorMoveTime{};
|
||||
|
||||
// Gamepad handling
|
||||
ImVector<SDL_Gamepad*> gamepads{};
|
||||
|
@ -371,6 +374,13 @@ bool ProcessEvent(const SDL_Event* event) {
|
|||
? ImGuiMouseSource_TouchScreen
|
||||
: ImGuiMouseSource_Mouse);
|
||||
io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
|
||||
if (mouse_pos.x != bd->prev_mouse_pos.x || mouse_pos.y != bd->prev_mouse_pos.y) {
|
||||
bd->prev_mouse_pos.x = mouse_pos.x;
|
||||
bd->prev_mouse_pos.y = mouse_pos.y;
|
||||
if (Config::getCursorState() == Config::HideCursorState::Idle) {
|
||||
bd->lastCursorMoveTime = bd->time;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case SDL_EVENT_MOUSE_WHEEL: {
|
||||
|
@ -447,6 +457,7 @@ bool ProcessEvent(const SDL_Event* event) {
|
|||
return false;
|
||||
bd->mouse_window_id = event->window.windowID;
|
||||
bd->mouse_pending_leave_frame = 0;
|
||||
bd->lastCursorMoveTime = bd->time;
|
||||
return true;
|
||||
}
|
||||
// - In some cases, when detaching a window from main viewport SDL may send
|
||||
|
@ -459,6 +470,7 @@ bool ProcessEvent(const SDL_Event* event) {
|
|||
if (GetViewportForWindowId(event->window.windowID) == NULL)
|
||||
return false;
|
||||
bd->mouse_pending_leave_frame = ImGui::GetFrameCount() + 1;
|
||||
bd->lastCursorMoveTime = bd->time;
|
||||
return true;
|
||||
}
|
||||
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
||||
|
@ -600,7 +612,18 @@ static void UpdateMouseData() {
|
|||
int window_x, window_y;
|
||||
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
|
||||
SDL_GetWindowPosition(focused_window, &window_x, &window_y);
|
||||
io.AddMousePosEvent(mouse_x_global - (float)window_x, mouse_y_global - (float)window_y);
|
||||
mouse_x_global -= (float)window_x;
|
||||
mouse_y_global -= (float)window_y;
|
||||
io.AddMousePosEvent(mouse_x_global, mouse_y_global);
|
||||
// SDL_EVENT_MOUSE_MOTION isn't triggered before the first frame is rendered
|
||||
// force update the prev_cursor coords
|
||||
if (mouse_x_global != bd->prev_mouse_pos.x || mouse_y_global != bd->prev_mouse_pos.y &&
|
||||
bd->prev_mouse_pos.y == 0 &&
|
||||
bd->prev_mouse_pos.x == 0) {
|
||||
bd->prev_mouse_pos.x = mouse_x_global;
|
||||
bd->prev_mouse_pos.y = mouse_y_global;
|
||||
bd->lastCursorMoveTime = bd->time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -611,10 +634,25 @@ static void UpdateMouseCursor() {
|
|||
return;
|
||||
SdlData* bd = GetBackendData();
|
||||
|
||||
s16 cursorState = Config::getCursorState();
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None) {
|
||||
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None ||
|
||||
cursorState == Config::HideCursorState::Always) {
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
SDL_HideCursor();
|
||||
|
||||
} else if (cursorState == Config::HideCursorState::Idle &&
|
||||
bd->time - bd->lastCursorMoveTime >=
|
||||
Config::getCursorHideTimeout() * SDL_GetPerformanceFrequency()) {
|
||||
|
||||
bool wasCursorVisible = SDL_CursorVisible();
|
||||
SDL_HideCursor();
|
||||
|
||||
if (wasCursorVisible) {
|
||||
SDL_WarpMouseInWindow(SDL_GetKeyboardFocus(), bd->prev_mouse_pos.x,
|
||||
bd->prev_mouse_pos.y); // Force refresh the cursor state
|
||||
}
|
||||
|
||||
} else {
|
||||
// Show OS mouse cursor
|
||||
SDL_Cursor* expected_cursor = bd->mouse_cursors[imgui_cursor]
|
||||
|
|
|
@ -47,6 +47,8 @@ QStringList languageNames = {"Arabic",
|
|||
const QVector<int> languageIndexes = {21, 23, 14, 6, 18, 1, 12, 22, 2, 4, 25, 24, 29, 5, 0,
|
||||
9, 15, 16, 17, 7, 26, 8, 11, 20, 3, 13, 27, 10, 19, 28};
|
||||
|
||||
QStringList hideCursorStates = {"Never", "Idle", "Always"};
|
||||
|
||||
SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidget* parent)
|
||||
: QDialog(parent), ui(new Ui::SettingsDialog) {
|
||||
ui->setupUi(this);
|
||||
|
@ -67,6 +69,8 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
|||
completer->setCaseSensitivity(Qt::CaseInsensitive);
|
||||
ui->consoleLanguageComboBox->setCompleter(completer);
|
||||
|
||||
ui->hideCursorComboBox->addItems(hideCursorStates);
|
||||
|
||||
InitializeEmulatorLanguages();
|
||||
LoadValuesFromConfig();
|
||||
|
||||
|
@ -153,6 +157,18 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
|||
});
|
||||
}
|
||||
|
||||
// Input TAB
|
||||
{
|
||||
connect(ui->hideCursorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
[this](s16 index) {
|
||||
Config::setCursorState(index);
|
||||
OnCursorStateChanged(index);
|
||||
});
|
||||
|
||||
connect(ui->idleTimeoutSpinBox, &QSpinBox::valueChanged, this,
|
||||
[](int index) { Config::setCursorHideTimeout(index); });
|
||||
}
|
||||
|
||||
// GPU TAB
|
||||
{
|
||||
// First options is auto selection -1, so gpuId on the GUI will always have to subtract 1
|
||||
|
@ -228,6 +244,9 @@ void SettingsDialog::LoadValuesFromConfig() {
|
|||
std::find(languageIndexes.begin(), languageIndexes.end(), Config::GetLanguage())) %
|
||||
languageIndexes.size());
|
||||
ui->emulatorLanguageComboBox->setCurrentIndex(languages[Config::getEmulatorLanguage()]);
|
||||
ui->hideCursorComboBox->setCurrentIndex(Config::getCursorState());
|
||||
OnCursorStateChanged(Config::getCursorState());
|
||||
ui->idleTimeoutSpinBox->setValue(Config::getCursorHideTimeout());
|
||||
ui->graphicsAdapterBox->setCurrentIndex(Config::getGpuId() + 1);
|
||||
ui->widthSpinBox->setValue(Config::getScreenWidth());
|
||||
ui->heightSpinBox->setValue(Config::getScreenHeight());
|
||||
|
@ -289,6 +308,18 @@ void SettingsDialog::OnLanguageChanged(int index) {
|
|||
emit LanguageChanged(ui->emulatorLanguageComboBox->itemData(index).toString().toStdString());
|
||||
}
|
||||
|
||||
void SettingsDialog::OnCursorStateChanged(s16 index) {
|
||||
if (index == -1)
|
||||
return;
|
||||
if (index == Config::HideCursorState::Idle) {
|
||||
ui->idleTimeoutGroupBox->show();
|
||||
} else {
|
||||
if (!ui->idleTimeoutGroupBox->isHidden()) {
|
||||
ui->idleTimeoutGroupBox->hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SettingsDialog::exec() {
|
||||
return QDialog::exec();
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ private:
|
|||
void LoadValuesFromConfig();
|
||||
void InitializeEmulatorLanguages();
|
||||
void OnLanguageChanged(int index);
|
||||
void OnCursorStateChanged(s16 index);
|
||||
|
||||
std::unique_ptr<Ui::SettingsDialog> ui;
|
||||
|
||||
|
|
|
@ -34,9 +34,18 @@
|
|||
<iconset>
|
||||
<normaloff>:/images/shadps4.ico</normaloff>:/images/shadps4.ico</iconset>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="settingsDialogLayout">
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
|
@ -51,8 +60,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>836</width>
|
||||
<height>446</height>
|
||||
<width>832</width>
|
||||
<height>431</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -62,7 +71,7 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="generalTab">
|
||||
<attribute name="title">
|
||||
|
@ -369,7 +378,7 @@
|
|||
<x>10</x>
|
||||
<y>30</y>
|
||||
<width>241</width>
|
||||
<height>71</height>
|
||||
<height>92</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
|
@ -461,6 +470,185 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="inputTab">
|
||||
<attribute name="title">
|
||||
<string>Input</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="inputTabHLayoutTop" stretch="1,1,1">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="cursorTabLayoutLeft">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="HideCursor">
|
||||
<property name="title">
|
||||
<string>Cursor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="inputCursorLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="hideCursorGroupBox">
|
||||
<property name="title">
|
||||
<string>Hide Cursor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="hideCursorLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="hideCursorComboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="idleTimeoutGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>85</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Hide Cursor Idle Timeout</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="IdleTimeoutLayout" stretch="0,0">
|
||||
<property name="leftMargin">
|
||||
<number>70</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="idleTimeoutSpinBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LayoutDirection::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="wrapping">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::ButtonSymbols::UpDownArrows</enum>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>3600</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="displayIntegerBase">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="idleTimeoutDurationLabel">
|
||||
<property name="text">
|
||||
<string>s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="emptyTabLayoutMiddle">
|
||||
<item>
|
||||
<spacer name="emptyHorizontalSpacerMiddle">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="emptyTabLayoutRight">
|
||||
<item>
|
||||
<spacer name="emptyHorizontalSpacerRight">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="inputTabHLayoutBottom">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="emptyVerticalSpacerBottom">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="grphicsTab">
|
||||
<attribute name="title">
|
||||
<string>Graphics</string>
|
||||
|
|
|
@ -304,9 +304,6 @@ void WindowSDL::onKeyPress(const SDL_Event* event) {
|
|||
if (axis != Input::Axis::AxisMax) {
|
||||
controller->Axis(0, axis, ax);
|
||||
}
|
||||
if (SDL_GetCursor() != NULL) {
|
||||
SDL_HideCursor();
|
||||
}
|
||||
}
|
||||
|
||||
void WindowSDL::onGamepadEvent(const SDL_Event* event) {
|
||||
|
@ -332,9 +329,6 @@ void WindowSDL::onGamepadEvent(const SDL_Event* event) {
|
|||
if (button != 0) {
|
||||
controller->CheckButton(0, button, event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN);
|
||||
}
|
||||
if (SDL_GetCursor() != NULL) {
|
||||
SDL_HideCursor();
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||
axis = event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFTX ? Input::Axis::LeftX
|
||||
|
|
Loading…
Add table
Reference in a new issue