Use stable names for macro pause hotkeys
Some checks failed
debian-build / build (push) Has been cancelled
Push to master / Check Formatting 🔍 (push) Has been cancelled
Push to master / Build Project 🧱 (push) Has been cancelled
Push to master / Create Release 🛫 (push) Has been cancelled

Otherwise external tools have a difficult time interacting with this
particular set of hotkeys, as the id might change when changing scene
collections.
This commit is contained in:
WarmUpTill
2026-11-05 09:38:55 +01:00
committed by WarmUpTill
parent e4fb49a8bd
commit b7bf68615d
3 changed files with 130 additions and 10 deletions

View File

@@ -10,6 +10,7 @@
#include "sync-helpers.hpp"
#include <obs-frontend-api.h>
#include <util/platform.h>
#include <QAction>
#include <QMainWindow>
@@ -917,6 +918,9 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const
"macroElseActionSplitterPosition");
obs_data_set_bool(obj, "registerHotkeys", _registerHotkeys);
if (!saveForCopy) {
obs_data_set_string(obj, "hotkeyId", _hotkeyId.c_str());
}
OBSDataArrayAutoRelease pauseHotkey = obs_hotkey_save(_pauseHotkey);
obs_data_set_array(obj, "pauseHotkey", pauseHotkey);
OBSDataArrayAutoRelease unpauseHotkey = obs_hotkey_save(_unpauseHotkey);
@@ -1013,6 +1017,7 @@ bool Macro::Load(obs_data_t *obj)
obs_data_set_default_bool(obj, "registerHotkeys", true);
_registerHotkeys = !_isNested &&
obs_data_get_bool(obj, "registerHotkeys");
_hotkeyId = obs_data_get_string(obj, "hotkeyId");
_pauseHotkeyData = obs_data_get_array(obj, "pauseHotkey");
_unpauseHotkeyData = obs_data_get_array(obj, "unpauseHotkey");
_togglePauseHotkeyData = obs_data_get_array(obj, "togglePauseHotkey");
@@ -1221,15 +1226,10 @@ static void togglePauseCB(void *data, obs_hotkey_id, obs_hotkey_t *,
}
}
static int macroHotkeyID = 0;
static obs_hotkey_id registerHotkeyHelper(const std::string prefix,
static obs_hotkey_id registerHotkeyHelper(const std::string &hotkeyName,
const char *formatModuleText,
Macro *macro, obs_hotkey_func func)
{
macroHotkeyID++;
std::string hotkeyName = prefix + std::to_string(macroHotkeyID);
QString format{obs_module_text(formatModuleText)};
QString hotkeyDesc = format.arg(QString::fromStdString(macro->Name()));
return obs_hotkey_register_frontend(hotkeyName.c_str(),
@@ -1249,14 +1249,20 @@ void Macro::SetupHotkeys()
ClearHotkeys();
}
if (_hotkeyId.empty()) {
char *uuid = os_generate_uuid();
_hotkeyId = uuid;
bfree(uuid);
}
_pauseHotkey = registerHotkeyHelper(
"macro_pause_hotkey_", "AdvSceneSwitcher.hotkey.macro.pause",
this, pauseCB);
"macro_pause_hotkey_" + _hotkeyId,
"AdvSceneSwitcher.hotkey.macro.pause", this, pauseCB);
_unpauseHotkey = registerHotkeyHelper(
"macro_unpause_hotkey_",
"macro_unpause_hotkey_" + _hotkeyId,
"AdvSceneSwitcher.hotkey.macro.unpause", this, unpauseCB);
_togglePauseHotkey = registerHotkeyHelper(
"macro_toggle_pause_hotkey_",
"macro_toggle_pause_hotkey_" + _hotkeyId,
"AdvSceneSwitcher.hotkey.macro.togglePause", this,
togglePauseCB);
}
@@ -1330,6 +1336,8 @@ std::vector<std::shared_ptr<Macro>> LoadImportedMacros(
for (size_t i = 0; i < count; i++) {
tempMacros.clear();
OBSDataAutoRelease obj = obs_data_array_item(array, i);
// The exported original might still exist in this collection
obs_data_erase(obj, "hotkeyId");
auto macro = std::make_shared<Macro>();
tempMacros.emplace_back(macro);
macro->Load(obj);

View File

@@ -218,6 +218,7 @@ private:
bool _paused = false;
int _runCount = 0;
bool _registerHotkeys = true;
std::string _hotkeyId;
obs_hotkey_id _pauseHotkey = OBS_INVALID_HOTKEY_ID;
obs_hotkey_id _unpauseHotkey = OBS_INVALID_HOTKEY_ID;
obs_hotkey_id _togglePauseHotkey = OBS_INVALID_HOTKEY_ID;

View File

@@ -1,8 +1,11 @@
#include "catch.hpp"
#include <macro-helpers.hpp>
#include <macro-settings.hpp>
#include <macro.hpp>
#include <memory>
#include <string>
namespace {
@@ -414,3 +417,111 @@ TEST_CASE("GetActionTriggerMode returns the set mode", "[macro]")
REQUIRE(m.GetActionTriggerMode() ==
advss::Macro::ActionTriggerMode::ANY_CONDITION_TRIGGERED);
}
// ---------------------------------------------------------------------------
// Hotkey ID persistence
// ---------------------------------------------------------------------------
static std::string savedHotkeyId(const advss::Macro &macro,
bool saveForCopy = false)
{
OBSDataAutoRelease data = obs_data_create();
macro.Save(data, saveForCopy);
return obs_data_get_string(data, "hotkeyId");
}
TEST_CASE("New macros with hotkeys enabled get a hotkey ID", "[macro]")
{
advss::GlobalMacroSettings settings;
advss::Macro first("first", settings);
advss::Macro second("second", settings);
REQUIRE_FALSE(savedHotkeyId(first).empty());
REQUIRE(savedHotkeyId(first) != savedHotkeyId(second));
}
TEST_CASE("New macros with hotkeys disabled have no hotkey ID", "[macro]")
{
advss::GlobalMacroSettings settings;
settings._newMacroRegisterHotkeys = false;
advss::Macro macro("macro", settings);
REQUIRE(savedHotkeyId(macro).empty());
}
TEST_CASE("Hotkey ID is kept across save and load", "[macro]")
{
advss::GlobalMacroSettings settings;
advss::Macro original("macro", settings);
OBSDataAutoRelease data = obs_data_create();
original.Save(data);
advss::Macro loaded;
loaded.Load(data);
loaded.PostLoad();
REQUIRE(savedHotkeyId(loaded) == savedHotkeyId(original));
}
TEST_CASE("Hotkey ID is kept when hotkeys are toggled", "[macro]")
{
advss::GlobalMacroSettings settings;
advss::Macro macro("macro", settings);
const auto id = savedHotkeyId(macro);
macro.EnablePauseHotkeys(false);
macro.EnablePauseHotkeys(true);
REQUIRE(savedHotkeyId(macro) == id);
}
TEST_CASE("Macros saved without a hotkey ID get one on load", "[macro]")
{
OBSDataAutoRelease data = obs_data_create();
obs_data_set_string(data, "name", "macro");
advss::Macro macro;
macro.Load(data);
macro.PostLoad();
REQUIRE_FALSE(savedHotkeyId(macro).empty());
}
TEST_CASE("Copied macros get a new hotkey ID", "[macro]")
{
advss::GlobalMacroSettings settings;
advss::Macro original("macro", settings);
REQUIRE(savedHotkeyId(original, true).empty());
OBSDataAutoRelease data = obs_data_create();
original.Save(data, true);
advss::Macro copy("copy", settings);
copy.Load(data);
copy.PostLoad();
REQUIRE_FALSE(savedHotkeyId(copy).empty());
REQUIRE(savedHotkeyId(copy) != savedHotkeyId(original));
}
TEST_CASE("Imported macros get a new hotkey ID", "[macro]")
{
advss::GlobalMacroSettings settings;
advss::Macro original("macro", settings);
OBSDataAutoRelease data = obs_data_create();
original.Save(data);
OBSDataArrayAutoRelease array = obs_data_array_create();
obs_data_array_push_back(array, data);
const auto imported = advss::LoadImportedMacros(
array,
[](const std::shared_ptr<advss::Macro> &) { return true; });
REQUIRE(imported.size() == 1);
REQUIRE_FALSE(savedHotkeyId(*imported[0]).empty());
REQUIRE(savedHotkeyId(*imported[0]) != savedHotkeyId(original));
advss::GetTopLevelMacros().clear();
}