Merge pull request #9697 from Filoppi/cursor_locking
Implement Cursor Locking and input focus checks for it
This commit is contained in:
commit
45a5c9cc04
|
@ -151,6 +151,12 @@ bool Host_RendererHasFocus()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Host_RendererHasFullFocus()
|
||||||
|
{
|
||||||
|
// Mouse cursor locking actually exists in Android but we don't implement (nor need) that
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Host_RendererIsFullscreen()
|
bool Host_RendererIsFullscreen()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -147,6 +147,7 @@ void SConfig::SaveInterfaceSettings(IniFile& ini)
|
||||||
|
|
||||||
interface->Set("ConfirmStop", bConfirmStop);
|
interface->Set("ConfirmStop", bConfirmStop);
|
||||||
interface->Set("HideCursor", bHideCursor);
|
interface->Set("HideCursor", bHideCursor);
|
||||||
|
interface->Set("LockCursor", bLockCursor);
|
||||||
interface->Set("LanguageCode", m_InterfaceLanguage);
|
interface->Set("LanguageCode", m_InterfaceLanguage);
|
||||||
interface->Set("ExtendedFPSInfo", m_InterfaceExtendedFPSInfo);
|
interface->Set("ExtendedFPSInfo", m_InterfaceExtendedFPSInfo);
|
||||||
interface->Set("ShowActiveTitle", m_show_active_title);
|
interface->Set("ShowActiveTitle", m_show_active_title);
|
||||||
|
@ -401,6 +402,7 @@ void SConfig::LoadInterfaceSettings(IniFile& ini)
|
||||||
|
|
||||||
interface->Get("ConfirmStop", &bConfirmStop, true);
|
interface->Get("ConfirmStop", &bConfirmStop, true);
|
||||||
interface->Get("HideCursor", &bHideCursor, false);
|
interface->Get("HideCursor", &bHideCursor, false);
|
||||||
|
interface->Get("LockCursor", &bLockCursor, false);
|
||||||
interface->Get("LanguageCode", &m_InterfaceLanguage, "");
|
interface->Get("LanguageCode", &m_InterfaceLanguage, "");
|
||||||
interface->Get("ExtendedFPSInfo", &m_InterfaceExtendedFPSInfo, false);
|
interface->Get("ExtendedFPSInfo", &m_InterfaceExtendedFPSInfo, false);
|
||||||
interface->Get("ShowActiveTitle", &m_show_active_title, true);
|
interface->Get("ShowActiveTitle", &m_show_active_title, true);
|
||||||
|
|
|
@ -150,6 +150,7 @@ struct SConfig
|
||||||
// Interface settings
|
// Interface settings
|
||||||
bool bConfirmStop = false;
|
bool bConfirmStop = false;
|
||||||
bool bHideCursor = false;
|
bool bHideCursor = false;
|
||||||
|
bool bLockCursor = false;
|
||||||
std::string theme_name;
|
std::string theme_name;
|
||||||
|
|
||||||
// Bluetooth passthrough mode settings
|
// Bluetooth passthrough mode settings
|
||||||
|
|
|
@ -1113,10 +1113,15 @@ void DoFrameStep()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateInputGate(bool require_focus)
|
void UpdateInputGate(bool require_focus, bool require_full_focus)
|
||||||
{
|
{
|
||||||
ControlReference::SetInputGate((!require_focus || Host_RendererHasFocus()) &&
|
// If the user accepts background input, controls should pass even if an on screen interface is on
|
||||||
!Host_UIBlocksControllerState());
|
const bool focus_passes =
|
||||||
|
!require_focus || (Host_RendererHasFocus() && !Host_UIBlocksControllerState());
|
||||||
|
// Ignore full focus if we don't require basic focus
|
||||||
|
const bool full_focus_passes =
|
||||||
|
!require_focus || !require_full_focus || (focus_passes && Host_RendererHasFullFocus());
|
||||||
|
ControlReference::SetInputGate(focus_passes && full_focus_passes);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -169,6 +169,6 @@ void HostDispatchJobs();
|
||||||
|
|
||||||
void DoFrameStep();
|
void DoFrameStep();
|
||||||
|
|
||||||
void UpdateInputGate(bool require_focus);
|
void UpdateInputGate(bool require_focus, bool require_full_focus = false);
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -867,7 +867,8 @@ void Update(u64 ticks)
|
||||||
|
|
||||||
if (s_half_line_of_next_si_poll == s_half_line_count)
|
if (s_half_line_of_next_si_poll == s_half_line_count)
|
||||||
{
|
{
|
||||||
Core::UpdateInputGate(!SConfig::GetInstance().m_BackgroundInput);
|
Core::UpdateInputGate(!SConfig::GetInstance().m_BackgroundInput,
|
||||||
|
SConfig::GetInstance().bLockCursor);
|
||||||
SerialInterface::UpdateDevices();
|
SerialInterface::UpdateDevices();
|
||||||
s_half_line_of_next_si_poll += 2 * SerialInterface::GetPollXLines();
|
s_half_line_of_next_si_poll += 2 * SerialInterface::GetPollXLines();
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ enum class HostMessageID
|
||||||
std::vector<std::string> Host_GetPreferredLocales();
|
std::vector<std::string> Host_GetPreferredLocales();
|
||||||
bool Host_UIBlocksControllerState();
|
bool Host_UIBlocksControllerState();
|
||||||
bool Host_RendererHasFocus();
|
bool Host_RendererHasFocus();
|
||||||
|
bool Host_RendererHasFullFocus();
|
||||||
bool Host_RendererIsFullscreen();
|
bool Host_RendererIsFullscreen();
|
||||||
|
|
||||||
void Host_Message(HostMessageID id);
|
void Host_Message(HostMessageID id);
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include "InputCommon/GCPadStatus.h"
|
#include "InputCommon/GCPadStatus.h"
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
constexpr std::array<const char*, 125> s_hotkey_labels{{
|
constexpr std::array<const char*, 126> s_hotkey_labels{{
|
||||||
_trans("Open"),
|
_trans("Open"),
|
||||||
_trans("Change Disc"),
|
_trans("Change Disc"),
|
||||||
_trans("Eject Disc"),
|
_trans("Eject Disc"),
|
||||||
|
@ -35,6 +35,7 @@ constexpr std::array<const char*, 125> s_hotkey_labels{{
|
||||||
_trans("Toggle Fullscreen"),
|
_trans("Toggle Fullscreen"),
|
||||||
_trans("Take Screenshot"),
|
_trans("Take Screenshot"),
|
||||||
_trans("Exit"),
|
_trans("Exit"),
|
||||||
|
_trans("Unlock Cursor"),
|
||||||
_trans("Activate NetPlay Chat"),
|
_trans("Activate NetPlay Chat"),
|
||||||
_trans("Control NetPlay Golf Mode"),
|
_trans("Control NetPlay Golf Mode"),
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ enum Hotkey
|
||||||
HK_FULLSCREEN,
|
HK_FULLSCREEN,
|
||||||
HK_SCREENSHOT,
|
HK_SCREENSHOT,
|
||||||
HK_EXIT,
|
HK_EXIT,
|
||||||
|
HK_UNLOCK_CURSOR,
|
||||||
HK_ACTIVATE_CHAT,
|
HK_ACTIVATE_CHAT,
|
||||||
HK_REQUEST_GOLF_CONTROL,
|
HK_REQUEST_GOLF_CONTROL,
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,12 @@ bool Host_RendererHasFocus()
|
||||||
return s_platform->IsWindowFocused();
|
return s_platform->IsWindowFocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Host_RendererHasFullFocus()
|
||||||
|
{
|
||||||
|
// Mouse capturing isn't implemented
|
||||||
|
return Host_RendererHasFocus();
|
||||||
|
}
|
||||||
|
|
||||||
bool Host_RendererIsFullscreen()
|
bool Host_RendererIsFullscreen()
|
||||||
{
|
{
|
||||||
return s_platform->IsWindowFullscreen();
|
return s_platform->IsWindowFullscreen();
|
||||||
|
|
|
@ -51,6 +51,6 @@ protected:
|
||||||
Common::Flag m_shutdown_requested{false};
|
Common::Flag m_shutdown_requested{false};
|
||||||
Common::Flag m_tried_graceful_shutdown{false};
|
Common::Flag m_tried_graceful_shutdown{false};
|
||||||
|
|
||||||
bool m_window_focus = true;
|
bool m_window_focus = true; // Should be made atomic if actually implemented
|
||||||
bool m_window_fullscreen = false;
|
bool m_window_fullscreen = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,10 @@
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Common/Common.h"
|
#include "Common/Common.h"
|
||||||
|
|
||||||
#include "Core/Config/MainSettings.h"
|
#include "Core/Config/MainSettings.h"
|
||||||
|
@ -49,6 +53,8 @@ Host* Host::GetInstance()
|
||||||
|
|
||||||
void Host::SetRenderHandle(void* handle)
|
void Host::SetRenderHandle(void* handle)
|
||||||
{
|
{
|
||||||
|
m_render_to_main = Config::Get(Config::MAIN_RENDER_TO_MAIN);
|
||||||
|
|
||||||
if (m_render_handle == handle)
|
if (m_render_handle == handle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -61,9 +67,27 @@ void Host::SetRenderHandle(void* handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Host::SetMainWindowHandle(void* handle)
|
||||||
|
{
|
||||||
|
m_main_window_handle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
bool Host::GetRenderFocus()
|
bool Host::GetRenderFocus()
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Unfortunately Qt calls SetRenderFocus() with a slight delay compared to what we actually need
|
||||||
|
// to avoid inputs that cause a focus loss to be processed by the emulation
|
||||||
|
if (m_render_to_main)
|
||||||
|
return GetForegroundWindow() == (HWND)m_main_window_handle.load();
|
||||||
|
return GetForegroundWindow() == (HWND)m_render_handle.load();
|
||||||
|
#else
|
||||||
return m_render_focus;
|
return m_render_focus;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Host::GetRenderFullFocus()
|
||||||
|
{
|
||||||
|
return m_render_full_focus;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Host::SetRenderFocus(bool focus)
|
void Host::SetRenderFocus(bool focus)
|
||||||
|
@ -76,6 +100,11 @@ void Host::SetRenderFocus(bool focus)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Host::SetRenderFullFocus(bool focus)
|
||||||
|
{
|
||||||
|
m_render_full_focus = focus;
|
||||||
|
}
|
||||||
|
|
||||||
bool Host::GetRenderFullscreen()
|
bool Host::GetRenderFullscreen()
|
||||||
{
|
{
|
||||||
return m_render_fullscreen;
|
return m_render_fullscreen;
|
||||||
|
@ -131,6 +160,11 @@ bool Host_RendererHasFocus()
|
||||||
return Host::GetInstance()->GetRenderFocus();
|
return Host::GetInstance()->GetRenderFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Host_RendererHasFullFocus()
|
||||||
|
{
|
||||||
|
return Host::GetInstance()->GetRenderFullFocus();
|
||||||
|
}
|
||||||
|
|
||||||
bool Host_RendererIsFullscreen()
|
bool Host_RendererIsFullscreen()
|
||||||
{
|
{
|
||||||
return Host::GetInstance()->GetRenderFullscreen();
|
return Host::GetInstance()->GetRenderFullscreen();
|
||||||
|
|
|
@ -23,10 +23,13 @@ public:
|
||||||
static Host* GetInstance();
|
static Host* GetInstance();
|
||||||
|
|
||||||
bool GetRenderFocus();
|
bool GetRenderFocus();
|
||||||
|
bool GetRenderFullFocus();
|
||||||
bool GetRenderFullscreen();
|
bool GetRenderFullscreen();
|
||||||
|
|
||||||
|
void SetMainWindowHandle(void* handle);
|
||||||
void SetRenderHandle(void* handle);
|
void SetRenderHandle(void* handle);
|
||||||
void SetRenderFocus(bool focus);
|
void SetRenderFocus(bool focus);
|
||||||
|
void SetRenderFullFocus(bool focus);
|
||||||
void SetRenderFullscreen(bool fullscreen);
|
void SetRenderFullscreen(bool fullscreen);
|
||||||
void ResizeSurface(int new_width, int new_height);
|
void ResizeSurface(int new_width, int new_height);
|
||||||
void RequestNotifyMapLoaded();
|
void RequestNotifyMapLoaded();
|
||||||
|
@ -42,6 +45,9 @@ private:
|
||||||
Host();
|
Host();
|
||||||
|
|
||||||
std::atomic<void*> m_render_handle{nullptr};
|
std::atomic<void*> m_render_handle{nullptr};
|
||||||
|
std::atomic<void*> m_main_window_handle{nullptr};
|
||||||
|
std::atomic<bool> m_render_to_main{false};
|
||||||
std::atomic<bool> m_render_focus{false};
|
std::atomic<bool> m_render_focus{false};
|
||||||
|
std::atomic<bool> m_render_full_focus{false};
|
||||||
std::atomic<bool> m_render_fullscreen{false};
|
std::atomic<bool> m_render_fullscreen{false};
|
||||||
};
|
};
|
||||||
|
|
|
@ -213,6 +213,10 @@ void HotkeyScheduler::Run()
|
||||||
if (IsHotkey(HK_EXIT))
|
if (IsHotkey(HK_EXIT))
|
||||||
emit ExitHotkey();
|
emit ExitHotkey();
|
||||||
|
|
||||||
|
// Unlock Cursor
|
||||||
|
if (IsHotkey(HK_UNLOCK_CURSOR))
|
||||||
|
emit UnlockCursor();
|
||||||
|
|
||||||
auto& settings = Settings::Instance();
|
auto& settings = Settings::Instance();
|
||||||
|
|
||||||
// Toggle Chat
|
// Toggle Chat
|
||||||
|
|
|
@ -27,6 +27,7 @@ signals:
|
||||||
void ChangeDisc();
|
void ChangeDisc();
|
||||||
|
|
||||||
void ExitHotkey();
|
void ExitHotkey();
|
||||||
|
void UnlockCursor();
|
||||||
void ActivateChat();
|
void ActivateChat();
|
||||||
void RequestGolfControl();
|
void RequestGolfControl();
|
||||||
void FullScreenHotkey();
|
void FullScreenHotkey();
|
||||||
|
|
|
@ -269,6 +269,8 @@ MainWindow::MainWindow(std::unique_ptr<BootParameters> boot_parameters,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Host::GetInstance()->SetMainWindowHandle(reinterpret_cast<void*>(winId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
|
@ -547,6 +549,7 @@ void MainWindow::ConnectHotkeys()
|
||||||
connect(m_hotkey_scheduler, &HotkeyScheduler::ChangeDisc, this, &MainWindow::ChangeDisc);
|
connect(m_hotkey_scheduler, &HotkeyScheduler::ChangeDisc, this, &MainWindow::ChangeDisc);
|
||||||
connect(m_hotkey_scheduler, &HotkeyScheduler::EjectDisc, this, &MainWindow::EjectDisc);
|
connect(m_hotkey_scheduler, &HotkeyScheduler::EjectDisc, this, &MainWindow::EjectDisc);
|
||||||
connect(m_hotkey_scheduler, &HotkeyScheduler::ExitHotkey, this, &MainWindow::close);
|
connect(m_hotkey_scheduler, &HotkeyScheduler::ExitHotkey, this, &MainWindow::close);
|
||||||
|
connect(m_hotkey_scheduler, &HotkeyScheduler::UnlockCursor, this, &MainWindow::UnlockCursor);
|
||||||
connect(m_hotkey_scheduler, &HotkeyScheduler::TogglePauseHotkey, this, &MainWindow::TogglePause);
|
connect(m_hotkey_scheduler, &HotkeyScheduler::TogglePauseHotkey, this, &MainWindow::TogglePause);
|
||||||
connect(m_hotkey_scheduler, &HotkeyScheduler::ActivateChat, this, &MainWindow::OnActivateChat);
|
connect(m_hotkey_scheduler, &HotkeyScheduler::ActivateChat, this, &MainWindow::OnActivateChat);
|
||||||
connect(m_hotkey_scheduler, &HotkeyScheduler::RequestGolfControl, this,
|
connect(m_hotkey_scheduler, &HotkeyScheduler::RequestGolfControl, this,
|
||||||
|
@ -813,6 +816,13 @@ bool MainWindow::RequestStop()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool rendered_widget_was_active =
|
||||||
|
m_render_widget->isActiveWindow() && !m_render_widget->isFullScreen();
|
||||||
|
QWidget* confirm_parent = (!m_rendering_to_main && rendered_widget_was_active) ?
|
||||||
|
m_render_widget :
|
||||||
|
static_cast<QWidget*>(this);
|
||||||
|
const bool was_cursor_locked = m_render_widget->IsCursorLocked();
|
||||||
|
|
||||||
if (!m_render_widget->isFullScreen())
|
if (!m_render_widget->isFullScreen())
|
||||||
m_render_widget_geometry = m_render_widget->saveGeometry();
|
m_render_widget_geometry = m_render_widget->saveGeometry();
|
||||||
else
|
else
|
||||||
|
@ -833,21 +843,44 @@ bool MainWindow::RequestStop()
|
||||||
if (pause)
|
if (pause)
|
||||||
Core::SetState(Core::State::Paused);
|
Core::SetState(Core::State::Paused);
|
||||||
|
|
||||||
|
if (rendered_widget_was_active)
|
||||||
|
{
|
||||||
|
// We have to do this before creating the message box, otherwise we might receive the window
|
||||||
|
// activation event before we know we need to lock the cursor again.
|
||||||
|
m_render_widget->SetCursorLockedOnNextActivation(was_cursor_locked);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is to avoid any "race conditions" between the "Window Activate" message and the
|
||||||
|
// message box returning, which could break cursor locking depending on the order
|
||||||
|
m_render_widget->SetWaitingForMessageBox(true);
|
||||||
auto confirm = ModalMessageBox::question(
|
auto confirm = ModalMessageBox::question(
|
||||||
m_rendering_to_main ? static_cast<QWidget*>(this) : m_render_widget, tr("Confirm"),
|
confirm_parent, tr("Confirm"),
|
||||||
m_stop_requested ? tr("A shutdown is already in progress. Unsaved data "
|
m_stop_requested ? tr("A shutdown is already in progress. Unsaved data "
|
||||||
"may be lost if you stop the current emulation "
|
"may be lost if you stop the current emulation "
|
||||||
"before it completes. Force stop?") :
|
"before it completes. Force stop?") :
|
||||||
tr("Do you want to stop the current emulation?"),
|
tr("Do you want to stop the current emulation?"),
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton, Qt::ApplicationModal);
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton, Qt::ApplicationModal);
|
||||||
|
|
||||||
|
// If a user confirmed stopping the emulation, we do not capture the cursor again,
|
||||||
|
// even if the render widget will stay alive for a while.
|
||||||
|
// If a used rejected stopping the emulation, we instead capture the cursor again,
|
||||||
|
// and let them continue playing as if nothing had happened
|
||||||
|
// (assuming cursor locking is on).
|
||||||
if (confirm != QMessageBox::Yes)
|
if (confirm != QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
|
m_render_widget->SetWaitingForMessageBox(false);
|
||||||
|
|
||||||
if (pause)
|
if (pause)
|
||||||
Core::SetState(state);
|
Core::SetState(state);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_render_widget->SetCursorLockedOnNextActivation(false);
|
||||||
|
// This needs to be after SetCursorLockedOnNextActivation(false) as it depends on it
|
||||||
|
m_render_widget->SetWaitingForMessageBox(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OnStopRecording();
|
OnStopRecording();
|
||||||
|
@ -917,6 +950,12 @@ void MainWindow::FullScreen()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::UnlockCursor()
|
||||||
|
{
|
||||||
|
if (!m_render_widget->isFullScreen())
|
||||||
|
m_render_widget->SetCursorLocked(false);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::ScreenShot()
|
void MainWindow::ScreenShot()
|
||||||
{
|
{
|
||||||
Core::SaveScreenShot();
|
Core::SaveScreenShot();
|
||||||
|
|
|
@ -108,6 +108,7 @@ private:
|
||||||
void SetFullScreenResolution(bool fullscreen);
|
void SetFullScreenResolution(bool fullscreen);
|
||||||
|
|
||||||
void FullScreen();
|
void FullScreen();
|
||||||
|
void UnlockCursor();
|
||||||
void ScreenShot();
|
void ScreenShot();
|
||||||
|
|
||||||
void CreateComponents();
|
void CreateComponents();
|
||||||
|
|
|
@ -32,9 +32,16 @@
|
||||||
#include "DolphinQt/Resources.h"
|
#include "DolphinQt/Resources.h"
|
||||||
#include "DolphinQt/Settings.h"
|
#include "DolphinQt/Settings.h"
|
||||||
|
|
||||||
|
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||||
|
|
||||||
#include "VideoCommon/RenderBase.h"
|
#include "VideoCommon/RenderBase.h"
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <WinUser.h>
|
||||||
|
#include <windef.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
|
RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
setWindowTitle(QStringLiteral("Dolphin"));
|
setWindowTitle(QStringLiteral("Dolphin"));
|
||||||
|
@ -79,7 +86,10 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
|
||||||
|
|
||||||
connect(&Settings::Instance(), &Settings::HideCursorChanged, this,
|
connect(&Settings::Instance(), &Settings::HideCursorChanged, this,
|
||||||
&RenderWidget::OnHideCursorChanged);
|
&RenderWidget::OnHideCursorChanged);
|
||||||
|
connect(&Settings::Instance(), &Settings::LockCursorChanged, this,
|
||||||
|
&RenderWidget::OnLockCursorChanged);
|
||||||
OnHideCursorChanged();
|
OnHideCursorChanged();
|
||||||
|
OnLockCursorChanged();
|
||||||
connect(&Settings::Instance(), &Settings::KeepWindowOnTopChanged, this,
|
connect(&Settings::Instance(), &Settings::KeepWindowOnTopChanged, this,
|
||||||
&RenderWidget::OnKeepOnTopChanged);
|
&RenderWidget::OnKeepOnTopChanged);
|
||||||
OnKeepOnTopChanged(Settings::Instance().IsKeepWindowOnTopEnabled());
|
OnKeepOnTopChanged(Settings::Instance().IsKeepWindowOnTopEnabled());
|
||||||
|
@ -128,7 +138,33 @@ void RenderWidget::dropEvent(QDropEvent* event)
|
||||||
|
|
||||||
void RenderWidget::OnHideCursorChanged()
|
void RenderWidget::OnHideCursorChanged()
|
||||||
{
|
{
|
||||||
setCursor(Settings::Instance().GetHideCursor() ? Qt::BlankCursor : Qt::ArrowCursor);
|
UpdateCursor();
|
||||||
|
}
|
||||||
|
void RenderWidget::OnLockCursorChanged()
|
||||||
|
{
|
||||||
|
SetCursorLocked(false);
|
||||||
|
UpdateCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calling this at any time will set the cursor (image) to the correct state
|
||||||
|
void RenderWidget::UpdateCursor()
|
||||||
|
{
|
||||||
|
if (!Settings::Instance().GetLockCursor())
|
||||||
|
{
|
||||||
|
// Only hide if the cursor is automatically locking (it will hide on lock).
|
||||||
|
// "Unhide" the cursor if we lost focus, otherwise it will disappear when hovering
|
||||||
|
// 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() &&
|
||||||
|
(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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderWidget::OnKeepOnTopChanged(bool top)
|
void RenderWidget::OnKeepOnTopChanged(bool top)
|
||||||
|
@ -138,14 +174,22 @@ void RenderWidget::OnKeepOnTopChanged(bool top)
|
||||||
setWindowFlags(top ? windowFlags() | Qt::WindowStaysOnTopHint :
|
setWindowFlags(top ? windowFlags() | Qt::WindowStaysOnTopHint :
|
||||||
windowFlags() & ~Qt::WindowStaysOnTopHint);
|
windowFlags() & ~Qt::WindowStaysOnTopHint);
|
||||||
|
|
||||||
|
m_dont_lock_cursor_on_show = true;
|
||||||
if (was_visible)
|
if (was_visible)
|
||||||
show();
|
show();
|
||||||
|
m_dont_lock_cursor_on_show = false;
|
||||||
|
|
||||||
|
UpdateCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderWidget::HandleCursorTimer()
|
void RenderWidget::HandleCursorTimer()
|
||||||
{
|
{
|
||||||
if (isActiveWindow())
|
if (!isActiveWindow())
|
||||||
|
return;
|
||||||
|
if (!Settings::Instance().GetLockCursor() || m_cursor_locked)
|
||||||
|
{
|
||||||
setCursor(Qt::BlankCursor);
|
setCursor(Qt::BlankCursor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderWidget::showFullScreen()
|
void RenderWidget::showFullScreen()
|
||||||
|
@ -159,6 +203,138 @@ void RenderWidget::showFullScreen()
|
||||||
emit SizeChanged(width() * dpr, height() * dpr);
|
emit SizeChanged(width() * dpr, height() * dpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lock the cursor within the window/widget internal borders, including the aspect ratio if wanted
|
||||||
|
void RenderWidget::SetCursorLocked(bool locked, bool follow_aspect_ratio)
|
||||||
|
{
|
||||||
|
// It seems like QT doesn't scale the window frame correctly with some DPIs
|
||||||
|
// so it might happen that the locked cursor can be on the frame of the window,
|
||||||
|
// being able to resize it, but that is a minor problem.
|
||||||
|
// As a hack, if necessary, we could always scale down the size by 2 pixel, to a min of 1 given
|
||||||
|
// that the size can be 0 already. We probably shouldn't scale axes already scaled by aspect ratio
|
||||||
|
QRect render_rect = geometry();
|
||||||
|
if (parentWidget())
|
||||||
|
{
|
||||||
|
render_rect.moveTopLeft(parentWidget()->mapToGlobal(render_rect.topLeft()));
|
||||||
|
}
|
||||||
|
auto scale = devicePixelRatioF(); // Seems to always be rounded on Win. Should we round results?
|
||||||
|
QPoint screen_offset = QPoint(0, 0);
|
||||||
|
if (window()->windowHandle() && window()->windowHandle()->screen())
|
||||||
|
{
|
||||||
|
screen_offset = window()->windowHandle()->screen()->geometry().topLeft();
|
||||||
|
}
|
||||||
|
render_rect.moveTopLeft(((render_rect.topLeft() - screen_offset) * scale) + screen_offset);
|
||||||
|
render_rect.setSize(render_rect.size() * scale);
|
||||||
|
|
||||||
|
if (follow_aspect_ratio)
|
||||||
|
{
|
||||||
|
// TODO: SetCursorLocked() should be re-called every time this value is changed?
|
||||||
|
// This might cause imprecisions of one pixel (but it won't cause the cursor to go over borders)
|
||||||
|
Common::Vec2 aspect_ratio = g_controller_interface.GetWindowInputScale();
|
||||||
|
if (aspect_ratio.x > 1.f)
|
||||||
|
{
|
||||||
|
const float new_half_width = float(render_rect.width()) / (aspect_ratio.x * 2.f);
|
||||||
|
// Only ceil if it was >= 0.25
|
||||||
|
const float ceiled_new_half_width = std::ceil(std::round(new_half_width * 2.f) / 2.f);
|
||||||
|
const int x_center = render_rect.center().x();
|
||||||
|
// Make a guess on which one to floor and ceil.
|
||||||
|
// For more precision, we should have kept the rounding point scale from above as well.
|
||||||
|
render_rect.setLeft(x_center - std::floor(new_half_width));
|
||||||
|
render_rect.setRight(x_center + ceiled_new_half_width);
|
||||||
|
}
|
||||||
|
if (aspect_ratio.y > 1.f)
|
||||||
|
{
|
||||||
|
const float new_half_height = render_rect.height() / (aspect_ratio.y * 2.f);
|
||||||
|
const float ceiled_new_half_height = std::ceil(std::round(new_half_height * 2.f) / 2.f);
|
||||||
|
const int y_center = render_rect.center().y();
|
||||||
|
render_rect.setTop(y_center - std::floor(new_half_height));
|
||||||
|
render_rect.setBottom(y_center + ceiled_new_half_height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locked)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
RECT rect;
|
||||||
|
rect.left = render_rect.left();
|
||||||
|
rect.right = render_rect.right();
|
||||||
|
rect.top = render_rect.top();
|
||||||
|
rect.bottom = render_rect.bottom();
|
||||||
|
|
||||||
|
if (ClipCursor(&rect))
|
||||||
|
#else
|
||||||
|
// TODO: implement on other platforms. Probably XGrabPointer on Linux.
|
||||||
|
// The setting is hidden in the UI if not implemented
|
||||||
|
if (false)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
m_cursor_locked = true;
|
||||||
|
|
||||||
|
if (Settings::Instance().GetHideCursor())
|
||||||
|
{
|
||||||
|
setCursor(Qt::BlankCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
Host::GetInstance()->SetRenderFullFocus(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
ClipCursor(nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (m_cursor_locked)
|
||||||
|
{
|
||||||
|
m_cursor_locked = false;
|
||||||
|
|
||||||
|
if (!Settings::Instance().GetLockCursor())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Center the mouse in the window if it's still active
|
||||||
|
// Leave it where it was otherwise, e.g. a prompt has opened or we alt tabbed.
|
||||||
|
if (isActiveWindow())
|
||||||
|
{
|
||||||
|
cursor().setPos(render_rect.left() + render_rect.width() / 2,
|
||||||
|
render_rect.top() + render_rect.height() / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the cursor or the user won't know the mouse is now unlocked
|
||||||
|
setCursor(Qt::ArrowCursor);
|
||||||
|
|
||||||
|
Host::GetInstance()->SetRenderFullFocus(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderWidget::SetCursorLockedOnNextActivation(bool locked)
|
||||||
|
{
|
||||||
|
if (Settings::Instance().GetLockCursor())
|
||||||
|
{
|
||||||
|
m_lock_cursor_on_next_activation = locked;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_lock_cursor_on_next_activation = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderWidget::SetWaitingForMessageBox(bool waiting_for_message_box)
|
||||||
|
{
|
||||||
|
if (m_waiting_for_message_box == waiting_for_message_box)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_waiting_for_message_box = waiting_for_message_box;
|
||||||
|
if (!m_waiting_for_message_box && m_lock_cursor_on_next_activation && isActiveWindow())
|
||||||
|
{
|
||||||
|
if (Settings::Instance().GetLockCursor())
|
||||||
|
{
|
||||||
|
SetCursorLocked(true);
|
||||||
|
}
|
||||||
|
m_lock_cursor_on_next_activation = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool RenderWidget::event(QEvent* event)
|
bool RenderWidget::event(QEvent* event)
|
||||||
{
|
{
|
||||||
PassEventToImGui(event);
|
PassEventToImGui(event);
|
||||||
|
@ -178,23 +354,67 @@ bool RenderWidget::event(QEvent* event)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Needed in case a new window open and it moves the mouse
|
||||||
|
case QEvent::WindowBlocked:
|
||||||
|
SetCursorLocked(false);
|
||||||
|
break;
|
||||||
case QEvent::MouseButtonPress:
|
case QEvent::MouseButtonPress:
|
||||||
if (!Settings::Instance().GetHideCursor() && isActiveWindow())
|
if (isActiveWindow())
|
||||||
{
|
{
|
||||||
setCursor(Qt::ArrowCursor);
|
// Lock the cursor with any mouse button click (behave the same as window focus change).
|
||||||
m_mouse_timer->start(MOUSE_HIDE_DELAY);
|
// This event is occasionally missed because isActiveWindow is laggy
|
||||||
|
if (Settings::Instance().GetLockCursor() && event->type() == QEvent::MouseButtonPress)
|
||||||
|
{
|
||||||
|
SetCursorLocked(true);
|
||||||
|
}
|
||||||
|
// Unhide on movement
|
||||||
|
if (!Settings::Instance().GetHideCursor())
|
||||||
|
{
|
||||||
|
setCursor(Qt::ArrowCursor);
|
||||||
|
m_mouse_timer->start(MOUSE_HIDE_DELAY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QEvent::WinIdChange:
|
case QEvent::WinIdChange:
|
||||||
emit HandleChanged(reinterpret_cast<void*>(winId()));
|
emit HandleChanged(reinterpret_cast<void*>(winId()));
|
||||||
break;
|
break;
|
||||||
|
case QEvent::Show:
|
||||||
|
// Don't do if "stay on top" changed (or was true)
|
||||||
|
if (Settings::Instance().GetLockCursor() && Settings::Instance().GetHideCursor() &&
|
||||||
|
!m_dont_lock_cursor_on_show)
|
||||||
|
{
|
||||||
|
// Auto lock when this window is shown (it was hidden)
|
||||||
|
if (isActiveWindow())
|
||||||
|
SetCursorLocked(true);
|
||||||
|
else
|
||||||
|
SetCursorLockedOnNextActivation();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// Note that this event in Windows is not always aligned to the window that is highlighted,
|
||||||
|
// it's the window that has keyboard and mouse focus
|
||||||
case QEvent::WindowActivate:
|
case QEvent::WindowActivate:
|
||||||
if (SConfig::GetInstance().m_PauseOnFocusLost && Core::GetState() == Core::State::Paused)
|
if (SConfig::GetInstance().m_PauseOnFocusLost && Core::GetState() == Core::State::Paused)
|
||||||
Core::SetState(Core::State::Running);
|
Core::SetState(Core::State::Running);
|
||||||
|
|
||||||
|
UpdateCursor();
|
||||||
|
|
||||||
|
// Avoid "race conditions" with message boxes
|
||||||
|
if (m_lock_cursor_on_next_activation && !m_waiting_for_message_box)
|
||||||
|
{
|
||||||
|
if (Settings::Instance().GetLockCursor())
|
||||||
|
{
|
||||||
|
SetCursorLocked(true);
|
||||||
|
}
|
||||||
|
m_lock_cursor_on_next_activation = false;
|
||||||
|
}
|
||||||
|
|
||||||
emit FocusChanged(true);
|
emit FocusChanged(true);
|
||||||
break;
|
break;
|
||||||
case QEvent::WindowDeactivate:
|
case QEvent::WindowDeactivate:
|
||||||
|
SetCursorLocked(false);
|
||||||
|
|
||||||
|
UpdateCursor();
|
||||||
|
|
||||||
if (SConfig::GetInstance().m_PauseOnFocusLost && Core::GetState() == Core::State::Running)
|
if (SConfig::GetInstance().m_PauseOnFocusLost && Core::GetState() == Core::State::Running)
|
||||||
{
|
{
|
||||||
// If we are declared as the CPU thread, it means that the real CPU thread is waiting
|
// If we are declared as the CPU thread, it means that the real CPU thread is waiting
|
||||||
|
@ -206,8 +426,13 @@ bool RenderWidget::event(QEvent* event)
|
||||||
|
|
||||||
emit FocusChanged(false);
|
emit FocusChanged(false);
|
||||||
break;
|
break;
|
||||||
|
case QEvent::Move:
|
||||||
|
SetCursorLocked(m_cursor_locked);
|
||||||
|
break;
|
||||||
case QEvent::Resize:
|
case QEvent::Resize:
|
||||||
{
|
{
|
||||||
|
SetCursorLocked(m_cursor_locked);
|
||||||
|
|
||||||
const QResizeEvent* se = static_cast<QResizeEvent*>(event);
|
const QResizeEvent* se = static_cast<QResizeEvent*>(event);
|
||||||
QSize new_size = se->size();
|
QSize new_size = se->size();
|
||||||
|
|
||||||
|
@ -218,14 +443,18 @@ bool RenderWidget::event(QEvent* event)
|
||||||
emit SizeChanged(new_size.width() * dpr, new_size.height() * dpr);
|
emit SizeChanged(new_size.width() * dpr, new_size.height() * dpr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Happens when we add/remove the widget from the main window instead of the dedicated one
|
||||||
|
case QEvent::ParentChange:
|
||||||
|
SetCursorLocked(false);
|
||||||
|
break;
|
||||||
case QEvent::WindowStateChange:
|
case QEvent::WindowStateChange:
|
||||||
|
// Lock the mouse again when fullscreen changes (we might have missed some events)
|
||||||
|
SetCursorLocked(m_cursor_locked || (isFullScreen() && Settings::Instance().GetLockCursor()));
|
||||||
emit StateChanged(isFullScreen());
|
emit StateChanged(isFullScreen());
|
||||||
break;
|
break;
|
||||||
case QEvent::Close:
|
case QEvent::Close:
|
||||||
emit Closed();
|
emit Closed();
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return QWidget::event(event);
|
return QWidget::event(event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,10 @@ public:
|
||||||
bool event(QEvent* event) override;
|
bool event(QEvent* event) override;
|
||||||
void showFullScreen();
|
void showFullScreen();
|
||||||
QPaintEngine* paintEngine() const override;
|
QPaintEngine* paintEngine() const override;
|
||||||
|
bool IsCursorLocked() const { return m_cursor_locked; }
|
||||||
|
void SetCursorLockedOnNextActivation(bool locked = true);
|
||||||
|
void SetWaitingForMessageBox(bool waiting_for_message_box);
|
||||||
|
void SetCursorLocked(bool locked, bool follow_aspect_ratio = true);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void EscapePressed();
|
void EscapePressed();
|
||||||
|
@ -32,7 +36,9 @@ signals:
|
||||||
private:
|
private:
|
||||||
void HandleCursorTimer();
|
void HandleCursorTimer();
|
||||||
void OnHideCursorChanged();
|
void OnHideCursorChanged();
|
||||||
|
void OnLockCursorChanged();
|
||||||
void OnKeepOnTopChanged(bool top);
|
void OnKeepOnTopChanged(bool top);
|
||||||
|
void UpdateCursor();
|
||||||
void PassEventToImGui(const QEvent* event);
|
void PassEventToImGui(const QEvent* event);
|
||||||
void SetImGuiKeyMap();
|
void SetImGuiKeyMap();
|
||||||
void dragEnterEvent(QDragEnterEvent* event) override;
|
void dragEnterEvent(QDragEnterEvent* event) override;
|
||||||
|
@ -41,4 +47,8 @@ private:
|
||||||
static constexpr int MOUSE_HIDE_DELAY = 3000;
|
static constexpr int MOUSE_HIDE_DELAY = 3000;
|
||||||
QTimer* m_mouse_timer;
|
QTimer* m_mouse_timer;
|
||||||
QPoint m_last_mouse{};
|
QPoint m_last_mouse{};
|
||||||
|
bool m_cursor_locked = false;
|
||||||
|
bool m_lock_cursor_on_next_activation = false;
|
||||||
|
bool m_dont_lock_cursor_on_show = false;
|
||||||
|
bool m_waiting_for_message_box = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -280,6 +280,17 @@ bool Settings::GetHideCursor() const
|
||||||
return SConfig::GetInstance().bHideCursor;
|
return SConfig::GetInstance().bHideCursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Settings::SetLockCursor(bool lock_cursor)
|
||||||
|
{
|
||||||
|
SConfig::GetInstance().bLockCursor = lock_cursor;
|
||||||
|
emit LockCursorChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Settings::GetLockCursor() const
|
||||||
|
{
|
||||||
|
return SConfig::GetInstance().bLockCursor;
|
||||||
|
}
|
||||||
|
|
||||||
void Settings::SetKeepWindowOnTop(bool top)
|
void Settings::SetKeepWindowOnTop(bool top)
|
||||||
{
|
{
|
||||||
if (IsKeepWindowOnTopEnabled() == top)
|
if (IsKeepWindowOnTopEnabled() == top)
|
||||||
|
|
|
@ -100,6 +100,8 @@ public:
|
||||||
// Graphics
|
// Graphics
|
||||||
void SetHideCursor(bool hide_cursor);
|
void SetHideCursor(bool hide_cursor);
|
||||||
bool GetHideCursor() const;
|
bool GetHideCursor() const;
|
||||||
|
void SetLockCursor(bool lock_cursor);
|
||||||
|
bool GetLockCursor() const;
|
||||||
void SetKeepWindowOnTop(bool top);
|
void SetKeepWindowOnTop(bool top);
|
||||||
bool IsKeepWindowOnTopEnabled() const;
|
bool IsKeepWindowOnTopEnabled() const;
|
||||||
|
|
||||||
|
@ -168,6 +170,7 @@ signals:
|
||||||
void MetadataRefreshCompleted();
|
void MetadataRefreshCompleted();
|
||||||
void AutoRefreshToggled(bool enabled);
|
void AutoRefreshToggled(bool enabled);
|
||||||
void HideCursorChanged();
|
void HideCursorChanged();
|
||||||
|
void LockCursorChanged();
|
||||||
void KeepWindowOnTopChanged(bool top);
|
void KeepWindowOnTopChanged(bool top);
|
||||||
void VolumeChanged(int volume);
|
void VolumeChanged(int volume);
|
||||||
void NANDRefresh();
|
void NANDRefresh();
|
||||||
|
|
|
@ -171,6 +171,14 @@ void InterfacePane::CreateInGame()
|
||||||
m_checkbox_show_active_title = new QCheckBox(tr("Show Active Title in Window Title"));
|
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_pause_on_focus_lost = new QCheckBox(tr("Pause on Focus Loss"));
|
||||||
m_checkbox_hide_mouse = new QCheckBox(tr("Always Hide Mouse Cursor"));
|
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"));
|
||||||
|
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."));
|
||||||
|
|
||||||
groupbox_layout->addWidget(m_checkbox_top_window);
|
groupbox_layout->addWidget(m_checkbox_top_window);
|
||||||
groupbox_layout->addWidget(m_checkbox_confirm_on_stop);
|
groupbox_layout->addWidget(m_checkbox_confirm_on_stop);
|
||||||
|
@ -179,6 +187,9 @@ void InterfacePane::CreateInGame()
|
||||||
groupbox_layout->addWidget(m_checkbox_show_active_title);
|
groupbox_layout->addWidget(m_checkbox_show_active_title);
|
||||||
groupbox_layout->addWidget(m_checkbox_pause_on_focus_lost);
|
groupbox_layout->addWidget(m_checkbox_pause_on_focus_lost);
|
||||||
groupbox_layout->addWidget(m_checkbox_hide_mouse);
|
groupbox_layout->addWidget(m_checkbox_hide_mouse);
|
||||||
|
#ifdef _WIN32
|
||||||
|
groupbox_layout->addWidget(m_checkbox_lock_mouse);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterfacePane::ConnectLayout()
|
void InterfacePane::ConnectLayout()
|
||||||
|
@ -203,6 +214,8 @@ void InterfacePane::ConnectLayout()
|
||||||
connect(m_checkbox_pause_on_focus_lost, &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(),
|
connect(m_checkbox_hide_mouse, &QCheckBox::toggled, &Settings::Instance(),
|
||||||
&Settings::SetHideCursor);
|
&Settings::SetHideCursor);
|
||||||
|
connect(m_checkbox_lock_mouse, &QCheckBox::toggled, &Settings::Instance(),
|
||||||
|
&Settings::SetLockCursor);
|
||||||
connect(m_checkbox_use_userstyle, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
|
connect(m_checkbox_use_userstyle, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,6 +252,7 @@ void InterfacePane::LoadConfig()
|
||||||
m_checkbox_use_covers->setChecked(Config::Get(Config::MAIN_USE_GAME_COVERS));
|
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_focused_hotkeys->setChecked(Config::Get(Config::MAIN_FOCUSED_HOTKEYS));
|
||||||
m_checkbox_hide_mouse->setChecked(Settings::Instance().GetHideCursor());
|
m_checkbox_hide_mouse->setChecked(Settings::Instance().GetHideCursor());
|
||||||
|
m_checkbox_lock_mouse->setChecked(Settings::Instance().GetLockCursor());
|
||||||
m_checkbox_disable_screensaver->setChecked(Config::Get(Config::MAIN_DISABLE_SCREENSAVER));
|
m_checkbox_disable_screensaver->setChecked(Config::Get(Config::MAIN_DISABLE_SCREENSAVER));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,4 +45,5 @@ private:
|
||||||
QCheckBox* m_checkbox_show_active_title;
|
QCheckBox* m_checkbox_show_active_title;
|
||||||
QCheckBox* m_checkbox_pause_on_focus_lost;
|
QCheckBox* m_checkbox_pause_on_focus_lost;
|
||||||
QCheckBox* m_checkbox_hide_mouse;
|
QCheckBox* m_checkbox_hide_mouse;
|
||||||
|
QCheckBox* m_checkbox_lock_mouse;
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,6 +39,10 @@ bool Host_RendererHasFocus()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool Host_RendererHasFullFocus()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
bool Host_RendererIsFullscreen()
|
bool Host_RendererIsFullscreen()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -43,6 +43,10 @@ bool Host_RendererHasFocus()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool Host_RendererHasFullFocus()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
bool Host_RendererIsFullscreen()
|
bool Host_RendererIsFullscreen()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in New Issue