diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
index 84f364189..4e0b39f58 100644
--- a/UI/data/locale/en-US.ini
+++ b/UI/data/locale/en-US.ini
@@ -1209,6 +1209,7 @@ Basic.Settings.Hotkeys.Pair="Key combinations shared with '%1' act as toggles"
Basic.Settings.Hotkeys.Filter="Filter"
Basic.Settings.Hotkeys.FilterByHotkey="Filter by Hotkey"
Basic.Settings.Hotkeys.DuplicateWarning="This hotkey is shared by one or more other actions, click to show conflicts"
+Basic.Settings.Hotkeys.PleaseWait="Loading hotkeys, please wait..."
# basic mode hotkeys
Basic.Hotkeys.SelectScene="Switch to scene"
diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui
index ff27f52c2..c20e7d3d1 100644
--- a/UI/forms/OBSBasicSettings.ui
+++ b/UI/forms/OBSBasicSettings.ui
@@ -5692,6 +5692,25 @@
9
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.Hotkeys.PleaseWait
+
+
+ false
+
+
+ Qt::AlignCenter
+
+
+
diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp
index 98720b2c9..0ce8800ab 100644
--- a/UI/window-basic-settings.cpp
+++ b/UI/window-basic-settings.cpp
@@ -3074,6 +3074,13 @@ void OBSBasicSettings::LoadHotkeySettings(obs_hotkey_id ignoreKey)
AddHotkeys(*hotkeysLayout, obs_service_get_name, services);
ScanDuplicateHotkeys(hotkeysLayout);
+
+ /* After this function returns the UI can still be unresponsive for a bit.
+ * So by deferring the call to unsetCursor() to the Qt event loop it will
+ * take until it has actually finished processing the created widgets
+ * before the cursor is reset. */
+ QTimer::singleShot(1, this, &OBSBasicSettings::unsetCursor);
+ hotkeysLoaded = true;
}
void OBSBasicSettings::LoadSettings(bool changedOnly)
@@ -3088,8 +3095,6 @@ void OBSBasicSettings::LoadSettings(bool changedOnly)
LoadAudioSettings();
if (!changedOnly || videoChanged)
LoadVideoSettings();
- if (!changedOnly || hotkeysChanged)
- LoadHotkeySettings();
if (!changedOnly || a11yChanged)
LoadA11ySettings();
if (!changedOnly || advancedChanged)
@@ -3996,6 +4001,20 @@ void OBSBasicSettings::on_listWidget_itemSelectionChanged()
if (loading || row == pageIndex)
return;
+ if (!hotkeysLoaded && row == 5) {
+ setCursor(Qt::BusyCursor);
+ /* Look, I know this /feels/ wrong, but the specific issue we're dealing with
+ * here means that the UI locks up immediately even when using "invokeMethod".
+ * So the only way for the user to see the loading message on the page is to
+ * give the Qt event loop a tiny bit of time to switch to the hotkey page,
+ * and only then start loading. This could maybe be done by subclassing QWidget
+ * for the hotkey page and then using showEvent() but I *really* don't want
+ * to deal with that right now. I've got better things to do with my life
+ * than to work around this god damn stupid issue for something we'll remove
+ * soon enough anyway. So this solution it is. */
+ QTimer::singleShot(1, this, [&]() { LoadHotkeySettings(); });
+ }
+
pageIndex = row;
}
@@ -4629,6 +4648,8 @@ bool OBSBasicSettings::ScanDuplicateHotkeys(QFormLayout *layout)
void OBSBasicSettings::ReloadHotkeys(obs_hotkey_id ignoreKey)
{
+ if (!hotkeysLoaded)
+ return;
LoadHotkeySettings(ignoreKey);
}
diff --git a/UI/window-basic-settings.hpp b/UI/window-basic-settings.hpp
index 51f00e941..51f00336f 100644
--- a/UI/window-basic-settings.hpp
+++ b/UI/window-basic-settings.hpp
@@ -125,6 +125,7 @@ private:
int sampleRateIndex = 0;
int channelIndex = 0;
bool llBufferingEnabled = false;
+ bool hotkeysLoaded = false;
int lastSimpleRecQualityIdx = 0;
int lastServiceIdx = -1;