mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-03-21 17:34:57 -05:00
Improve focus handling
* Display current focus window / process * Match against app name instead of window name on MacOS when using Process condition * Clean up
This commit is contained in:
parent
267ab6a7c1
commit
50e26aba72
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -280,6 +280,9 @@ void SwitcherData::setPreconditions()
|
|||
}
|
||||
currentTitle = title;
|
||||
|
||||
// Process name
|
||||
GetForegroundProcessName(currentForegroundProcess);
|
||||
|
||||
// Cursor
|
||||
std::pair<int, int> cursorPos = getCursorPos();
|
||||
cursorPosChanged = cursorPos.first != switcher->lastCursorPos.first ||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -48,36 +48,48 @@ std::string MacroConditionProcess::GetShortDesc()
|
|||
|
||||
MacroConditionProcessEdit::MacroConditionProcessEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionProcess> 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<std::string, QWidget *> 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<std::mutex> 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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<MacroConditionProcess> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
bool _loading = true;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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<std::string> &windowList)
|
||||
const std::string ¤tWindowTitle,
|
||||
const std::vector<std::string> &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<std::string> windowList;
|
||||
GetWindowList(windowList);
|
||||
|
||||
|
|
@ -101,17 +102,18 @@ std::string MacroConditionWindow::GetShortDesc()
|
|||
|
||||
MacroConditionWindowEdit::MacroConditionWindowEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionWindow> 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<std::mutex> lock(switcher->m);
|
||||
_entryData->_focus = state;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionWindowEdit::WindowFocusChanged(int state)
|
||||
|
|
@ -202,6 +214,22 @@ void MacroConditionWindowEdit::WindowFocusChanged(int state)
|
|||
|
||||
std::lock_guard<std::mutex> 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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,11 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
bool CheckWindowTitleSwitchDirect(std::string ¤tWindowTitle);
|
||||
bool CheckWindowTitleSwitchRegex(std::string ¤tWindowTitle,
|
||||
std::vector<std::string> &windowList);
|
||||
bool
|
||||
CheckWindowTitleSwitchDirect(const std::string ¤tWindowTitle);
|
||||
bool
|
||||
CheckWindowTitleSwitchRegex(const std::string ¤tWindowTitle,
|
||||
const std::vector<std::string> &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<MacroConditionWindow> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
bool _loading = true;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ bool isMaximized(const std::string &title);
|
|||
std::pair<int, int> getCursorPos();
|
||||
int secondsSinceLastInput();
|
||||
void GetProcessList(QStringList &processes);
|
||||
void GetForegroundProcessName(std::string &name);
|
||||
bool isInFocus(const QString &executable);
|
||||
void PressKeys(const std::vector<HotkeyType> keys, int duration);
|
||||
void PlatformInit();
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ struct SwitcherData {
|
|||
std::vector<std::string> ignoreIdleWindows;
|
||||
std::string lastTitle;
|
||||
std::string currentTitle;
|
||||
std::string currentForegroundProcess;
|
||||
|
||||
std::deque<ScreenRegionSwitch> screenRegionSwitches;
|
||||
std::pair<int, int> lastCursorPos = {0, 0};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user