Combine hotkeys with the same description into a single hotkey

This commit is contained in:
WarmUpTill
2022-12-10 16:23:40 +01:00
committed by WarmUpTill
parent 0d1a3e5646
commit 368034ad5a
5 changed files with 187 additions and 46 deletions

View File

@@ -4,6 +4,119 @@
#include <fstream>
#include <regex>
std::vector<std::weak_ptr<Hotkey>> Hotkey::_registeredHotkeys = {};
uint32_t Hotkey::_hotkeyCounter = 1;
std::shared_ptr<Hotkey> Hotkey::GetHotkey(const std::string &description,
bool ignoreExistingHotkeys)
{
// Clean up expired hotkeys
auto it = _registeredHotkeys.begin();
while (it != _registeredHotkeys.end()) {
if (it->expired()) {
it = _registeredHotkeys.erase(it);
} else {
it++;
}
}
// Check for existing hotkey with same description
for (const auto &h : _registeredHotkeys) {
auto hotkey = h.lock();
if (!hotkey) {
continue;
}
if (hotkey->_description == description) {
hotkey->_ignoreExistingHotkeys = ignoreExistingHotkeys;
return hotkey;
}
}
// Create new hotkey
auto hotkey = std::make_shared<Hotkey>(description);
_registeredHotkeys.emplace_back(hotkey);
hotkey->_ignoreExistingHotkeys = ignoreExistingHotkeys;
return hotkey;
}
Hotkey::Hotkey(const std::string &description) : _description(description)
{
std::string name =
"macro_condition_hotkey_" + std::to_string(_hotkeyCounter);
_hotkeyID = obs_hotkey_register_frontend(
name.c_str(), _description.c_str(), Callback, this);
_hotkeyCounter++;
}
bool Hotkey::Save(obs_data_t *obj) const
{
obs_data_set_string(obj, "desc", _description.c_str());
obs_data_array_t *hotkeyData = obs_hotkey_save(_hotkeyID);
obs_data_set_array(obj, "keyBind", hotkeyData);
obs_data_array_release(hotkeyData);
return true;
}
bool Hotkey::Load(obs_data_t *obj)
{
auto description = obs_data_get_string(obj, "desc");
if (!DescriptionAvailable(description)) {
return false;
}
_description = description;
obs_data_array_t *hotkeyData = obs_data_get_array(obj, "keyBind");
obs_hotkey_load(_hotkeyID, hotkeyData);
obs_data_array_release(hotkeyData);
obs_hotkey_set_description(_hotkeyID, _description.c_str());
_ignoreExistingHotkeys = false;
return true;
}
Hotkey::~Hotkey()
{
obs_hotkey_unregister(_hotkeyID);
}
bool Hotkey::UpdateDescription(const std::string &descritpion)
{
if (!DescriptionAvailable(descritpion)) {
return false;
}
_description = descritpion;
obs_hotkey_set_description(_hotkeyID, descritpion.c_str());
return true;
}
bool Hotkey::DescriptionAvailable(const std::string &descritpion)
{
for (const auto &hotkey : _registeredHotkeys) {
auto h = hotkey.lock();
if (!h) {
continue;
}
if (!h->_ignoreExistingHotkeys &&
h->_description == descritpion) {
return false;
}
}
return true;
}
void Hotkey::Callback(void *data, obs_hotkey_id, obs_hotkey_t *, bool pressed)
{
auto hotkey = static_cast<Hotkey *>(data);
if (pressed) {
hotkey->_lastPressed =
std::chrono::high_resolution_clock::now();
}
hotkey->_pressed = pressed;
}
void Hotkey::ClearAllHotkeys()
{
_registeredHotkeys.clear();
}
void startHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
{
if (pressed) {

View File

@@ -1,7 +1,46 @@
#pragma once
#include <obs.hpp>
#include <string>
#include <memory>
#include <vector>
#include <chrono>
extern bool canSimulateKeyPresses;
class Hotkey {
public:
Hotkey(const std::string &description);
~Hotkey();
static std::shared_ptr<Hotkey>
GetHotkey(const std::string &description,
bool ignoreExistingHotkeys = false);
static void ClearAllHotkeys();
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
bool GetPressed() const { return _pressed; }
auto GetLastPressed() const { return _lastPressed; }
std::string GetDescription() const { return _description; }
bool UpdateDescription(const std::string &);
private:
static bool DescriptionAvailable(const std::string &);
static void Callback(void *data, obs_hotkey_id, obs_hotkey_t *,
bool pressed);
static std::vector<std::weak_ptr<Hotkey>> _registeredHotkeys;
static uint32_t _hotkeyCounter;
std::string _description;
obs_hotkey_id _hotkeyID = OBS_INVALID_HOTKEY_ID;
bool _pressed = false;
std::chrono::high_resolution_clock::time_point _lastPressed{};
// When set will not attempt to share settings with existing hotkey
bool _ignoreExistingHotkeys = false;
};
enum class HotkeyType {
Key_NoKey = 0,

View File

@@ -10,63 +10,41 @@ bool MacroConditionHotkey::_registered = MacroConditionFactory::Register(
{MacroConditionHotkey::Create, MacroConditionHotkeyEdit::Create,
"AdvSceneSwitcher.condition.hotkey", false});
static void hotkeyCB(void *data, obs_hotkey_id, obs_hotkey_t *, bool pressed)
{
auto hotkeyCondition = static_cast<MacroConditionHotkey *>(data);
auto macro = hotkeyCondition->GetMacro();
if (macro) {
hotkeyCondition->SetPressed(pressed && !macro->Paused());
} else {
hotkeyCondition->SetPressed(pressed);
}
}
static uint32_t count = 1;
MacroConditionHotkey::MacroConditionHotkey(Macro *m) : MacroCondition(m)
{
if (_hotkeyID != OBS_INVALID_HOTKEY_ID) {
obs_hotkey_unregister(_hotkeyID);
}
std::string hotkeyName =
"macro_condition_hotkey_" + std::to_string(count);
_name = obs_module_text("AdvSceneSwitcher.condition.hotkey.name") +
std::string(" ") + std::to_string(count);
_hotkeyID = obs_hotkey_register_frontend(hotkeyName.c_str(),
_name.c_str(), hotkeyCB, this);
auto name = obs_module_text("AdvSceneSwitcher.condition.hotkey.name") +
std::string(" ") + std::to_string(count);
_hotkey = Hotkey::GetHotkey(name, true);
count++;
}
MacroConditionHotkey::~MacroConditionHotkey()
{
obs_hotkey_unregister(_hotkeyID);
}
bool MacroConditionHotkey::CheckCondition()
{
return _pressed;
bool ret = _hotkey->GetPressed() ||
_hotkey->GetLastPressed() > _lastCheck;
_lastCheck = std::chrono::high_resolution_clock::now();
return ret;
}
bool MacroConditionHotkey::Save(obs_data_t *obj)
{
MacroCondition::Save(obj);
obs_data_set_string(obj, "desc", _name.c_str());
obs_data_array_t *pauseHotkey = obs_hotkey_save(_hotkeyID);
obs_data_set_array(obj, "keyBind", pauseHotkey);
obs_data_array_release(pauseHotkey);
_hotkey->Save(obj);
return true;
}
bool MacroConditionHotkey::Load(obs_data_t *obj)
{
MacroCondition::Load(obj);
_name = obs_data_get_string(obj, "desc");
obs_data_array_t *pauseHotkey = obs_data_get_array(obj, "keyBind");
obs_hotkey_load(_hotkeyID, pauseHotkey);
obs_data_array_release(pauseHotkey);
obs_hotkey_set_description(_hotkeyID, _name.c_str());
if (!_hotkey->Load(obj)) {
auto description = obs_data_get_string(obj, "desc");
_hotkey = Hotkey::GetHotkey(description);
vblog(LOG_WARNING,
"hotkey name conflict for \"%s\" - using previous key bind",
description);
}
return true;
}
@@ -109,9 +87,18 @@ void MacroConditionHotkeyEdit::NameChanged()
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_name = _name->text().toStdString();
obs_hotkey_set_description(_entryData->_hotkeyID,
_entryData->_name.c_str());
const auto name = _name->text().toStdString();
// In case a hotkey is used by multiple conditions create a new hotkey
// with the new description or get an existing hotkey matching this
// description.
// If the hotkey is only used by this single condition instance try to
// update the description.
// If updating the description runs into a conflict with an existing
// hotkey use its settings instead.
if (_entryData->_hotkey.use_count() > 1 ||
!_entryData->_hotkey->UpdateDescription(name)) {
_entryData->_hotkey = Hotkey::GetHotkey(name);
}
}
void MacroConditionHotkeyEdit::UpdateEntryData()
@@ -120,5 +107,6 @@ void MacroConditionHotkeyEdit::UpdateEntryData()
return;
}
_name->setText(QString::fromStdString(_entryData->_name));
_name->setText(
QString::fromStdString(_entryData->_hotkey->GetDescription()));
}

View File

@@ -1,12 +1,13 @@
#pragma once
#include "macro.hpp"
#include "hotkey.hpp"
#include <QWidget>
#include <QLineEdit>
class MacroConditionHotkey : public MacroCondition {
public:
MacroConditionHotkey(Macro *m);
~MacroConditionHotkey();
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
@@ -15,13 +16,12 @@ public:
{
return std::make_shared<MacroConditionHotkey>(m);
}
void SetPressed(bool value) { _pressed = value; }
std::string _name;
obs_hotkey_id _hotkeyID = OBS_INVALID_HOTKEY_ID;
std::shared_ptr<Hotkey> _hotkey;
private:
bool _pressed = false;
std::chrono::high_resolution_clock::time_point _lastCheck{};
static bool _registered;
static const std::string id;
};

View File

@@ -594,6 +594,7 @@ void SwitcherData::saveMacros(obs_data_t *obj)
void SwitcherData::loadMacros(obs_data_t *obj)
{
Hotkey::ClearAllHotkeys();
switcher->macroProperties.Load(obj);
macros.clear();