mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-15 13:53:19 -05:00
Combine hotkeys with the same description into a single hotkey
This commit is contained in:
113
src/hotkey.cpp
113
src/hotkey.cpp
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user