diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 6bd1a9a7..f5abf564 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -128,6 +128,7 @@ AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}" AdvSceneSwitcher.condition.window="Window" AdvSceneSwitcher.condition.window.entry.line1="{{windows}} exist and ..." AdvSceneSwitcher.condition.window.entry.line2="... is {{fullscreen}} fullscreen {{maximized}} maximized {{focused}} focused {{windowFocusChanged}} foreground window changed" +AdvSceneSwitcher.condition.window.entry.line3="Current foreground window: {{focusWindow}}" AdvSceneSwitcher.condition.file="File" AdvSceneSwitcher.condition.file.type.match="matches" AdvSceneSwitcher.condition.file.type.contentChange="content changed" @@ -200,6 +201,7 @@ AdvSceneSwitcher.condition.record.state.stop="Recording stopped" AdvSceneSwitcher.condition.record.entry="{{recordState}}" AdvSceneSwitcher.condition.process="Process" AdvSceneSwitcher.condition.process.entry="{{processes}} is running {{focused}} and is focused" +AdvSceneSwitcher.condition.process.entry.focus="Current foreground process: {{focusProcess}}" AdvSceneSwitcher.condition.idle="Idle" AdvSceneSwitcher.condition.idle.entry="No keyboard or mouse inputs for {{duration}}" AdvSceneSwitcher.condition.pluginState="Plugin state" diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp index caaeb8e6..fa6e7532 100644 --- a/src/advanced-scene-switcher.cpp +++ b/src/advanced-scene-switcher.cpp @@ -280,6 +280,9 @@ void SwitcherData::setPreconditions() } currentTitle = title; + // Process name + GetForegroundProcessName(currentForegroundProcess); + // Cursor std::pair cursorPos = getCursorPos(); cursorPosChanged = cursorPos.first != switcher->lastCursorPos.first || diff --git a/src/linux/advanced-scene-switcher-nix.cpp b/src/linux/advanced-scene-switcher-nix.cpp index a233eb12..2a740dc2 100644 --- a/src/linux/advanced-scene-switcher-nix.cpp +++ b/src/linux/advanced-scene-switcher-nix.cpp @@ -434,10 +434,24 @@ std::string getProcNameFromPid(int pid) return buffer.str(); } -bool isInFocus(const QString &executable) +void GetForegroundProcessName(QString &proc) { + std::string temp; + GetForegroundProcessName(temp); + proc = QString::fromStdString(temp); +} + +void GetForegroundProcessName(std::string &proc) +{ + proc.resize(0); auto pid = getForegroundProcessPid(); std::string current = getProcNameFromPid(pid); +} + +bool isInFocus(const QString &executable) +{ + std::string current; + GetForegroundProcessName(current); // True if executable switch equals current window bool equals = (executable.toStdString() == current); diff --git a/src/macro-core/macro-condition-process.cpp b/src/macro-core/macro-condition-process.cpp index 5a5f484e..f9d3d1c7 100644 --- a/src/macro-core/macro-condition-process.cpp +++ b/src/macro-core/macro-condition-process.cpp @@ -48,36 +48,48 @@ std::string MacroConditionProcess::GetShortDesc() MacroConditionProcessEdit::MacroConditionProcessEdit( QWidget *parent, std::shared_ptr entryData) - : QWidget(parent) + : QWidget(parent), + _processSelection(new QComboBox()), + _focused(new QCheckBox()), + _focusProcess(new QLabel()), + _focusLayout(new QHBoxLayout()) { - _processSelection = new QComboBox(); _processSelection->setEditable(true); _processSelection->setMaxVisibleItems(20); - _focused = new QCheckBox(); - QWidget::connect(_processSelection, SIGNAL(currentTextChanged(const QString &)), this, SLOT(ProcessChanged(const QString &))); QWidget::connect(_focused, SIGNAL(stateChanged(int)), this, SLOT(FocusChanged(int))); + QWidget::connect(&_timer, SIGNAL(timeout()), this, + SLOT(UpdateFocusProcess())); populateProcessSelection(_processSelection); std::unordered_map widgetPlaceholders = { {"{{processes}}", _processSelection}, {"{{focused}}", _focused}, + {"{{focusProcess}}", _focusProcess}, }; - QHBoxLayout *mainLayout = new QHBoxLayout; + auto entryLayout = new QHBoxLayout; placeWidgets( obs_module_text("AdvSceneSwitcher.condition.process.entry"), - mainLayout, widgetPlaceholders); + entryLayout, widgetPlaceholders); + placeWidgets(obs_module_text( + "AdvSceneSwitcher.condition.process.entry.focus"), + _focusLayout, widgetPlaceholders); + auto mainLayout = new QVBoxLayout; + mainLayout->addLayout(entryLayout); + mainLayout->addLayout(_focusLayout); setLayout(mainLayout); _entryData = entryData; UpdateEntryData(); _loading = false; + + _timer.start(1000); } void MacroConditionProcessEdit::ProcessChanged(const QString &text) @@ -100,6 +112,22 @@ void MacroConditionProcessEdit::FocusChanged(int state) std::lock_guard lock(switcher->m); _entryData->_focus = state; + SetWidgetVisibility(); +} + +void MacroConditionProcessEdit::UpdateFocusProcess() +{ + _focusProcess->setText( + QString::fromStdString(switcher->currentForegroundProcess)); +} + +void MacroConditionProcessEdit::SetWidgetVisibility() +{ + if (!_entryData) { + return; + } + setLayoutVisible(_focusLayout, _entryData->_focus); + adjustSize(); } void MacroConditionProcessEdit::UpdateEntryData() @@ -110,4 +138,5 @@ void MacroConditionProcessEdit::UpdateEntryData() _processSelection->setCurrentText(_entryData->_process.c_str()); _focused->setChecked(_entryData->_focus); + SetWidgetVisibility(); } diff --git a/src/macro-core/macro-condition-process.hpp b/src/macro-core/macro-condition-process.hpp index e09172b3..b741bb2a 100644 --- a/src/macro-core/macro-condition-process.hpp +++ b/src/macro-core/macro-condition-process.hpp @@ -44,14 +44,20 @@ public: private slots: void ProcessChanged(const QString &text); void FocusChanged(int state); + void UpdateFocusProcess(); signals: void HeaderInfoChanged(const QString &); protected: QComboBox *_processSelection; QCheckBox *_focused; + QLabel *_focusProcess; + QHBoxLayout *_focusLayout; + QTimer _timer; std::shared_ptr _entryData; private: + void SetWidgetVisibility(); + bool _loading = true; }; diff --git a/src/macro-core/macro-condition-window.cpp b/src/macro-core/macro-condition-window.cpp index 6538baf6..ecd8e556 100644 --- a/src/macro-core/macro-condition-window.cpp +++ b/src/macro-core/macro-condition-window.cpp @@ -13,7 +13,7 @@ bool MacroConditionWindow::_registered = MacroConditionFactory::Register( "AdvSceneSwitcher.condition.window"}); bool MacroConditionWindow::CheckWindowTitleSwitchDirect( - std::string ¤tWindowTitle) + const std::string ¤tWindowTitle) { bool focus = (!_focus || _window == currentWindowTitle); bool fullscreen = (!_fullscreen || isFullscreen(_window)); @@ -23,7 +23,8 @@ bool MacroConditionWindow::CheckWindowTitleSwitchDirect( } bool MacroConditionWindow::CheckWindowTitleSwitchRegex( - std::string ¤tWindowTitle, std::vector &windowList) + const std::string ¤tWindowTitle, + const std::vector &windowList) { bool match = false; for (auto &window : windowList) { @@ -54,7 +55,7 @@ bool foregroundWindowChanged() bool MacroConditionWindow::CheckCondition() { - std::string currentWindowTitle = switcher->currentTitle; + const std::string ¤tWindowTitle = switcher->currentTitle; std::vector windowList; GetWindowList(windowList); @@ -101,17 +102,18 @@ std::string MacroConditionWindow::GetShortDesc() MacroConditionWindowEdit::MacroConditionWindowEdit( QWidget *parent, std::shared_ptr entryData) - : QWidget(parent) + : QWidget(parent), + _windowSelection(new QComboBox()), + _fullscreen(new QCheckBox()), + _maximized(new QCheckBox()), + _focused(new QCheckBox()), + _windowFocusChanged(new QCheckBox()), + _focusWindow(new QLabel()), + _focusLayout(new QHBoxLayout()) { - _windowSelection = new QComboBox(); _windowSelection->setEditable(true); _windowSelection->setMaxVisibleItems(20); - _fullscreen = new QCheckBox(); - _maximized = new QCheckBox(); - _focused = new QCheckBox(); - _windowFocusChanged = new QCheckBox(); - QWidget::connect(_windowSelection, SIGNAL(currentTextChanged(const QString &)), this, SLOT(WindowChanged(const QString &))); @@ -123,6 +125,8 @@ MacroConditionWindowEdit::MacroConditionWindowEdit( SLOT(FocusedChanged(int))); QWidget::connect(_windowFocusChanged, SIGNAL(stateChanged(int)), this, SLOT(WindowFocusChanged(int))); + QWidget::connect(&_timer, SIGNAL(timeout()), this, + SLOT(UpdateFocusWindow())); populateWindowSelection(_windowSelection); @@ -132,24 +136,31 @@ MacroConditionWindowEdit::MacroConditionWindowEdit( {"{{maximized}}", _maximized}, {"{{focused}}", _focused}, {"{{windowFocusChanged}}", _windowFocusChanged}, + {"{{focusWindow}}", _focusWindow}, }; - QVBoxLayout *mainLayout = new QVBoxLayout; - QHBoxLayout *line1Layout = new QHBoxLayout; - QHBoxLayout *line2Layout = new QHBoxLayout; + auto *line1Layout = new QHBoxLayout; placeWidgets(obs_module_text( "AdvSceneSwitcher.condition.window.entry.line1"), line1Layout, widgetPlaceholders); + auto *line2Layout = new QHBoxLayout; placeWidgets(obs_module_text( "AdvSceneSwitcher.condition.window.entry.line2"), line2Layout, widgetPlaceholders); + placeWidgets(obs_module_text( + "AdvSceneSwitcher.condition.window.entry.line3"), + _focusLayout, widgetPlaceholders); + auto *mainLayout = new QVBoxLayout; mainLayout->addLayout(line1Layout); mainLayout->addLayout(line2Layout); + mainLayout->addLayout(_focusLayout); setLayout(mainLayout); _entryData = entryData; UpdateEntryData(); _loading = false; + + _timer.start(1000); } void MacroConditionWindowEdit::WindowChanged(const QString &text) @@ -192,6 +203,7 @@ void MacroConditionWindowEdit::FocusedChanged(int state) std::lock_guard lock(switcher->m); _entryData->_focus = state; + SetWidgetVisibility(); } void MacroConditionWindowEdit::WindowFocusChanged(int state) @@ -202,6 +214,22 @@ void MacroConditionWindowEdit::WindowFocusChanged(int state) std::lock_guard lock(switcher->m); _entryData->_windowFocusChanged = state; + SetWidgetVisibility(); +} + +void MacroConditionWindowEdit::UpdateFocusWindow() +{ + _focusWindow->setText(QString::fromStdString(switcher->currentTitle)); +} + +void MacroConditionWindowEdit::SetWidgetVisibility() +{ + if (!_entryData) { + return; + } + setLayoutVisible(_focusLayout, + _entryData->_focus || _entryData->_windowFocusChanged); + adjustSize(); } void MacroConditionWindowEdit::UpdateEntryData() @@ -215,4 +243,5 @@ void MacroConditionWindowEdit::UpdateEntryData() _maximized->setChecked(_entryData->_maximized); _focused->setChecked(_entryData->_focus); _windowFocusChanged->setChecked(_entryData->_windowFocusChanged); + SetWidgetVisibility(); } diff --git a/src/macro-core/macro-condition-window.hpp b/src/macro-core/macro-condition-window.hpp index 911c23f7..c94a206d 100644 --- a/src/macro-core/macro-condition-window.hpp +++ b/src/macro-core/macro-condition-window.hpp @@ -18,9 +18,11 @@ public: } private: - bool CheckWindowTitleSwitchDirect(std::string ¤tWindowTitle); - bool CheckWindowTitleSwitchRegex(std::string ¤tWindowTitle, - std::vector &windowList); + bool + CheckWindowTitleSwitchDirect(const std::string ¤tWindowTitle); + bool + CheckWindowTitleSwitchRegex(const std::string ¤tWindowTitle, + const std::vector &windowList); public: std::string _window; @@ -56,6 +58,7 @@ private slots: void MaximizedChanged(int state); void FocusedChanged(int state); void WindowFocusChanged(int state); + void UpdateFocusWindow(); signals: void HeaderInfoChanged(const QString &); @@ -65,8 +68,13 @@ protected: QCheckBox *_maximized; QCheckBox *_focused; QCheckBox *_windowFocusChanged; + QLabel *_focusWindow; + QHBoxLayout *_focusLayout; + QTimer _timer; std::shared_ptr _entryData; private: + void SetWidgetVisibility(); + bool _loading = true; }; diff --git a/src/osx/advanced-scene-switcher-osx.mm b/src/osx/advanced-scene-switcher-osx.mm index 73f79feb..9cbaa207 100644 --- a/src/osx/advanced-scene-switcher-osx.mm +++ b/src/osx/advanced-scene-switcher-osx.mm @@ -288,10 +288,38 @@ void GetProcessList(QStringList &list) } } +void GetForegroundProcessName(std::string &proc) +{ + proc.resize(0); + @autoreleasepool { + NSWorkspace *ws = [NSWorkspace sharedWorkspace]; + NSArray *array = [ws runningApplications]; + for (NSRunningApplication *app in array) { + if (!app.isActive) { + continue; + } + NSString *name = app.localizedName; + if (!name) { + break; + } + const char *str = name.UTF8String; + proc = std::string(str); + break; + } + } +} + +void GetForegroundProcessName(QString &proc) +{ + std::string temp; + GetForegroundProcessName(temp); + proc = QString::fromStdString(temp); +} + bool isInFocus(const QString &executable) { std::string current; - GetCurrentWindowTitle(current); + GetForegroundProcessName(current); // True if executable switch equals current window bool equals = (executable.toStdString() == current); diff --git a/src/platform-funcs.hpp b/src/platform-funcs.hpp index fc95dfd9..670b078b 100644 --- a/src/platform-funcs.hpp +++ b/src/platform-funcs.hpp @@ -13,6 +13,7 @@ bool isMaximized(const std::string &title); std::pair getCursorPos(); int secondsSinceLastInput(); void GetProcessList(QStringList &processes); +void GetForegroundProcessName(std::string &name); bool isInFocus(const QString &executable); void PressKeys(const std::vector keys, int duration); void PlatformInit(); diff --git a/src/switcher-data-structs.hpp b/src/switcher-data-structs.hpp index ef6de4b4..96fca0f2 100644 --- a/src/switcher-data-structs.hpp +++ b/src/switcher-data-structs.hpp @@ -148,6 +148,7 @@ struct SwitcherData { std::vector ignoreIdleWindows; std::string lastTitle; std::string currentTitle; + std::string currentForegroundProcess; std::deque screenRegionSwitches; std::pair lastCursorPos = {0, 0}; diff --git a/src/win/advanced-scene-switcher-win.cpp b/src/win/advanced-scene-switcher-win.cpp index 534f3a13..e9a7955d 100644 --- a/src/win/advanced-scene-switcher-win.cpp +++ b/src/win/advanced-scene-switcher-win.cpp @@ -238,7 +238,7 @@ void GetProcessList(QStringList &processes) CloseHandle(procSnapshot); } -bool isInFocus(const QString &executable) +void GetForegroundProcessName(QString &proc) { // only checks if the current foreground window is from the same executable, // may return true for any window from a program @@ -249,21 +249,36 @@ bool isInFocus(const QString &executable) HANDLE process = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); if (process == NULL) { - return false; + return; } WCHAR executablePath[600]; GetModuleFileNameEx(process, 0, executablePath, 600); CloseHandle(process); - QString file = QString::fromWCharArray(executablePath) - .split(QRegularExpression("(/|\\\\)")) - .back(); + proc = QString::fromWCharArray(executablePath) + .split(QRegularExpression("(/|\\\\)")) + .back(); +} + +void GetForegroundProcessName(std::string &proc) +{ + QString temp; + GetForegroundProcessName(temp); + proc = temp.toStdString(); +} + +bool isInFocus(const QString &executable) +{ + // only checks if the current foreground window is from the same executable, + // may return true for any window from a program + QString foregroundProc; + GetForegroundProcessName(foregroundProc); // True if executable switch equals current window - bool equals = (executable == file); + bool equals = (executable == foregroundProc); // True if executable switch matches current window - bool matches = file.contains(QRegularExpression(executable)); + bool matches = foregroundProc.contains(QRegularExpression(executable)); return (equals || matches); }