This commit is contained in:
WarmUpTill 2018-07-13 22:29:01 +02:00
parent 3381e6d62f
commit d41868c660
18 changed files with 4336 additions and 4290 deletions

View File

@ -1,17 +1,17 @@
#include <obs-module.h>
OBS_DECLARE_MODULE()
void InitSceneSwitcher();
void FreeSceneSwitcher();
bool obs_module_load(void)
{
InitSceneSwitcher();
return true;
}
void obs_module_unload(void)
{
FreeSceneSwitcher();
}
#include <obs-module.h>
OBS_DECLARE_MODULE()
void InitSceneSwitcher();
void FreeSceneSwitcher();
bool obs_module_load(void)
{
InitSceneSwitcher();
return true;
}
void obs_module_unload(void)
{
FreeSceneSwitcher();
}

View File

@ -1,172 +1,168 @@
#include <windows.h>
#include <util/platform.h>
#include "advanced-scene-switcher.hpp"
#include <TlHelp32.h>
#include <Psapi.h>
using namespace std;
static bool GetWindowTitle(HWND window, string& title)
{
size_t len = (size_t)GetWindowTextLengthW(window);
wstring wtitle;
wtitle.resize(len);
if (!GetWindowTextW(window, &wtitle[0], (int)len + 1))
return false;
len = os_wcs_to_utf8(wtitle.c_str(), 0, nullptr, 0);
title.resize(len);
os_wcs_to_utf8(wtitle.c_str(), 0, &title[0], len + 1);
return true;
}
static bool WindowValid(HWND window)
{
LONG_PTR styles, ex_styles;
RECT rect;
DWORD id;
if (!IsWindowVisible(window))
return false;
GetWindowThreadProcessId(window, &id);
if (id == GetCurrentProcessId())
return false;
GetClientRect(window, &rect);
styles = GetWindowLongPtr(window, GWL_STYLE);
ex_styles = GetWindowLongPtr(window, GWL_EXSTYLE);
if (ex_styles & WS_EX_TOOLWINDOW)
return false;
if (styles & WS_CHILD)
return false;
return true;
}
void GetWindowList(vector<string>& windows)
{
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD);
while (window)
{
string title;
if (WindowValid(window) && GetWindowTitle(window, title))
windows.emplace_back(title);
window = GetNextWindow(window, GW_HWNDNEXT);
}
}
void GetCurrentWindowTitle(string& title)
{
HWND window = GetForegroundWindow();
DWORD pid;
DWORD thid;
thid = GetWindowThreadProcessId(window, &pid);
/*GetWindowText will freeze if the control it is reading was created in another thread.
It does not directly read the control.Instead,
it waits for the thread that created the control to process a WM_GETTEXT message.
So if that thread is frozen in a WaitFor... call you have a deadlock.*/
DWORD this_thid = GetCurrentThreadId();
//wstring message = L"\nUI id " + to_wstring(thid) + L", this_th_id " + to_wstring(this_thid) + L"\n";
//OutputDebugString(message.c_str());
//if (this_thid == thid) {
if (GetCurrentProcessId() == pid) {
title = "OBS";
return;
}
GetWindowTitle(window, title);
}
pair<int, int> getCursorPos()
{
pair<int, int> pos(0, 0);
POINT cursorPos;
if (GetPhysicalCursorPos(&cursorPos))
{
pos.first = cursorPos.x;
pos.second = cursorPos.y;
}
return pos;
}
bool isFullscreen()
{
RECT appBounds;
RECT rc;
GetWindowRect(GetDesktopWindow(), &rc);
HWND hwnd = GetForegroundWindow();
if (hwnd != GetDesktopWindow() && hwnd != GetShellWindow())
{
GetWindowRect(hwnd, &appBounds);
if (rc.bottom == appBounds.bottom && rc.top == appBounds.top && rc.left == appBounds.left
&& rc.right == appBounds.right)
{
return true;
}
}
return false;
}
void GetProcessList(QStringList &processes) {
HANDLE procSnapshot;
PROCESSENTRY32 procEntry;
procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (procSnapshot == INVALID_HANDLE_VALUE) return;
procEntry.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(procSnapshot, &procEntry)) {
CloseHandle(procSnapshot);
return;
}
do {
QString tempexe = QString::fromWCharArray(procEntry.szExeFile);
if (tempexe == "System") continue;
if (tempexe == "[System Process]") continue;
if (processes.contains(tempexe)) continue;
processes.append(tempexe);
} while (Process32Next(procSnapshot, &procEntry));
CloseHandle(procSnapshot);
}
bool isInFocus(const QString &exeToCheck) {
// only checks if the current foreground window is from the same executable,
// may return true for incorrent not meant windows from a program
HWND foregroundWindow = GetForegroundWindow();
DWORD processId = 0;
GetWindowThreadProcessId(foregroundWindow, &processId);
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
if (process == NULL) return false;
WCHAR executablePath[600];
GetModuleFileNameEx(process, 0, executablePath, 600);
CloseHandle(process);
return exeToCheck == QString::fromWCharArray(executablePath).split(QRegExp("(/|\\\\)")).back();
}
int getLastInputTime()
{
LASTINPUTINFO lastInputInfo;
lastInputInfo.cbSize = sizeof(LASTINPUTINFO);
if (GetLastInputInfo(&lastInputInfo))
return lastInputInfo.dwTime;
return 0;
}
int getTime()
{
return GetTickCount();
}
int secondsSinceLastInput()
{
return (getTime() - getLastInputTime()) / 1000;
}
#include <windows.h>
#include <util/platform.h>
#include "advanced-scene-switcher.hpp"
#include <TlHelp32.h>
#include <Psapi.h>
using namespace std;
static bool GetWindowTitle(HWND window, string& title)
{
size_t len = (size_t)GetWindowTextLengthW(window);
wstring wtitle;
wtitle.resize(len);
if (!GetWindowTextW(window, &wtitle[0], (int)len + 1))
return false;
len = os_wcs_to_utf8(wtitle.c_str(), 0, nullptr, 0);
title.resize(len);
os_wcs_to_utf8(wtitle.c_str(), 0, &title[0], len + 1);
return true;
}
static bool WindowValid(HWND window)
{
LONG_PTR styles, ex_styles;
RECT rect;
DWORD id;
if (!IsWindowVisible(window))
return false;
GetWindowThreadProcessId(window, &id);
if (id == GetCurrentProcessId())
return false;
GetClientRect(window, &rect);
styles = GetWindowLongPtr(window, GWL_STYLE);
ex_styles = GetWindowLongPtr(window, GWL_EXSTYLE);
if (ex_styles & WS_EX_TOOLWINDOW)
return false;
if (styles & WS_CHILD)
return false;
return true;
}
void GetWindowList(vector<string>& windows)
{
HWND window = GetWindow(GetDesktopWindow(), GW_CHILD);
while (window)
{
string title;
if (WindowValid(window) && GetWindowTitle(window, title))
windows.emplace_back(title);
window = GetNextWindow(window, GW_HWNDNEXT);
}
}
void GetCurrentWindowTitle(string& title)
{
HWND window = GetForegroundWindow();
DWORD pid;
DWORD thid;
thid = GetWindowThreadProcessId(window, &pid);
/*GetWindowText will freeze if the control it is reading was created in another thread.
It does not directly read the control.Instead,
it waits for the thread that created the control to process a WM_GETTEXT message.
So if that thread is frozen in a WaitFor... call you have a deadlock.*/
if (GetCurrentProcessId() == pid) {
title = "OBS";
return;
}
GetWindowTitle(window, title);
}
pair<int, int> getCursorPos()
{
pair<int, int> pos(0, 0);
POINT cursorPos;
if (GetPhysicalCursorPos(&cursorPos))
{
pos.first = cursorPos.x;
pos.second = cursorPos.y;
}
return pos;
}
bool isFullscreen()
{
RECT appBounds;
RECT rc;
GetWindowRect(GetDesktopWindow(), &rc);
HWND hwnd = GetForegroundWindow();
if (hwnd != GetDesktopWindow() && hwnd != GetShellWindow())
{
GetWindowRect(hwnd, &appBounds);
if (rc.bottom == appBounds.bottom && rc.top == appBounds.top && rc.left == appBounds.left
&& rc.right == appBounds.right)
{
return true;
}
}
return false;
}
void GetProcessList(QStringList &processes) {
HANDLE procSnapshot;
PROCESSENTRY32 procEntry;
procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (procSnapshot == INVALID_HANDLE_VALUE) return;
procEntry.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(procSnapshot, &procEntry)) {
CloseHandle(procSnapshot);
return;
}
do {
QString tempexe = QString::fromWCharArray(procEntry.szExeFile);
if (tempexe == "System") continue;
if (tempexe == "[System Process]") continue;
if (processes.contains(tempexe)) continue;
processes.append(tempexe);
} while (Process32Next(procSnapshot, &procEntry));
CloseHandle(procSnapshot);
}
bool isInFocus(const QString &exeToCheck) {
// only checks if the current foreground window is from the same executable,
// may return true for incorrent not meant windows from a program
HWND foregroundWindow = GetForegroundWindow();
DWORD processId = 0;
GetWindowThreadProcessId(foregroundWindow, &processId);
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
if (process == NULL) return false;
WCHAR executablePath[600];
GetModuleFileNameEx(process, 0, executablePath, 600);
CloseHandle(process);
return exeToCheck == QString::fromWCharArray(executablePath).split(QRegExp("(/|\\\\)")).back();
}
int getLastInputTime()
{
LASTINPUTINFO lastInputInfo;
lastInputInfo.cbSize = sizeof(LASTINPUTINFO);
if (GetLastInputInfo(&lastInputInfo))
return lastInputInfo.dwTime;
return 0;
}
int getTime()
{
return GetTickCount();
}
int secondsSinceLastInput()
{
return (getTime() - getLastInputTime()) / 1000;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,134 +1,175 @@
#pragma once
#include <QDialog>
#include <memory>
#include <vector>
#include <string>
#include "ui_advanced-scene-switcher.h"
#include "switcher-data-structs.hpp"
struct obs_weak_source;
typedef struct obs_weak_source obs_weak_source_t;
class QCloseEvent;
class SceneSwitcher : public QDialog {
Q_OBJECT
public:
std::unique_ptr<Ui_SceneSwitcher> ui;
bool loading = true;
SceneSwitcher(QWidget *parent);
void closeEvent(QCloseEvent *event) override;
void SetStarted();
void SetStopped();
int FindByData(const QString &window);
int ScreenRegionFindByData(const QString &region);
int PauseScenesFindByData(const QString &scene);
int PauseWindowsFindByData(const QString &window);
int IgnoreWindowsFindByData(const QString &window);
int SceneRoundTripFindByData(const QString &scene1);
int SceneTransitionsFindByData(const QString &scene1, const QString &scene2);
int DefaultTransitionsFindByData(const QString &scene);
int executableFindByData(const QString &exe);
int IgnoreIdleWindowsFindByData(const QString& window);
int randomFindByData(const QString& scene);
void UpdateNonMatchingScene(const QString &name);
void UpdateAutoStopScene(const QString &name);
void UpdateIdleDataTransition(const QString& name);
void UpdateIdleDataScene(const QString& name);
public slots:
void on_switches_currentRowChanged(int idx);
void on_add_clicked();
void on_remove_clicked();
void on_noMatchDontSwitch_clicked();
void on_noMatchSwitch_clicked();
void on_noMatchRandomSwitch_clicked();
void on_startAtLaunch_toggled(bool value);
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
void on_checkInterval_valueChanged(int value);
void on_toggleStartButton_clicked();
void on_screenRegions_currentRowChanged(int idx);
void on_screenRegionAdd_clicked();
void on_screenRegionRemove_clicked();
void on_pauseScenes_currentRowChanged(int idx);
void on_pauseScenesAdd_clicked();
void on_pauseScenesRemove_clicked();
void on_pauseWindows_currentRowChanged(int idx);
void on_pauseWindowsAdd_clicked();
void on_pauseWindowsRemove_clicked();
void on_ignoreWindows_currentRowChanged(int idx);
void on_ignoreWindowsAdd_clicked();
void on_ignoreWindowsRemove_clicked();
void on_sceneRoundTrips_currentRowChanged(int idx);
void on_sceneRoundTripAdd_clicked();
void on_sceneRoundTripRemove_clicked();
void on_sceneRoundTripSave_clicked();
void on_sceneRoundTripLoad_clicked();
void on_autoStopSceneCheckBox_stateChanged(int state);
void on_autoStopScenes_currentTextChanged(const QString &text);
void on_sceneTransitions_currentRowChanged(int idx);
void on_transitionsAdd_clicked();
void on_transitionsRemove_clicked();
void on_defaultTransitions_currentRowChanged(int idx);
void on_defaultTransitionsAdd_clicked();
void on_defaultTransitionsRemove_clicked();
void on_browseButton_clicked();
void on_readFileCheckBox_stateChanged(int state);
void on_readPathLineEdit_textChanged(const QString & text);
void on_writePathLineEdit_textChanged(const QString & text);
void on_browseButton_2_clicked();
void on_executableAdd_clicked();
void on_executableRemove_clicked();
void on_executables_currentRowChanged(int idx);
void on_idleCheckBox_stateChanged(int state);
void on_idleTransitions_currentTextChanged(const QString& text);
void on_idleScenes_currentTextChanged(const QString& text);
void on_idleSpinBox_valueChanged(int i);
void on_ignoreIdleWindows_currentRowChanged(int idx);
void on_ignoreIdleAdd_clicked();
void on_ignoreIdleRemove_clicked();
void on_randomAdd_clicked();
void on_randomRemove_clicked();
void on_randomScenesList_currentRowChanged(int idx);
void on_fileAdd_clicked();
void on_fileRemove_clicked();
void on_fileScenesList_currentRowChanged(int idx);
void on_browseButton_3_clicked();
void on_priorityUp_clicked();
void on_priorityDown_clicked();
void updateScreenRegionCursorPos();
void on_close_clicked();
};
void GetWindowList(std::vector<std::string> &windows);
void GetCurrentWindowTitle(std::string &title);
pair<int, int> getCursorPos();
bool isFullscreen();
int secondsSinceLastInput();
bool isInFocus(const QString &exeToCheck);
void GetProcessList(QStringList &processes);
struct SwitcherData;
extern SwitcherData* switcher;
#pragma once
#include <QDialog>
#include <memory>
#include <vector>
#include <string>
#include "ui_advanced-scene-switcher.h"
#include "switcher-data-structs.hpp"
class QCloseEvent;
/*******************************************************************************
* Advanced Scene Switcher window
*******************************************************************************/
class SceneSwitcher : public QDialog {
Q_OBJECT
public:
std::unique_ptr<Ui_SceneSwitcher> ui;
bool loading = true;
SceneSwitcher(QWidget *parent);
void closeEvent(QCloseEvent *event) override;
void SetStarted();
void SetStopped();
int FindByData(const QString &window);
int ScreenRegionFindByData(const QString &region);
int PauseScenesFindByData(const QString &scene);
int PauseWindowsFindByData(const QString &window);
int IgnoreWindowsFindByData(const QString &window);
int SceneRoundTripFindByData(const QString &scene1);
int SceneTransitionsFindByData(const QString &scene1, const QString &scene2);
int DefaultTransitionsFindByData(const QString &scene);
int executableFindByData(const QString &exe);
int IgnoreIdleWindowsFindByData(const QString& window);
int randomFindByData(const QString& scene);
void UpdateNonMatchingScene(const QString &name);
void UpdateAutoStopScene(const QString &name);
void UpdateIdleDataTransition(const QString& name);
void UpdateIdleDataScene(const QString& name);
public slots:
void on_switches_currentRowChanged(int idx);
void on_add_clicked();
void on_remove_clicked();
void on_noMatchDontSwitch_clicked();
void on_noMatchSwitch_clicked();
void on_noMatchRandomSwitch_clicked();
void on_startAtLaunch_toggled(bool value);
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
void on_checkInterval_valueChanged(int value);
void on_toggleStartButton_clicked();
void on_screenRegions_currentRowChanged(int idx);
void on_screenRegionAdd_clicked();
void on_screenRegionRemove_clicked();
void on_pauseScenes_currentRowChanged(int idx);
void on_pauseScenesAdd_clicked();
void on_pauseScenesRemove_clicked();
void on_pauseWindows_currentRowChanged(int idx);
void on_pauseWindowsAdd_clicked();
void on_pauseWindowsRemove_clicked();
void on_ignoreWindows_currentRowChanged(int idx);
void on_ignoreWindowsAdd_clicked();
void on_ignoreWindowsRemove_clicked();
void on_sceneRoundTrips_currentRowChanged(int idx);
void on_sceneRoundTripAdd_clicked();
void on_sceneRoundTripRemove_clicked();
void on_sceneRoundTripSave_clicked();
void on_sceneRoundTripLoad_clicked();
void on_autoStopSceneCheckBox_stateChanged(int state);
void on_autoStopScenes_currentTextChanged(const QString &text);
void on_sceneTransitions_currentRowChanged(int idx);
void on_transitionsAdd_clicked();
void on_transitionsRemove_clicked();
void on_defaultTransitions_currentRowChanged(int idx);
void on_defaultTransitionsAdd_clicked();
void on_defaultTransitionsRemove_clicked();
void on_browseButton_clicked();
void on_readFileCheckBox_stateChanged(int state);
void on_readPathLineEdit_textChanged(const QString & text);
void on_writePathLineEdit_textChanged(const QString & text);
void on_browseButton_2_clicked();
void on_executableAdd_clicked();
void on_executableRemove_clicked();
void on_executables_currentRowChanged(int idx);
void on_idleCheckBox_stateChanged(int state);
void on_idleTransitions_currentTextChanged(const QString& text);
void on_idleScenes_currentTextChanged(const QString& text);
void on_idleSpinBox_valueChanged(int i);
void on_ignoreIdleWindows_currentRowChanged(int idx);
void on_ignoreIdleAdd_clicked();
void on_ignoreIdleRemove_clicked();
void on_randomAdd_clicked();
void on_randomRemove_clicked();
void on_randomScenesList_currentRowChanged(int idx);
void on_fileAdd_clicked();
void on_fileRemove_clicked();
void on_fileScenesList_currentRowChanged(int idx);
void on_browseButton_3_clicked();
void on_priorityUp_clicked();
void on_priorityDown_clicked();
void updateScreenRegionCursorPos();
void on_close_clicked();
};
/********************************************************************************
* Windowtitle helper
********************************************************************************/
void GetWindowList(std::vector<std::string> &windows);
void GetCurrentWindowTitle(std::string &title);
bool isFullscreen();
/********************************************************************************
* Screenregion helper
********************************************************************************/
pair<int, int> getCursorPos();
/********************************************************************************
* Idle detection helper
********************************************************************************/
int secondsSinceLastInput();
/********************************************************************************
* Executable helper
********************************************************************************/
void GetProcessList(QStringList &processes);
bool isInFocus(const QString &exeToCheck);
/********************************************************************************
* Sceneswitch helper
********************************************************************************/
struct obs_weak_source;
typedef struct obs_weak_source obs_weak_source_t;
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2);
void switchScene(OBSWeakSource scene, OBSWeakSource transition);
/********************************************************************************
* Hotkey helper
********************************************************************************/
void startStopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed);
void loadKeybinding(obs_hotkey_id hotkeyId);
/********************************************************************************
* Main SwitcherData
********************************************************************************/
struct SwitcherData;
extern SwitcherData* switcher;

View File

@ -1,140 +1,140 @@
#include "advanced-scene-switcher.hpp"
int SceneSwitcher::executableFindByData(const QString& exe)
{
int count = ui->executables->count();
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->executables->item(i);
QString itemExe = item->data(Qt::UserRole).toString();
if (itemExe == exe)
return i;
}
return -1;
}
void SceneSwitcher::on_executables_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->executables->item(idx);
QString exec = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->executableSwitches)
{
if (exec.compare(s.mExe) == 0)
{
QString sceneName = GetWeakSourceName(s.mScene).c_str();
QString transitionName = GetWeakSourceName(s.mTransition).c_str();
ui->executableScenes->setCurrentText(sceneName);
ui->executable->setCurrentText(exec);
ui->executableTransitions->setCurrentText(transitionName);
ui->requiresFocusCheckBox->setChecked(s.mInFocus);
break;
}
}
}
void SceneSwitcher::on_executableAdd_clicked()
{
QString sceneName = ui->executableScenes->currentText();
QString exeName = ui->executable->currentText();
QString transitionName = ui->executableTransitions->currentText();
bool inFocus = ui->requiresFocusCheckBox->isChecked();
if (exeName.isEmpty() || sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(exeName);
QString text = MakeSwitchNameExecutable(sceneName, exeName, transitionName, inFocus);
int idx = executableFindByData(exeName);
if (idx == -1)
{
lock_guard<mutex> lock(switcher->m);
switcher->executableSwitches.emplace_back(
source, transition, exeName.toUtf8().constData(), inFocus);
QListWidgetItem* item = new QListWidgetItem(text, ui->executables);
item->setData(Qt::UserRole, v);
}
else
{
QListWidgetItem* item = ui->executables->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->executableSwitches)
{
if (s.mExe == exeName)
{
s.mScene = source;
s.mTransition = transition;
s.mInFocus = inFocus;
break;
}
}
}
ui->executables->sortItems();
}
}
void SceneSwitcher::on_executableRemove_clicked()
{
QListWidgetItem* item = ui->executables->currentItem();
if (!item)
return;
QString exe = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->executableSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.mExe == exe)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SwitcherData::checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
{
QStringList runningProcesses;
GetProcessList(runningProcesses);
for (ExecutableSceneSwitch& s : executableSwitches)
{
if (runningProcesses.contains(s.mExe))
{
scene = s.mScene;
transition = s.mTransition;
match = !s.mInFocus || (s.mInFocus && isInFocus(s.mExe));
break;
}
}
}
#include "advanced-scene-switcher.hpp"
int SceneSwitcher::executableFindByData(const QString& exe)
{
int count = ui->executables->count();
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->executables->item(i);
QString itemExe = item->data(Qt::UserRole).toString();
if (itemExe == exe)
return i;
}
return -1;
}
void SceneSwitcher::on_executables_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->executables->item(idx);
QString exec = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->executableSwitches)
{
if (exec.compare(s.mExe) == 0)
{
QString sceneName = GetWeakSourceName(s.mScene).c_str();
QString transitionName = GetWeakSourceName(s.mTransition).c_str();
ui->executableScenes->setCurrentText(sceneName);
ui->executable->setCurrentText(exec);
ui->executableTransitions->setCurrentText(transitionName);
ui->requiresFocusCheckBox->setChecked(s.mInFocus);
break;
}
}
}
void SceneSwitcher::on_executableAdd_clicked()
{
QString sceneName = ui->executableScenes->currentText();
QString exeName = ui->executable->currentText();
QString transitionName = ui->executableTransitions->currentText();
bool inFocus = ui->requiresFocusCheckBox->isChecked();
if (exeName.isEmpty() || sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(exeName);
QString text = MakeSwitchNameExecutable(sceneName, exeName, transitionName, inFocus);
int idx = executableFindByData(exeName);
if (idx == -1)
{
lock_guard<mutex> lock(switcher->m);
switcher->executableSwitches.emplace_back(
source, transition, exeName.toUtf8().constData(), inFocus);
QListWidgetItem* item = new QListWidgetItem(text, ui->executables);
item->setData(Qt::UserRole, v);
}
else
{
QListWidgetItem* item = ui->executables->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->executableSwitches)
{
if (s.mExe == exeName)
{
s.mScene = source;
s.mTransition = transition;
s.mInFocus = inFocus;
break;
}
}
}
ui->executables->sortItems();
}
}
void SceneSwitcher::on_executableRemove_clicked()
{
QListWidgetItem* item = ui->executables->currentItem();
if (!item)
return;
QString exe = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->executableSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.mExe == exe)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SwitcherData::checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
{
QStringList runningProcesses;
GetProcessList(runningProcesses);
for (ExecutableSceneSwitch& s : executableSwitches)
{
if (runningProcesses.contains(s.mExe))
{
scene = s.mScene;
transition = s.mTransition;
match = !s.mInFocus || (s.mInFocus && isInFocus(s.mExe));
break;
}
}
}

View File

@ -1,261 +1,254 @@
#include <QFileDialog>
#include <QTextStream>
#include <QDateTime>
#include <obs.hpp>
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_browseButton_clicked()
{
QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to write to ..."), QDir::currentPath(), tr("Text files (*.txt)"));
if (!path.isEmpty())
ui->writePathLineEdit->setText(path);
}
void SceneSwitcher::on_readFileCheckBox_stateChanged(int state)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (!state)
{
ui->browseButton_2->setDisabled(true);
ui->readPathLineEdit->setDisabled(true);
switcher->fileIO.readEnabled = false;
}
else
{
ui->browseButton_2->setDisabled(false);
ui->readPathLineEdit->setDisabled(false);
switcher->fileIO.readEnabled = true;
}
}
void SceneSwitcher::on_readPathLineEdit_textChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (text.isEmpty())
{
switcher->fileIO.readEnabled = false;
return;
}
switcher->fileIO.readEnabled = true;
switcher->fileIO.readPath = text.toUtf8().constData();
}
void SceneSwitcher::on_writePathLineEdit_textChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (text.isEmpty())
{
switcher->fileIO.writeEnabled = false;
return;
}
switcher->fileIO.writeEnabled = true;
switcher->fileIO.writePath = text.toUtf8().constData();
}
void SceneSwitcher::on_browseButton_2_clicked()
{
QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)"));
if (!path.isEmpty())
ui->readPathLineEdit->setText(path);
}
void SwitcherData::writeSceneInfoToFile()
{
if (!fileIO.writeEnabled || fileIO.writePath.empty())
return;
obs_source_t* currentSource = obs_frontend_get_current_scene();
QFile file(QString::fromStdString(fileIO.writePath));
if (file.open(QIODevice::WriteOnly))
{
const char* msg = obs_source_get_name(currentSource);
file.write(msg, qstrlen(msg));
file.close();
}
obs_source_release(currentSource);
}
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2);
void SwitcherData::checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
{
if (!fileIO.readEnabled || fileIO.readPath.empty())
return;
QFile file(QString::fromStdString(fileIO.readPath));
if (file.open(QIODevice::ReadOnly))
{
QTextStream in(&file);
QString sceneStr = in.readLine();
obs_source_t* sceneRead = obs_get_source_by_name(sceneStr.toUtf8().constData());
if (sceneRead){
obs_weak_source_t* sceneReadWs = obs_source_get_weak_source(sceneRead);
match = true;
scene = sceneReadWs;
transition = nullptr;
obs_weak_source_release(sceneReadWs);
obs_source_release(sceneRead);
}
file.close();
}
}
void SwitcherData::checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
{
for (FileSwitch& s : fileSwitches)
{
bool equal = false;
QString t = QString::fromStdString(s.text);
QFile file(QString::fromStdString(s.file));
if (!file.open(QIODevice::ReadOnly))
continue;
//check file mod date
if (s.useTime)
{
QDateTime newLastMod = QFileInfo(file).lastModified();
if (s.lastMod == newLastMod)
continue;
s.lastMod = newLastMod;
}
if (s.useRegex)
{
QTextStream in(&file);
QRegExp rx(t);
equal = rx.exactMatch(in.readAll());
}
else
{
/*Im using QTextStream here so the conversion between different lineendings is done by QT.
*QT itself uses only the linefeed internally so the input by the user is always using that,
*but the files selected by the user might use different line endings.
*If you are reading this and know of a cleaner way to do this, please let me know :)
*/
QTextStream in(&file);
QTextStream text(&t);
while (!in.atEnd() && !text.atEnd())
{
QString fileLine = in.readLine();
QString textLine = text.readLine();
if (QString::compare(fileLine, textLine, Qt::CaseSensitive) != 0)
{
equal = false;
break;
}
else {
equal = true;
}
}
}
file.close();
if (equal)
{
scene = s.scene;
transition = s.transition;
match = true;
break;
}
}
}
void SceneSwitcher::on_browseButton_3_clicked()
{
QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)"));
if (!path.isEmpty())
ui->filePathLineEdit->setText(path);
}
void SceneSwitcher::on_fileAdd_clicked()
{
QString sceneName = ui->fileScenes->currentText();
QString transitionName = ui->fileTransitions->currentText();
QString fileName = ui->filePathLineEdit->text();
QString text = ui->fileTextEdit->toPlainText();
bool useRegex = ui->fileContentRegExCheckBox->isChecked();
bool useTime = ui->fileContentTimeCheckBox->isChecked();
if (sceneName.isEmpty() || transitionName.isEmpty() || fileName.isEmpty() || text.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString switchText = MakeFileSwitchName(sceneName, transitionName, fileName, text, useRegex, useTime);
QVariant v = QVariant::fromValue(switchText);
QListWidgetItem* item = new QListWidgetItem(switchText, ui->fileScenesList);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->fileSwitches.emplace_back(
source, transition, fileName.toUtf8().constData(), text.toUtf8().constData(), useRegex, useTime);
}
void SceneSwitcher::on_fileRemove_clicked()
{
QListWidgetItem* item = ui->fileScenesList->currentItem();
if (!item)
return;
int idx = ui->fileScenesList->currentRow();
if (idx == -1)
return;
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->fileSwitches;
switches.erase(switches.begin() + idx);
}
qDeleteAll(ui->fileScenesList->selectedItems());
//delete item;
}
void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
lock_guard<mutex> lock(switcher->m);
if (switcher->fileSwitches.size() <= idx)
return;
FileSwitch s = switcher->fileSwitches[idx];
string sceneName = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition);
ui->fileScenes->setCurrentText(sceneName.c_str());
ui->fileTransitions->setCurrentText(transitionName.c_str());
ui->fileTextEdit->setPlainText(s.text.c_str());
ui->filePathLineEdit->setText(s.file.c_str());
ui->fileContentRegExCheckBox->setChecked(s.useRegex);
ui->fileContentTimeCheckBox->setChecked(s.useTime);
}
#include <QFileDialog>
#include <QTextStream>
#include <QDateTime>
#include <obs.hpp>
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_browseButton_clicked()
{
QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to write to ..."), QDir::currentPath(), tr("Text files (*.txt)"));
if (!path.isEmpty())
ui->writePathLineEdit->setText(path);
}
void SceneSwitcher::on_readFileCheckBox_stateChanged(int state)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (!state)
{
ui->browseButton_2->setDisabled(true);
ui->readPathLineEdit->setDisabled(true);
switcher->fileIO.readEnabled = false;
}
else
{
ui->browseButton_2->setDisabled(false);
ui->readPathLineEdit->setDisabled(false);
switcher->fileIO.readEnabled = true;
}
}
void SceneSwitcher::on_readPathLineEdit_textChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (text.isEmpty())
{
switcher->fileIO.readEnabled = false;
return;
}
switcher->fileIO.readEnabled = true;
switcher->fileIO.readPath = text.toUtf8().constData();
}
void SceneSwitcher::on_writePathLineEdit_textChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (text.isEmpty())
{
switcher->fileIO.writeEnabled = false;
return;
}
switcher->fileIO.writeEnabled = true;
switcher->fileIO.writePath = text.toUtf8().constData();
}
void SceneSwitcher::on_browseButton_2_clicked()
{
QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)"));
if (!path.isEmpty())
ui->readPathLineEdit->setText(path);
}
void SwitcherData::writeSceneInfoToFile()
{
if (!fileIO.writeEnabled || fileIO.writePath.empty())
return;
obs_source_t* currentSource = obs_frontend_get_current_scene();
QFile file(QString::fromStdString(fileIO.writePath));
if (file.open(QIODevice::WriteOnly))
{
const char* msg = obs_source_get_name(currentSource);
file.write(msg, qstrlen(msg));
file.close();
}
obs_source_release(currentSource);
}
void SwitcherData::checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
{
if (!fileIO.readEnabled || fileIO.readPath.empty())
return;
QFile file(QString::fromStdString(fileIO.readPath));
if (file.open(QIODevice::ReadOnly))
{
QTextStream in(&file);
QString sceneStr = in.readLine();
obs_source_t* sceneRead = obs_get_source_by_name(sceneStr.toUtf8().constData());
if (sceneRead){
obs_weak_source_t* sceneReadWs = obs_source_get_weak_source(sceneRead);
match = true;
scene = sceneReadWs;
transition = nullptr;
obs_weak_source_release(sceneReadWs);
obs_source_release(sceneRead);
}
file.close();
}
}
void SwitcherData::checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
{
for (FileSwitch& s : fileSwitches)
{
bool equal = false;
QString t = QString::fromStdString(s.text);
QFile file(QString::fromStdString(s.file));
if (!file.open(QIODevice::ReadOnly))
continue;
if (s.useTime)
{
QDateTime newLastMod = QFileInfo(file).lastModified();
if (s.lastMod == newLastMod)
continue;
s.lastMod = newLastMod;
}
if (s.useRegex)
{
QTextStream in(&file);
QRegExp rx(t);
equal = rx.exactMatch(in.readAll());
}
else
{
/*Im using QTextStream here so the conversion between different lineendings is done by QT.
*QT itself uses only the linefeed internally so the input by the user is always using that,
*but the files selected by the user might use different line endings.
*If you are reading this and know of a cleaner way to do this, please let me know :)
*/
QTextStream in(&file);
QTextStream text(&t);
while (!in.atEnd() && !text.atEnd())
{
QString fileLine = in.readLine();
QString textLine = text.readLine();
if (QString::compare(fileLine, textLine, Qt::CaseSensitive) != 0)
{
equal = false;
break;
}
else {
equal = true;
}
}
}
file.close();
if (equal)
{
scene = s.scene;
transition = s.transition;
match = true;
break;
}
}
}
void SceneSwitcher::on_browseButton_3_clicked()
{
QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to read from ..."), QDir::currentPath(), tr("Any files (*.*)"));
if (!path.isEmpty())
ui->filePathLineEdit->setText(path);
}
void SceneSwitcher::on_fileAdd_clicked()
{
QString sceneName = ui->fileScenes->currentText();
QString transitionName = ui->fileTransitions->currentText();
QString fileName = ui->filePathLineEdit->text();
QString text = ui->fileTextEdit->toPlainText();
bool useRegex = ui->fileContentRegExCheckBox->isChecked();
bool useTime = ui->fileContentTimeCheckBox->isChecked();
if (sceneName.isEmpty() || transitionName.isEmpty() || fileName.isEmpty() || text.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString switchText = MakeFileSwitchName(sceneName, transitionName, fileName, text, useRegex, useTime);
QVariant v = QVariant::fromValue(switchText);
QListWidgetItem* item = new QListWidgetItem(switchText, ui->fileScenesList);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->fileSwitches.emplace_back(
source, transition, fileName.toUtf8().constData(), text.toUtf8().constData(), useRegex, useTime);
}
void SceneSwitcher::on_fileRemove_clicked()
{
QListWidgetItem* item = ui->fileScenesList->currentItem();
if (!item)
return;
int idx = ui->fileScenesList->currentRow();
if (idx == -1)
return;
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->fileSwitches;
switches.erase(switches.begin() + idx);
}
qDeleteAll(ui->fileScenesList->selectedItems());
}
void SceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
lock_guard<mutex> lock(switcher->m);
if (switcher->fileSwitches.size() <= idx)
return;
FileSwitch s = switcher->fileSwitches[idx];
string sceneName = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition);
ui->fileScenes->setCurrentText(sceneName.c_str());
ui->fileTransitions->setCurrentText(transitionName.c_str());
ui->fileTextEdit->setPlainText(s.text.c_str());
ui->filePathLineEdit->setText(s.file.c_str());
ui->fileContentRegExCheckBox->setChecked(s.useRegex);
ui->fileContentTimeCheckBox->setChecked(s.useTime);
}

View File

@ -1,107 +1,107 @@
#include "advanced-scene-switcher.hpp"
#include <obs-module.h>
void SceneSwitcher::on_close_clicked()
{
done(0);
}
void SceneSwitcher::on_startAtLaunch_toggled(bool value)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->startAtLaunch = value;
}
void SceneSwitcher::UpdateNonMatchingScene(const QString& name)
{
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
switcher->nonMatchingScene = ws;
obs_weak_source_release(ws);
obs_source_release(scene);
}
void SceneSwitcher::on_noMatchDontSwitch_clicked()
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->switchIfNotMatching = NO_SWITCH;
ui->noMatchSwitchScene->setEnabled(false);
}
void SceneSwitcher::on_noMatchSwitch_clicked()
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->switchIfNotMatching = SWITCH;
ui->noMatchSwitchScene->setEnabled(true);
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
}
void SceneSwitcher::on_noMatchRandomSwitch_clicked()
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->switchIfNotMatching = RANDOM_SWITCH;
ui->noMatchSwitchScene->setEnabled(false);
}
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
UpdateNonMatchingScene(text);
}
void SceneSwitcher::on_checkInterval_valueChanged(int value)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->interval = value;
}
void SceneSwitcher::SetStarted()
{
ui->toggleStartButton->setText("Stop");
ui->pluginRunningText->setText("Active");
}
void SceneSwitcher::SetStopped()
{
ui->toggleStartButton->setText("Start");
ui->pluginRunningText->setText("Inactive");
}
void SceneSwitcher::on_toggleStartButton_clicked()
{
if (switcher->th.joinable())
{
switcher->Stop();
SetStopped();
}
else
{
switcher->Start();
SetStarted();
}
}
void SceneSwitcher::closeEvent(QCloseEvent*)
{
obs_frontend_save();
}
#include "advanced-scene-switcher.hpp"
#include <obs-module.h>
void SceneSwitcher::on_close_clicked()
{
done(0);
}
void SceneSwitcher::on_startAtLaunch_toggled(bool value)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->startAtLaunch = value;
}
void SceneSwitcher::UpdateNonMatchingScene(const QString& name)
{
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
switcher->nonMatchingScene = ws;
obs_weak_source_release(ws);
obs_source_release(scene);
}
void SceneSwitcher::on_noMatchDontSwitch_clicked()
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->switchIfNotMatching = NO_SWITCH;
ui->noMatchSwitchScene->setEnabled(false);
}
void SceneSwitcher::on_noMatchSwitch_clicked()
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->switchIfNotMatching = SWITCH;
ui->noMatchSwitchScene->setEnabled(true);
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
}
void SceneSwitcher::on_noMatchRandomSwitch_clicked()
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->switchIfNotMatching = RANDOM_SWITCH;
ui->noMatchSwitchScene->setEnabled(false);
}
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
UpdateNonMatchingScene(text);
}
void SceneSwitcher::on_checkInterval_valueChanged(int value)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->interval = value;
}
void SceneSwitcher::SetStarted()
{
ui->toggleStartButton->setText("Stop");
ui->pluginRunningText->setText("Active");
}
void SceneSwitcher::SetStopped()
{
ui->toggleStartButton->setText("Start");
ui->pluginRunningText->setText("Inactive");
}
void SceneSwitcher::on_toggleStartButton_clicked()
{
if (switcher->th.joinable())
{
switcher->Stop();
SetStopped();
}
else
{
switcher->Start();
SetStarted();
}
}
void SceneSwitcher::closeEvent(QCloseEvent*)
{
obs_frontend_save();
}

View File

@ -1,72 +1,72 @@
#include <obs-module.h>
#include "advanced-scene-switcher.hpp"
void startStopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
{
UNUSED_PARAMETER(data);
UNUSED_PARAMETER(hotkey);
if (pressed)
{
if (switcher->th.joinable())
switcher->Stop();
else
switcher->Start();
}
obs_data_array* hotkeyData = obs_hotkey_save(id);
if (hotkeyData != NULL)
{
char* path = obs_module_config_path("");
ofstream file;
file.open(string(path).append("hotkey.txt"), ofstream::trunc);
if (file.is_open())
{
size_t num = obs_data_array_count(hotkeyData);
for (size_t i = 0; i < num; i++)
{
obs_data_t* data = obs_data_array_item(hotkeyData, i);
string temp = obs_data_get_json(data);
obs_data_release(data);
file << temp;
}
file.close();
}
bfree(path);
}
obs_data_array_release(hotkeyData);
}
string loadConfigFile(string filename)
{
ifstream settingsFile;
char* path = obs_module_config_path("");
string value;
settingsFile.open(string(path).append(filename));
if (settingsFile.is_open())
{
settingsFile.seekg(0, ios::end);
value.reserve(settingsFile.tellg());
settingsFile.seekg(0, ios::beg);
value.assign((istreambuf_iterator<char>(settingsFile)), istreambuf_iterator<char>());
settingsFile.close();
}
bfree(path);
return value;
}
void loadKeybinding(obs_hotkey_id hotkeyId)
{
string bindings = loadConfigFile("hotkey.txt");
if (!bindings.empty())
{
obs_data_array_t* hotkeyData = obs_data_array_create();
obs_data_t* data = obs_data_create_from_json(bindings.c_str());
obs_data_array_insert(hotkeyData, 0, data);
obs_data_release(data);
obs_hotkey_load(hotkeyId, hotkeyData);
obs_data_array_release(hotkeyData);
}
}
#include <obs-module.h>
#include "advanced-scene-switcher.hpp"
void startStopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pressed)
{
UNUSED_PARAMETER(data);
UNUSED_PARAMETER(hotkey);
if (pressed)
{
if (switcher->th.joinable())
switcher->Stop();
else
switcher->Start();
}
obs_data_array* hotkeyData = obs_hotkey_save(id);
if (hotkeyData != NULL)
{
char* path = obs_module_config_path("");
ofstream file;
file.open(string(path).append("hotkey.txt"), ofstream::trunc);
if (file.is_open())
{
size_t num = obs_data_array_count(hotkeyData);
for (size_t i = 0; i < num; i++)
{
obs_data_t* data = obs_data_array_item(hotkeyData, i);
string temp = obs_data_get_json(data);
obs_data_release(data);
file << temp;
}
file.close();
}
bfree(path);
}
obs_data_array_release(hotkeyData);
}
string loadConfigFile(string filename)
{
ifstream settingsFile;
char* path = obs_module_config_path("");
string value;
settingsFile.open(string(path).append(filename));
if (settingsFile.is_open())
{
settingsFile.seekg(0, ios::end);
value.reserve(settingsFile.tellg());
settingsFile.seekg(0, ios::beg);
value.assign((istreambuf_iterator<char>(settingsFile)), istreambuf_iterator<char>());
settingsFile.close();
}
bfree(path);
return value;
}
void loadKeybinding(obs_hotkey_id hotkeyId)
{
string bindings = loadConfigFile("hotkey.txt");
if (!bindings.empty())
{
obs_data_array_t* hotkeyData = obs_data_array_create();
obs_data_t* data = obs_data_create_from_json(bindings.c_str());
obs_data_array_insert(hotkeyData, 0, data);
obs_data_release(data);
obs_hotkey_load(hotkeyId, hotkeyData);
obs_data_array_release(hotkeyData);
}
}

View File

@ -1,210 +1,210 @@
#include "advanced-scene-switcher.hpp"
void SwitcherData::checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
{
if (!idleData.idleEnable)
return;
string title;
bool ignoreIdle = false;
//lock.unlock();
GetCurrentWindowTitle(title);
//lock.lock();
for (string& window : ignoreIdleWindows)
{
if (window == title)
{
ignoreIdle = true;
break;
}
}
if (!ignoreIdle)
{
for (string& window : ignoreIdleWindows)
{
try
{
bool matches = regex_match(title, regex(window));
if (matches)
{
ignoreIdle = true;
break;
}
}
catch (const regex_error&)
{
}
}
}
if (!ignoreIdle && secondsSinceLastInput() > idleData.time)
{
scene = idleData.scene;
transition = idleData.transition;
match = true;
}
}
void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (!state)
{
ui->idleScenes->setDisabled(true);
ui->idleSpinBox->setDisabled(true);
ui->idleTransitions->setDisabled(true);
switcher->idleData.idleEnable = false;
}
else
{
ui->idleScenes->setDisabled(false);
ui->idleSpinBox->setDisabled(false);
ui->idleTransitions->setDisabled(false);
switcher->idleData.idleEnable = true;
UpdateIdleDataTransition(ui->idleTransitions->currentText());
UpdateIdleDataScene(ui->idleScenes->currentText());
}
}
void SceneSwitcher::UpdateIdleDataTransition(const QString& name)
{
obs_weak_source_t* transition = GetWeakTransitionByQString(name);
switcher->idleData.transition = transition;
}
void SceneSwitcher::UpdateIdleDataScene(const QString& name)
{
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
switcher->idleData.scene = ws;
obs_weak_source_release(ws);
obs_source_release(scene);
}
void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
UpdateIdleDataTransition(text);
}
void SceneSwitcher::on_idleScenes_currentTextChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
UpdateIdleDataScene(text);
}
void SceneSwitcher::on_idleSpinBox_valueChanged(int i)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->idleData.time = i;
}
void SceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->ignoreIdleWindows->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& w : switcher->ignoreIdleWindows)
{
if (window.compare(w.c_str()) == 0)
{
ui->ignoreIdleWindowsWindows->setCurrentText(w.c_str());
break;
}
}
}
void SceneSwitcher::on_ignoreIdleAdd_clicked()
{
QString windowName = ui->ignoreIdleWindowsWindows->currentText();
if (windowName.isEmpty())
return;
QVariant v = QVariant::fromValue(windowName);
QList<QListWidgetItem*> items = ui->ignoreIdleWindows->findItems(windowName, Qt::MatchExactly);
if (items.size() == 0)
{
QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreIdleWindows);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->ignoreIdleWindows.emplace_back(windowName.toUtf8().constData());
ui->ignoreIdleWindows->sortItems();
}
}
void SceneSwitcher::on_ignoreIdleRemove_clicked()
{
QListWidgetItem* item = ui->ignoreIdleWindows->currentItem();
if (!item)
return;
QString windowName = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& windows = switcher->ignoreIdleWindows;
for (auto it = windows.begin(); it != windows.end(); ++it)
{
auto& s = *it;
if (s == windowName.toUtf8().constData())
{
windows.erase(it);
break;
}
}
}
delete item;
}
int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString& window)
{
int count = ui->ignoreIdleWindows->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->ignoreIdleWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window)
{
idx = i;
break;
}
}
return idx;
}
#include "advanced-scene-switcher.hpp"
void SwitcherData::checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
{
if (!idleData.idleEnable)
return;
string title;
bool ignoreIdle = false;
//lock.unlock();
GetCurrentWindowTitle(title);
//lock.lock();
for (string& window : ignoreIdleWindows)
{
if (window == title)
{
ignoreIdle = true;
break;
}
}
if (!ignoreIdle)
{
for (string& window : ignoreIdleWindows)
{
try
{
bool matches = regex_match(title, regex(window));
if (matches)
{
ignoreIdle = true;
break;
}
}
catch (const regex_error&)
{
}
}
}
if (!ignoreIdle && secondsSinceLastInput() > idleData.time)
{
scene = idleData.scene;
transition = idleData.transition;
match = true;
}
}
void SceneSwitcher::on_idleCheckBox_stateChanged(int state)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (!state)
{
ui->idleScenes->setDisabled(true);
ui->idleSpinBox->setDisabled(true);
ui->idleTransitions->setDisabled(true);
switcher->idleData.idleEnable = false;
}
else
{
ui->idleScenes->setDisabled(false);
ui->idleSpinBox->setDisabled(false);
ui->idleTransitions->setDisabled(false);
switcher->idleData.idleEnable = true;
UpdateIdleDataTransition(ui->idleTransitions->currentText());
UpdateIdleDataScene(ui->idleScenes->currentText());
}
}
void SceneSwitcher::UpdateIdleDataTransition(const QString& name)
{
obs_weak_source_t* transition = GetWeakTransitionByQString(name);
switcher->idleData.transition = transition;
}
void SceneSwitcher::UpdateIdleDataScene(const QString& name)
{
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
switcher->idleData.scene = ws;
obs_weak_source_release(ws);
obs_source_release(scene);
}
void SceneSwitcher::on_idleTransitions_currentTextChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
UpdateIdleDataTransition(text);
}
void SceneSwitcher::on_idleScenes_currentTextChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
UpdateIdleDataScene(text);
}
void SceneSwitcher::on_idleSpinBox_valueChanged(int i)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
switcher->idleData.time = i;
}
void SceneSwitcher::on_ignoreIdleWindows_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->ignoreIdleWindows->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& w : switcher->ignoreIdleWindows)
{
if (window.compare(w.c_str()) == 0)
{
ui->ignoreIdleWindowsWindows->setCurrentText(w.c_str());
break;
}
}
}
void SceneSwitcher::on_ignoreIdleAdd_clicked()
{
QString windowName = ui->ignoreIdleWindowsWindows->currentText();
if (windowName.isEmpty())
return;
QVariant v = QVariant::fromValue(windowName);
QList<QListWidgetItem*> items = ui->ignoreIdleWindows->findItems(windowName, Qt::MatchExactly);
if (items.size() == 0)
{
QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreIdleWindows);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->ignoreIdleWindows.emplace_back(windowName.toUtf8().constData());
ui->ignoreIdleWindows->sortItems();
}
}
void SceneSwitcher::on_ignoreIdleRemove_clicked()
{
QListWidgetItem* item = ui->ignoreIdleWindows->currentItem();
if (!item)
return;
QString windowName = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& windows = switcher->ignoreIdleWindows;
for (auto it = windows.begin(); it != windows.end(); ++it)
{
auto& s = *it;
if (s == windowName.toUtf8().constData())
{
windows.erase(it);
break;
}
}
}
delete item;
}
int SceneSwitcher::IgnoreIdleWindowsFindByData(const QString& window)
{
int count = ui->ignoreIdleWindows->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->ignoreIdleWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window)
{
idx = i;
break;
}
}
return idx;
}

View File

@ -1,242 +1,242 @@
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_pauseScenesAdd_clicked()
{
QString sceneName = ui->pauseScenesScenes->currentText();
if (sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
QVariant v = QVariant::fromValue(sceneName);
QList<QListWidgetItem*> items = ui->pauseScenes->findItems(sceneName, Qt::MatchExactly);
if (items.size() == 0)
{
QListWidgetItem* item = new QListWidgetItem(sceneName, ui->pauseScenes);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->pauseScenesSwitches.emplace_back(source);
ui->pauseScenes->sortItems();
}
}
void SceneSwitcher::on_pauseScenesRemove_clicked()
{
QListWidgetItem* item = ui->pauseScenes->currentItem();
if (!item)
return;
QString pauseScene = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->pauseScenesSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s == GetWeakSourceByQString(pauseScene))
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_pauseWindowsAdd_clicked()
{
QString windowName = ui->pauseWindowsWindows->currentText();
if (windowName.isEmpty())
return;
QVariant v = QVariant::fromValue(windowName);
QList<QListWidgetItem*> items = ui->pauseWindows->findItems(windowName, Qt::MatchExactly);
if (items.size() == 0)
{
QListWidgetItem* item = new QListWidgetItem(windowName, ui->pauseWindows);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->pauseWindowsSwitches.emplace_back(windowName.toUtf8().constData());
ui->pauseWindows->sortItems();
}
}
void SceneSwitcher::on_pauseWindowsRemove_clicked()
{
QListWidgetItem* item = ui->pauseWindows->currentItem();
if (!item)
return;
QString windowName = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->pauseWindowsSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s == windowName.toUtf8().constData())
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->pauseScenes->item(idx);
QString scene = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->pauseScenesSwitches)
{
string name = GetWeakSourceName(s);
if (scene.compare(name.c_str()) == 0)
{
ui->pauseScenesScenes->setCurrentText(name.c_str());
break;
}
}
}
void SceneSwitcher::on_pauseWindows_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->pauseWindows->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->pauseWindowsSwitches)
{
if (window.compare(s.c_str()) == 0)
{
ui->pauseWindowsWindows->setCurrentText(s.c_str());
break;
}
}
}
int SceneSwitcher::PauseScenesFindByData(const QString& scene)
{
int count = ui->pauseScenes->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->pauseScenes->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == scene)
{
idx = i;
break;
}
}
return idx;
}
int SceneSwitcher::PauseWindowsFindByData(const QString& window)
{
int count = ui->pauseWindows->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->pauseWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window)
{
idx = i;
break;
}
}
return idx;
}
bool SwitcherData::checkPause()
{
bool pause = false;
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
for (OBSWeakSource& s : pauseScenesSwitches)
{
if (s == ws)
{
pause = true;
break;
}
}
obs_source_release(currentSource);
obs_weak_source_release(ws);
string title;
if (!pause)
{
//lock.unlock();
GetCurrentWindowTitle(title);
//lock.lock();
for (string& window : pauseWindowsSwitches)
{
if (window == title)
{
pause = true;
break;
}
}
}
if (!pause)
{
//lock.unlock();
GetCurrentWindowTitle(title);
//lock.lock();
for (string& window : pauseWindowsSwitches)
{
try
{
bool matches = regex_match(title, regex(window));
if (matches)
{
pause = true;
break;
}
}
catch (const regex_error&)
{
}
}
}
return pause;
}
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_pauseScenesAdd_clicked()
{
QString sceneName = ui->pauseScenesScenes->currentText();
if (sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
QVariant v = QVariant::fromValue(sceneName);
QList<QListWidgetItem*> items = ui->pauseScenes->findItems(sceneName, Qt::MatchExactly);
if (items.size() == 0)
{
QListWidgetItem* item = new QListWidgetItem(sceneName, ui->pauseScenes);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->pauseScenesSwitches.emplace_back(source);
ui->pauseScenes->sortItems();
}
}
void SceneSwitcher::on_pauseScenesRemove_clicked()
{
QListWidgetItem* item = ui->pauseScenes->currentItem();
if (!item)
return;
QString pauseScene = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->pauseScenesSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s == GetWeakSourceByQString(pauseScene))
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_pauseWindowsAdd_clicked()
{
QString windowName = ui->pauseWindowsWindows->currentText();
if (windowName.isEmpty())
return;
QVariant v = QVariant::fromValue(windowName);
QList<QListWidgetItem*> items = ui->pauseWindows->findItems(windowName, Qt::MatchExactly);
if (items.size() == 0)
{
QListWidgetItem* item = new QListWidgetItem(windowName, ui->pauseWindows);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->pauseWindowsSwitches.emplace_back(windowName.toUtf8().constData());
ui->pauseWindows->sortItems();
}
}
void SceneSwitcher::on_pauseWindowsRemove_clicked()
{
QListWidgetItem* item = ui->pauseWindows->currentItem();
if (!item)
return;
QString windowName = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->pauseWindowsSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s == windowName.toUtf8().constData())
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_pauseScenes_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->pauseScenes->item(idx);
QString scene = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->pauseScenesSwitches)
{
string name = GetWeakSourceName(s);
if (scene.compare(name.c_str()) == 0)
{
ui->pauseScenesScenes->setCurrentText(name.c_str());
break;
}
}
}
void SceneSwitcher::on_pauseWindows_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->pauseWindows->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->pauseWindowsSwitches)
{
if (window.compare(s.c_str()) == 0)
{
ui->pauseWindowsWindows->setCurrentText(s.c_str());
break;
}
}
}
int SceneSwitcher::PauseScenesFindByData(const QString& scene)
{
int count = ui->pauseScenes->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->pauseScenes->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == scene)
{
idx = i;
break;
}
}
return idx;
}
int SceneSwitcher::PauseWindowsFindByData(const QString& window)
{
int count = ui->pauseWindows->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->pauseWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window)
{
idx = i;
break;
}
}
return idx;
}
bool SwitcherData::checkPause()
{
bool pause = false;
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
for (OBSWeakSource& s : pauseScenesSwitches)
{
if (s == ws)
{
pause = true;
break;
}
}
obs_source_release(currentSource);
obs_weak_source_release(ws);
string title;
if (!pause)
{
//lock.unlock();
GetCurrentWindowTitle(title);
//lock.lock();
for (string& window : pauseWindowsSwitches)
{
if (window == title)
{
pause = true;
break;
}
}
}
if (!pause)
{
//lock.unlock();
GetCurrentWindowTitle(title);
//lock.lock();
for (string& window : pauseWindowsSwitches)
{
try
{
bool matches = regex_match(title, regex(window));
if (matches)
{
pause = true;
break;
}
}
catch (const regex_error&)
{
}
}
}
return pause;
}

View File

@ -1,45 +1,44 @@
#include <algorithm>
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_priorityUp_clicked()
{
int currentIndex = ui->priorityList->currentRow();
if (currentIndex != -1 && currentIndex != 0)
{
ui->priorityList->insertItem(currentIndex - 1 ,ui->priorityList->takeItem(currentIndex));
ui->priorityList->setCurrentRow(currentIndex -1);
lock_guard<mutex> lock(switcher->m);
iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex - 1);
}
}
void SceneSwitcher::on_priorityDown_clicked()
{
int currentIndex = ui->priorityList->currentRow();
if (currentIndex != -1 && currentIndex != ui->priorityList->count() - 1)
{
ui->priorityList->insertItem(currentIndex + 1, ui->priorityList->takeItem(currentIndex));
ui->priorityList->setCurrentRow(currentIndex + 1);
lock_guard<mutex> lock(switcher->m);
iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex + 1);
}
}
bool SwitcherData::prioFuncsValid()
{
auto it = std::unique(functionNamesByPriority.begin(), functionNamesByPriority.end());
bool wasUnique = (it == functionNamesByPriority.end());
if (!wasUnique)
return false;
for (int p : functionNamesByPriority)
{
if (p < 0 || p > 5)
return false;
}
return true;
}
#include <algorithm>
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_priorityUp_clicked()
{
int currentIndex = ui->priorityList->currentRow();
if (currentIndex != -1 && currentIndex != 0)
{
ui->priorityList->insertItem(currentIndex - 1 ,ui->priorityList->takeItem(currentIndex));
ui->priorityList->setCurrentRow(currentIndex -1);
lock_guard<mutex> lock(switcher->m);
iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex - 1);
}
}
void SceneSwitcher::on_priorityDown_clicked()
{
int currentIndex = ui->priorityList->currentRow();
if (currentIndex != -1 && currentIndex != ui->priorityList->count() - 1)
{
ui->priorityList->insertItem(currentIndex + 1, ui->priorityList->takeItem(currentIndex));
ui->priorityList->setCurrentRow(currentIndex + 1);
lock_guard<mutex> lock(switcher->m);
iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex + 1);
}
}
bool SwitcherData::prioFuncsValid()
{
auto it = std::unique(functionNamesByPriority.begin(), functionNamesByPriority.end());
bool wasUnique = (it == functionNamesByPriority.end());
if (!wasUnique)
return false;
for (int p : functionNamesByPriority)
{
if (p < 0 || p > 5)
return false;
}
return true;
}

View File

@ -1,143 +1,141 @@
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->randomScenesList->item(idx);
QString randomSceneStr = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->randomSwitches)
{
if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0)
{
QString sceneName = GetWeakSourceName(s.scene).c_str();
QString transitionName = GetWeakSourceName(s.transition).c_str();
ui->randomScenes->setCurrentText(sceneName);
ui->randomSpinBox->setValue(s.delay);
ui->randomTransitions->setCurrentText(transitionName);
break;
}
}
}
int SceneSwitcher::randomFindByData(const QString& randomStr)
{
int count = ui->randomScenesList->count();
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->randomScenesList->item(i);
QString str = item->data(Qt::UserRole).toString();
if (str == randomStr)
return i;
}
return -1;
}
void SceneSwitcher::on_randomAdd_clicked()
{
QString sceneName = ui->randomScenes->currentText();
QString transitionName = ui->randomTransitions->currentText();
double delay = ui->randomSpinBox->value();
if (sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeRandomSwitchName(sceneName, transitionName, delay);
QVariant v = QVariant::fromValue(text);
int idx = randomFindByData(text);
if (idx == -1)
{
lock_guard<mutex> lock(switcher->m);
switcher->randomSwitches.emplace_back(
source, transition, delay, text.toUtf8().constData());
QListWidgetItem* item = new QListWidgetItem(text, ui->randomScenesList);
item->setData(Qt::UserRole, v);
}
else
{
QListWidgetItem* item = ui->randomScenesList->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->randomSwitches)
{
if (s.scene == source)
{
s.delay = delay;
s.transition = transition;
s.randomSwitchStr = text.toUtf8().constData();;
break;
}
}
}
ui->randomScenesList->sortItems();
}
}
void SceneSwitcher::on_randomRemove_clicked()
{
QListWidgetItem* item = ui->randomScenesList->currentItem();
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->randomSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.randomSwitchStr == text)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SwitcherData::checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay)
{
if (randomSwitches.size() == 0)
return;
vector<RandomSwitch> rs (randomSwitches);
std::random_shuffle(rs.begin(), rs.end());
for (RandomSwitch& r : rs)
{
if (r.scene == lastRandomScene)
continue;
scene = r.scene;
transition = r.transition;
delay = (int)r.delay * 1000;
match = true;
lastRandomScene = r.scene;
break;
}
}
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_randomScenesList_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->randomScenesList->item(idx);
QString randomSceneStr = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->randomSwitches)
{
if (randomSceneStr.compare(s.randomSwitchStr.c_str()) == 0)
{
QString sceneName = GetWeakSourceName(s.scene).c_str();
QString transitionName = GetWeakSourceName(s.transition).c_str();
ui->randomScenes->setCurrentText(sceneName);
ui->randomSpinBox->setValue(s.delay);
ui->randomTransitions->setCurrentText(transitionName);
break;
}
}
}
int SceneSwitcher::randomFindByData(const QString& randomStr)
{
int count = ui->randomScenesList->count();
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->randomScenesList->item(i);
QString str = item->data(Qt::UserRole).toString();
if (str == randomStr)
return i;
}
return -1;
}
void SceneSwitcher::on_randomAdd_clicked()
{
QString sceneName = ui->randomScenes->currentText();
QString transitionName = ui->randomTransitions->currentText();
double delay = ui->randomSpinBox->value();
if (sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeRandomSwitchName(sceneName, transitionName, delay);
QVariant v = QVariant::fromValue(text);
int idx = randomFindByData(text);
if (idx == -1)
{
lock_guard<mutex> lock(switcher->m);
switcher->randomSwitches.emplace_back(
source, transition, delay, text.toUtf8().constData());
QListWidgetItem* item = new QListWidgetItem(text, ui->randomScenesList);
item->setData(Qt::UserRole, v);
}
else
{
QListWidgetItem* item = ui->randomScenesList->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->randomSwitches)
{
if (s.scene == source)
{
s.delay = delay;
s.transition = transition;
s.randomSwitchStr = text.toUtf8().constData();;
break;
}
}
}
ui->randomScenesList->sortItems();
}
}
void SceneSwitcher::on_randomRemove_clicked()
{
QListWidgetItem* item = ui->randomScenesList->currentItem();
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->randomSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.randomSwitchStr == text)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SwitcherData::checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay)
{
if (randomSwitches.size() == 0)
return;
vector<RandomSwitch> rs (randomSwitches);
std::random_shuffle(rs.begin(), rs.end());
for (RandomSwitch& r : rs)
{
if (r.scene == lastRandomScene)
continue;
scene = r.scene;
transition = r.transition;
delay = (int)r.delay * 1000;
match = true;
lastRandomScene = r.scene;
break;
}
}

View File

@ -1,309 +1,305 @@
#include <QFileDialog>
#include <QTextStream>
#include <obs.hpp>
#include "advanced-scene-switcher.hpp"
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2);
void SceneSwitcher::on_sceneRoundTripAdd_clicked()
{
QString scene1Name = ui->sceneRoundTripScenes1->currentText();
QString scene2Name = ui->sceneRoundTripScenes2->currentText();
QString transitionName = ui->sceneRoundTripTransitions->currentText();
if (scene1Name.isEmpty() || scene2Name.isEmpty())
return;
double delay = ui->sceneRoundTripSpinBox->value();
if (scene1Name == scene2Name)
return;
OBSWeakSource source1 = GetWeakSourceByQString(scene1Name);
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeSceneRoundTripSwitchName(scene1Name, scene2Name, transitionName, delay);
QVariant v = QVariant::fromValue(text);
int idx = SceneRoundTripFindByData(scene1Name);
if (idx == -1)
{
QListWidgetItem* item = new QListWidgetItem(text, ui->sceneRoundTrips);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->sceneRoundTripSwitches.emplace_back(
source1, source2, transition, int(delay * 1000), text.toUtf8().constData());
}
else
{
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->sceneRoundTripSwitches)
{
if (s.scene1 == source1)
{
s.scene2 = source2;
s.delay = int(delay * 1000);
s.transition = transition;
s.sceneRoundTripStr = text.toUtf8().constData();
break;
}
}
}
ui->sceneRoundTrips->sortItems();
}
}
void SceneSwitcher::on_sceneRoundTripRemove_clicked()
{
QListWidgetItem* item = ui->sceneRoundTrips->currentItem();
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->sceneRoundTripSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.sceneRoundTripStr == text)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (!state)
{
ui->autoStopScenes->setDisabled(true);
switcher->autoStopEnable = false;
}
else
{
ui->autoStopScenes->setDisabled(false);
switcher->autoStopEnable = true;
}
}
void SceneSwitcher::UpdateAutoStopScene(const QString& name)
{
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
switcher->autoStopScene = ws;
obs_weak_source_release(ws);
obs_source_release(scene);
}
void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
UpdateAutoStopScene(text);
}
void SceneSwitcher::on_sceneRoundTripSave_clicked()
{
QString directory = QFileDialog::getSaveFileName(
this, tr("Save Scene Round Trip to file ..."), QDir::currentPath(), tr("Text files (*.txt)"));
if (!directory.isEmpty())
{
QFile file(directory);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches)
{
out << QString::fromStdString(GetWeakSourceName(s.scene1)) << "\n";
out << QString::fromStdString(GetWeakSourceName(s.scene2)) << "\n";
out << s.delay << "\n";
out << QString::fromStdString(s.sceneRoundTripStr) << "\n";
out << QString::fromStdString(GetWeakSourceName(s.transition)) << "\n";
}
}
}
void SceneSwitcher::on_sceneRoundTripLoad_clicked()
{
lock_guard<mutex> lock(switcher->m);
QString directory = QFileDialog::getOpenFileName(
this, tr("Select a file to read Scene Round Trip from ..."), QDir::currentPath(), tr("Text files (*.txt)"));
if (!directory.isEmpty())
{
QFile file(directory);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&file);
vector<QString> lines;
vector<SceneRoundTripSwitch> newSceneRoundTripSwitch;
while (!in.atEnd())
{
QString line = in.readLine();
lines.push_back(line);
if (lines.size() == 5)
{
OBSWeakSource scene1 = GetWeakSourceByQString(lines[0]);
OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]);
OBSWeakSource transition = GetWeakTransitionByQString(lines[4]);
if (WeakSourceValid(scene1) && WeakSourceValid(scene2)
&& WeakSourceValid(transition))
{
newSceneRoundTripSwitch.emplace_back(SceneRoundTripSwitch(
GetWeakSourceByQString(lines[0]),
GetWeakSourceByQString(lines[1]),
GetWeakTransitionByQString(lines[4]),
lines[2].toInt(),
lines[3].toStdString()));
}
lines.clear();
}
}
//unvalid amount of lines in file or nothing valid read
if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0)
return;
switcher->sceneRoundTripSwitches.clear();
ui->sceneRoundTrips->clear();
switcher->sceneRoundTripSwitches = newSceneRoundTripSwitch;
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches)
{
QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(s.sceneRoundTripStr), ui->sceneRoundTrips);
item->setData(Qt::UserRole, QString::fromStdString(s.sceneRoundTripStr));
}
}
}
void SwitcherData::checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, unique_lock<mutex>& lock)
{
bool sceneRoundTripActive = false;
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
for (SceneRoundTripSwitch& s : sceneRoundTripSwitches)
{
if (s.scene1 == ws)
{
sceneRoundTripActive = true;
int dur = s.delay - interval;
if (dur > 0)
{
string s = obs_source_get_name(currentSource);
waitSceneName = s;
cv.wait_for(lock, chrono::milliseconds(dur));
}
obs_source_t* currentSource2 = obs_frontend_get_current_scene();
// only switch if user hasn't changed scene manually
if (currentSource == currentSource2)
{
match = true;
scene = s.scene2;
transition = s.transition;
}
obs_source_release(currentSource2);
break;
}
}
obs_source_release(currentSource);
obs_weak_source_release(ws);
}
void SceneSwitcher::on_sceneRoundTrips_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
QString sceneRoundTrip = item->text();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->sceneRoundTripSwitches)
{
if (sceneRoundTrip.compare(s.sceneRoundTripStr.c_str()) == 0)
{
string scene1 = GetWeakSourceName(s.scene1);
string scene2 = GetWeakSourceName(s.scene2);
string transitionName = GetWeakSourceName(s.transition);
int delay = s.delay;
ui->sceneRoundTripScenes1->setCurrentText(scene1.c_str());
ui->sceneRoundTripScenes2->setCurrentText(scene2.c_str());
ui->sceneRoundTripTransitions->setCurrentText(transitionName.c_str());
ui->sceneRoundTripSpinBox->setValue((double)delay/1000);
break;
}
}
}
int SceneSwitcher::SceneRoundTripFindByData(const QString& scene1)
{
QRegExp rx(scene1 + " ->.*");
int count = ui->sceneRoundTrips->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->sceneRoundTrips->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString))
{
idx = i;
break;
}
}
return idx;
}
void SwitcherData::autoStopStreamAndRecording()
{
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
if (ws && autoStopScene == ws)
{
if (obs_frontend_streaming_active())
obs_frontend_streaming_stop();
if (obs_frontend_recording_active())
obs_frontend_recording_stop();
}
obs_source_release(currentSource);
obs_weak_source_release(ws);
}
#include <QFileDialog>
#include <QTextStream>
#include <obs.hpp>
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_sceneRoundTripAdd_clicked()
{
QString scene1Name = ui->sceneRoundTripScenes1->currentText();
QString scene2Name = ui->sceneRoundTripScenes2->currentText();
QString transitionName = ui->sceneRoundTripTransitions->currentText();
if (scene1Name.isEmpty() || scene2Name.isEmpty())
return;
double delay = ui->sceneRoundTripSpinBox->value();
if (scene1Name == scene2Name)
return;
OBSWeakSource source1 = GetWeakSourceByQString(scene1Name);
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeSceneRoundTripSwitchName(scene1Name, scene2Name, transitionName, delay);
QVariant v = QVariant::fromValue(text);
int idx = SceneRoundTripFindByData(scene1Name);
if (idx == -1)
{
QListWidgetItem* item = new QListWidgetItem(text, ui->sceneRoundTrips);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->sceneRoundTripSwitches.emplace_back(
source1, source2, transition, int(delay * 1000), text.toUtf8().constData());
}
else
{
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->sceneRoundTripSwitches)
{
if (s.scene1 == source1)
{
s.scene2 = source2;
s.delay = int(delay * 1000);
s.transition = transition;
s.sceneRoundTripStr = text.toUtf8().constData();
break;
}
}
}
ui->sceneRoundTrips->sortItems();
}
}
void SceneSwitcher::on_sceneRoundTripRemove_clicked()
{
QListWidgetItem* item = ui->sceneRoundTrips->currentItem();
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->sceneRoundTripSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.sceneRoundTripStr == text)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_autoStopSceneCheckBox_stateChanged(int state)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
if (!state)
{
ui->autoStopScenes->setDisabled(true);
switcher->autoStopEnable = false;
}
else
{
ui->autoStopScenes->setDisabled(false);
switcher->autoStopEnable = true;
}
}
void SceneSwitcher::UpdateAutoStopScene(const QString& name)
{
obs_source_t* scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t* ws = obs_source_get_weak_source(scene);
switcher->autoStopScene = ws;
obs_weak_source_release(ws);
obs_source_release(scene);
}
void SceneSwitcher::on_autoStopScenes_currentTextChanged(const QString& text)
{
if (loading)
return;
lock_guard<mutex> lock(switcher->m);
UpdateAutoStopScene(text);
}
void SceneSwitcher::on_sceneRoundTripSave_clicked()
{
QString directory = QFileDialog::getSaveFileName(
this, tr("Save Scene Round Trip to file ..."), QDir::currentPath(), tr("Text files (*.txt)"));
if (!directory.isEmpty())
{
QFile file(directory);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches)
{
out << QString::fromStdString(GetWeakSourceName(s.scene1)) << "\n";
out << QString::fromStdString(GetWeakSourceName(s.scene2)) << "\n";
out << s.delay << "\n";
out << QString::fromStdString(s.sceneRoundTripStr) << "\n";
out << QString::fromStdString(GetWeakSourceName(s.transition)) << "\n";
}
}
}
void SceneSwitcher::on_sceneRoundTripLoad_clicked()
{
lock_guard<mutex> lock(switcher->m);
QString directory = QFileDialog::getOpenFileName(
this, tr("Select a file to read Scene Round Trip from ..."), QDir::currentPath(), tr("Text files (*.txt)"));
if (!directory.isEmpty())
{
QFile file(directory);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&file);
vector<QString> lines;
vector<SceneRoundTripSwitch> newSceneRoundTripSwitch;
while (!in.atEnd())
{
QString line = in.readLine();
lines.push_back(line);
if (lines.size() == 5)
{
OBSWeakSource scene1 = GetWeakSourceByQString(lines[0]);
OBSWeakSource scene2 = GetWeakSourceByQString(lines[1]);
OBSWeakSource transition = GetWeakTransitionByQString(lines[4]);
if (WeakSourceValid(scene1) && WeakSourceValid(scene2)
&& WeakSourceValid(transition))
{
newSceneRoundTripSwitch.emplace_back(SceneRoundTripSwitch(
GetWeakSourceByQString(lines[0]),
GetWeakSourceByQString(lines[1]),
GetWeakTransitionByQString(lines[4]),
lines[2].toInt(),
lines[3].toStdString()));
}
lines.clear();
}
}
if (lines.size() != 0 || newSceneRoundTripSwitch.size() == 0)
return;
switcher->sceneRoundTripSwitches.clear();
ui->sceneRoundTrips->clear();
switcher->sceneRoundTripSwitches = newSceneRoundTripSwitch;
for (SceneRoundTripSwitch s : switcher->sceneRoundTripSwitches)
{
QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(s.sceneRoundTripStr), ui->sceneRoundTrips);
item->setData(Qt::UserRole, QString::fromStdString(s.sceneRoundTripStr));
}
}
}
void SwitcherData::checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, unique_lock<mutex>& lock)
{
bool sceneRoundTripActive = false;
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
for (SceneRoundTripSwitch& s : sceneRoundTripSwitches)
{
if (s.scene1 == ws)
{
sceneRoundTripActive = true;
int dur = s.delay - interval;
if (dur > 0)
{
waitScene = currentSource;
cv.wait_for(lock, chrono::milliseconds(dur));
}
obs_source_t* currentSource2 = obs_frontend_get_current_scene();
// only switch if user hasn't changed scene manually
if (currentSource == currentSource2)
{
match = true;
scene = s.scene2;
transition = s.transition;
}
obs_source_release(currentSource2);
break;
}
}
obs_source_release(currentSource);
obs_weak_source_release(ws);
}
void SceneSwitcher::on_sceneRoundTrips_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->sceneRoundTrips->item(idx);
QString sceneRoundTrip = item->text();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->sceneRoundTripSwitches)
{
if (sceneRoundTrip.compare(s.sceneRoundTripStr.c_str()) == 0)
{
string scene1 = GetWeakSourceName(s.scene1);
string scene2 = GetWeakSourceName(s.scene2);
string transitionName = GetWeakSourceName(s.transition);
int delay = s.delay;
ui->sceneRoundTripScenes1->setCurrentText(scene1.c_str());
ui->sceneRoundTripScenes2->setCurrentText(scene2.c_str());
ui->sceneRoundTripTransitions->setCurrentText(transitionName.c_str());
ui->sceneRoundTripSpinBox->setValue((double)delay/1000);
break;
}
}
}
int SceneSwitcher::SceneRoundTripFindByData(const QString& scene1)
{
QRegExp rx(scene1 + " ->.*");
int count = ui->sceneRoundTrips->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->sceneRoundTrips->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString))
{
idx = i;
break;
}
}
return idx;
}
void SwitcherData::autoStopStreamAndRecording()
{
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
if (ws && autoStopScene == ws)
{
if (obs_frontend_streaming_active())
obs_frontend_streaming_stop();
if (obs_frontend_recording_active())
obs_frontend_recording_stop();
}
obs_source_release(currentSource);
obs_weak_source_release(ws);
}

View File

@ -1,283 +1,284 @@
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_transitionsAdd_clicked()
{
QString scene1Name = ui->transitionsScene1->currentText();
QString scene2Name = ui->transitionsScene2->currentText();
QString transitionName = ui->transitionsTransitions->currentText();
if (scene1Name.isEmpty() || scene2Name.isEmpty())
return;
if (scene1Name == scene2Name)
return;
OBSWeakSource source1 = GetWeakSourceByQString(scene1Name);
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeSceneTransitionName(scene1Name, scene2Name, transitionName);
QVariant v = QVariant::fromValue(text);
int idx = SceneTransitionsFindByData(scene1Name, scene2Name);
if (idx == -1)
{
QListWidgetItem* item = new QListWidgetItem(text, ui->sceneTransitions);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->sceneTransitions.emplace_back(
source1, source2, transition, text.toUtf8().constData());
}
else
{
QListWidgetItem* item = ui->sceneTransitions->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->sceneTransitions)
{
if (s.scene1 == source1 && s.scene2 == source2)
{
s.transition = transition;
s.sceneTransitionStr = text.toUtf8().constData();
break;
}
}
}
ui->sceneTransitions->sortItems();
}
}
void SceneSwitcher::on_transitionsRemove_clicked()
{
QListWidgetItem* item = ui->sceneTransitions->currentItem();
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->sceneTransitions;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.sceneTransitionStr == text)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_defaultTransitionsAdd_clicked()
{
QString sceneName = ui->defaultTransitionsScene->currentText();
QString transitionName = ui->defaultTransitionsTransitions->currentText();
if (sceneName.isEmpty() || transitionName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeDefaultSceneTransitionName(sceneName, transitionName);
QVariant v = QVariant::fromValue(text);
int idx = DefaultTransitionsFindByData(sceneName);
if (idx == -1)
{
QListWidgetItem* item = new QListWidgetItem(text, ui->defaultTransitions);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->defaultSceneTransitions.emplace_back(
source, transition, text.toUtf8().constData());
}
else
{
QListWidgetItem* item = ui->defaultTransitions->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->defaultSceneTransitions)
{
if (s.scene == source)
{
s.transition = transition;
s.sceneTransitionStr = text.toUtf8().constData();
break;
}
}
}
ui->defaultTransitions->sortItems();
}
}
void SceneSwitcher::on_defaultTransitionsRemove_clicked()
{
QListWidgetItem* item = ui->defaultTransitions->currentItem();
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->defaultSceneTransitions;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.sceneTransitionStr == text)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SwitcherData::setDefaultSceneTransitions(unique_lock<mutex>& lock)
{
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
for (DefaultSceneTransition& s : defaultSceneTransitions)
{
if (s.scene == ws)
{
obs_source_t* transition = obs_weak_source_get_source(s.transition);
//sleep planned but no fitting OBS event to measure transition time
obs_frontend_set_current_transition(transition);
obs_source_release(transition);
break;
}
}
obs_source_release(currentSource);
obs_weak_source_release(ws);
}
int SceneSwitcher::SceneTransitionsFindByData(const QString& scene1, const QString& scene2)
{
QRegExp rx(scene1 + " --- .* --> " + scene2);
int count = ui->sceneTransitions->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->sceneTransitions->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString))
{
idx = i;
break;
}
}
return idx;
}
int SceneSwitcher::DefaultTransitionsFindByData(const QString& scene)
{
QRegExp rx(scene + " --> .*");
int count = ui->defaultTransitions->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->defaultTransitions->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString))
{
idx = i;
break;
}
}
return idx;
}
void SceneSwitcher::on_sceneTransitions_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->sceneTransitions->item(idx);
QString sceneTransition = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->sceneTransitions)
{
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0)
{
string scene1 = GetWeakSourceName(s.scene1);
string scene2 = GetWeakSourceName(s.scene2);
string transitionName = GetWeakSourceName(s.transition);
ui->transitionsScene1->setCurrentText(scene1.c_str());
ui->transitionsScene2->setCurrentText(scene2.c_str());
ui->transitionsTransitions->setCurrentText(transitionName.c_str());
break;
}
}
}
void SceneSwitcher::on_defaultTransitions_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->defaultTransitions->item(idx);
QString sceneTransition = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->defaultSceneTransitions)
{
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0)
{
string scene = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition);
ui->defaultTransitionsScene->setCurrentText(scene.c_str());
ui->defaultTransitionsTransitions->setCurrentText(transitionName.c_str());
break;
}
}
}
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2)
{
obs_weak_source_t* ws = nullptr;
if (scene1 && scene2)
{
for (SceneTransition& t : switcher->sceneTransitions)
{
if (t.scene1 == scene1 && t.scene2 == scene2)
ws = t.transition;
}
obs_weak_source_addref(ws);
}
return ws;
}
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_transitionsAdd_clicked()
{
QString scene1Name = ui->transitionsScene1->currentText();
QString scene2Name = ui->transitionsScene2->currentText();
QString transitionName = ui->transitionsTransitions->currentText();
if (scene1Name.isEmpty() || scene2Name.isEmpty())
return;
if (scene1Name == scene2Name)
return;
OBSWeakSource source1 = GetWeakSourceByQString(scene1Name);
OBSWeakSource source2 = GetWeakSourceByQString(scene2Name);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeSceneTransitionName(scene1Name, scene2Name, transitionName);
QVariant v = QVariant::fromValue(text);
int idx = SceneTransitionsFindByData(scene1Name, scene2Name);
if (idx == -1)
{
QListWidgetItem* item = new QListWidgetItem(text, ui->sceneTransitions);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->sceneTransitions.emplace_back(
source1, source2, transition, text.toUtf8().constData());
}
else
{
QListWidgetItem* item = ui->sceneTransitions->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->sceneTransitions)
{
if (s.scene1 == source1 && s.scene2 == source2)
{
s.transition = transition;
s.sceneTransitionStr = text.toUtf8().constData();
break;
}
}
}
ui->sceneTransitions->sortItems();
}
}
void SceneSwitcher::on_transitionsRemove_clicked()
{
QListWidgetItem* item = ui->sceneTransitions->currentItem();
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->sceneTransitions;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.sceneTransitionStr == text)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_defaultTransitionsAdd_clicked()
{
QString sceneName = ui->defaultTransitionsScene->currentText();
QString transitionName = ui->defaultTransitionsTransitions->currentText();
if (sceneName.isEmpty() || transitionName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeDefaultSceneTransitionName(sceneName, transitionName);
QVariant v = QVariant::fromValue(text);
int idx = DefaultTransitionsFindByData(sceneName);
if (idx == -1)
{
QListWidgetItem* item = new QListWidgetItem(text, ui->defaultTransitions);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->defaultSceneTransitions.emplace_back(
source, transition, text.toUtf8().constData());
}
else
{
QListWidgetItem* item = ui->defaultTransitions->item(idx);
item->setText(text);
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->defaultSceneTransitions)
{
if (s.scene == source)
{
s.transition = transition;
s.sceneTransitionStr = text.toUtf8().constData();
break;
}
}
}
ui->defaultTransitions->sortItems();
}
}
void SceneSwitcher::on_defaultTransitionsRemove_clicked()
{
QListWidgetItem* item = ui->defaultTransitions->currentItem();
if (!item)
return;
string text = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->defaultSceneTransitions;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.sceneTransitionStr == text)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SwitcherData::setDefaultSceneTransitions(unique_lock<mutex>& lock)
{
obs_source_t* currentSource = obs_frontend_get_current_scene();
obs_weak_source_t* ws = obs_source_get_weak_source(currentSource);
for (DefaultSceneTransition& s : defaultSceneTransitions)
{
if (s.scene == ws)
{
obs_source_t* transition = obs_weak_source_get_source(s.transition);
//This might cancel the current transition
//There is no way to be sure when the previous transition finished
obs_frontend_set_current_transition(transition);
obs_source_release(transition);
break;
}
}
obs_source_release(currentSource);
obs_weak_source_release(ws);
}
int SceneSwitcher::SceneTransitionsFindByData(const QString& scene1, const QString& scene2)
{
QRegExp rx(scene1 + " --- .* --> " + scene2);
int count = ui->sceneTransitions->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->sceneTransitions->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString))
{
idx = i;
break;
}
}
return idx;
}
int SceneSwitcher::DefaultTransitionsFindByData(const QString& scene)
{
QRegExp rx(scene + " --> .*");
int count = ui->defaultTransitions->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->defaultTransitions->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (rx.exactMatch(itemString))
{
idx = i;
break;
}
}
return idx;
}
void SceneSwitcher::on_sceneTransitions_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->sceneTransitions->item(idx);
QString sceneTransition = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->sceneTransitions)
{
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0)
{
string scene1 = GetWeakSourceName(s.scene1);
string scene2 = GetWeakSourceName(s.scene2);
string transitionName = GetWeakSourceName(s.transition);
ui->transitionsScene1->setCurrentText(scene1.c_str());
ui->transitionsScene2->setCurrentText(scene2.c_str());
ui->transitionsTransitions->setCurrentText(transitionName.c_str());
break;
}
}
}
void SceneSwitcher::on_defaultTransitions_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->defaultTransitions->item(idx);
QString sceneTransition = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->defaultSceneTransitions)
{
if (sceneTransition.compare(s.sceneTransitionStr.c_str()) == 0)
{
string scene = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition);
ui->defaultTransitionsScene->setCurrentText(scene.c_str());
ui->defaultTransitionsTransitions->setCurrentText(transitionName.c_str());
break;
}
}
}
obs_weak_source_t* getNextTransition(obs_weak_source_t* scene1, obs_weak_source_t* scene2)
{
obs_weak_source_t* ws = nullptr;
if (scene1 && scene2)
{
for (SceneTransition& t : switcher->sceneTransitions)
{
if (t.scene1 == scene1 && t.scene2 == scene2)
ws = t.transition;
}
obs_weak_source_addref(ws);
}
return ws;
}

View File

@ -1,165 +1,165 @@
#include "advanced-scene-switcher.hpp"
void SwitcherData::checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
{
pair<int, int> cursorPos = getCursorPos();
int minRegionSize = 99999;
for (auto& s : screenRegionSwitches)
{
if (cursorPos.first >= s.minX && cursorPos.second >= s.minY
&& cursorPos.first <= s.maxX && cursorPos.second <= s.maxY)
{
int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY);
if (regionSize < minRegionSize)
{
match = true;
scene = s.scene;
transition = s.transition;
minRegionSize = regionSize;
}
}
}
}
void SceneSwitcher::updateScreenRegionCursorPos()
{
pair<int, int> position = getCursorPos();
ui->cursorXPosition->setText(QString::number(position.first));
;
ui->cursorYPosition->setText(QString::number(position.second));
}
void SceneSwitcher::on_screenRegionAdd_clicked()
{
QString sceneName = ui->screenRegionScenes->currentText();
QString transitionName = ui->screenRegionsTransitions->currentText();
if (sceneName.isEmpty())
return;
int minX = ui->screenRegionMinX->value();
int minY = ui->screenRegionMinY->value();
int maxX = ui->screenRegionMaxX->value();
int maxY = ui->screenRegionMaxY->value();
string regionStr = to_string(minX) + ", " + to_string(minY) + " x " + to_string(maxX) + ", "
+ to_string(maxY);
QString region = QString::fromStdString(regionStr);
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(region);
QString text = MakeScreenRegionSwitchName(sceneName, transitionName, minX, minY, maxX, maxY);
int idx = ScreenRegionFindByData(region);
if (idx == -1)
{
QListWidgetItem* item = new QListWidgetItem(text, ui->screenRegions);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->screenRegionSwitches.emplace_back(
source, transition, minX, minY, maxX, maxY, regionStr);
}
else
{
QListWidgetItem* item = ui->screenRegions->item(idx);
item->setText(text);
string curRegion = region.toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->screenRegionSwitches)
{
if (s.regionStr == curRegion)
{
s.scene = source;
s.transition = transition;
break;
}
}
}
ui->screenRegions->sortItems();
}
}
void SceneSwitcher::on_screenRegionRemove_clicked()
{
QListWidgetItem* item = ui->screenRegions->currentItem();
if (!item)
return;
string region = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->screenRegionSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.regionStr == region)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_screenRegions_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->screenRegions->item(idx);
QString region = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->screenRegionSwitches)
{
if (region.compare(s.regionStr.c_str()) == 0)
{
string name = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition);
ui->screenRegionScenes->setCurrentText(name.c_str());
ui->screenRegionsTransitions->setCurrentText(transitionName.c_str());
ui->screenRegionMinX->setValue(s.minX);
ui->screenRegionMinY->setValue(s.minY);
ui->screenRegionMaxX->setValue(s.maxX);
ui->screenRegionMaxY->setValue(s.maxY);
break;
}
}
}
int SceneSwitcher::ScreenRegionFindByData(const QString& region)
{
int count = ui->screenRegions->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->screenRegions->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == region)
{
idx = i;
break;
}
}
return idx;
}
#include "advanced-scene-switcher.hpp"
void SwitcherData::checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
{
pair<int, int> cursorPos = getCursorPos();
int minRegionSize = 99999;
for (auto& s : screenRegionSwitches)
{
if (cursorPos.first >= s.minX && cursorPos.second >= s.minY
&& cursorPos.first <= s.maxX && cursorPos.second <= s.maxY)
{
int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY);
if (regionSize < minRegionSize)
{
match = true;
scene = s.scene;
transition = s.transition;
minRegionSize = regionSize;
}
}
}
}
void SceneSwitcher::updateScreenRegionCursorPos()
{
pair<int, int> position = getCursorPos();
ui->cursorXPosition->setText(QString::number(position.first));
;
ui->cursorYPosition->setText(QString::number(position.second));
}
void SceneSwitcher::on_screenRegionAdd_clicked()
{
QString sceneName = ui->screenRegionScenes->currentText();
QString transitionName = ui->screenRegionsTransitions->currentText();
if (sceneName.isEmpty())
return;
int minX = ui->screenRegionMinX->value();
int minY = ui->screenRegionMinY->value();
int maxX = ui->screenRegionMaxX->value();
int maxY = ui->screenRegionMaxY->value();
string regionStr = to_string(minX) + ", " + to_string(minY) + " x " + to_string(maxX) + ", "
+ to_string(maxY);
QString region = QString::fromStdString(regionStr);
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(region);
QString text = MakeScreenRegionSwitchName(sceneName, transitionName, minX, minY, maxX, maxY);
int idx = ScreenRegionFindByData(region);
if (idx == -1)
{
QListWidgetItem* item = new QListWidgetItem(text, ui->screenRegions);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->screenRegionSwitches.emplace_back(
source, transition, minX, minY, maxX, maxY, regionStr);
}
else
{
QListWidgetItem* item = ui->screenRegions->item(idx);
item->setText(text);
string curRegion = region.toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->screenRegionSwitches)
{
if (s.regionStr == curRegion)
{
s.scene = source;
s.transition = transition;
break;
}
}
}
ui->screenRegions->sortItems();
}
}
void SceneSwitcher::on_screenRegionRemove_clicked()
{
QListWidgetItem* item = ui->screenRegions->currentItem();
if (!item)
return;
string region = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->screenRegionSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.regionStr == region)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_screenRegions_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->screenRegions->item(idx);
QString region = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->screenRegionSwitches)
{
if (region.compare(s.regionStr.c_str()) == 0)
{
string name = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition);
ui->screenRegionScenes->setCurrentText(name.c_str());
ui->screenRegionsTransitions->setCurrentText(transitionName.c_str());
ui->screenRegionMinX->setValue(s.minX);
ui->screenRegionMinY->setValue(s.minY);
ui->screenRegionMaxX->setValue(s.maxX);
ui->screenRegionMaxY->setValue(s.maxY);
break;
}
}
}
int SceneSwitcher::ScreenRegionFindByData(const QString& region)
{
int count = ui->screenRegions->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->screenRegions->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == region)
{
idx = i;
break;
}
}
return idx;
}

View File

@ -1,354 +1,372 @@
#pragma once
#include <condition_variable>
#include <chrono>
#include <string>
#include <vector>
#include <thread>
#include <regex>
#include <mutex>
#include <fstream>
#include <QDateTime>
#include "utility.hpp"
#define DEFAULT_INTERVAL 300
#define DEFAULT_IDLE_TIME 60
#define READ_FILE_FUNC 0
#define ROUND_TRIP_FUNC 1
#define IDLE_FUNC 2
#define EXE_FUNC 3
#define SCREEN_REGION_FUNC 4
#define WINDOW_TITLE_FUNC 5
#define DEFAULT_PRIORITY_0 READ_FILE_FUNC
#define DEFAULT_PRIORITY_1 ROUND_TRIP_FUNC
#define DEFAULT_PRIORITY_2 IDLE_FUNC
#define DEFAULT_PRIORITY_3 EXE_FUNC
#define DEFAULT_PRIORITY_4 SCREEN_REGION_FUNC
#define DEFAULT_PRIORITY_5 WINDOW_TITLE_FUNC
using namespace std;
struct SceneSwitch
{
OBSWeakSource scene;
string window;
OBSWeakSource transition;
bool fullscreen;
inline SceneSwitch(
OBSWeakSource scene_, const char* window_, OBSWeakSource transition_, bool fullscreen_)
: scene(scene_)
, window(window_)
, transition(transition_)
, fullscreen(fullscreen_)
{
}
};
struct ExecutableSceneSwitch
{
OBSWeakSource mScene;
OBSWeakSource mTransition;
QString mExe;
bool mInFocus;
inline ExecutableSceneSwitch(
OBSWeakSource scene, OBSWeakSource transition, const QString& exe, bool inFocus)
: mScene(scene)
, mTransition(transition)
, mExe(exe)
, mInFocus(inFocus)
{
}
};
struct ScreenRegionSwitch
{
OBSWeakSource scene;
OBSWeakSource transition;
int minX, minY, maxX, maxY;
string regionStr;
inline ScreenRegionSwitch(OBSWeakSource scene_, OBSWeakSource transition_, int minX_, int minY_,
int maxX_, int maxY_, string regionStr_)
: scene(scene_)
, transition(transition_)
, minX(minX_)
, minY(minY_)
, maxX(maxX_)
, maxY(maxY_)
, regionStr(regionStr_)
{
}
};
struct SceneRoundTripSwitch
{
OBSWeakSource scene1;
OBSWeakSource scene2;
OBSWeakSource transition;
int delay;
string sceneRoundTripStr;
inline SceneRoundTripSwitch(OBSWeakSource scene1_, OBSWeakSource scene2_,
OBSWeakSource transition_, int delay_, string str)
: scene1(scene1_)
, scene2(scene2_)
, transition(transition_)
, delay(delay_)
, sceneRoundTripStr(str)
{
}
};
struct RandomSwitch
{
OBSWeakSource scene;
OBSWeakSource transition;
double delay;
string randomSwitchStr;
inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_
, double delay_, string str)
: scene(scene_)
, transition(transition_)
, delay(delay_)
, randomSwitchStr(str)
{
}
};
struct SceneTransition
{
OBSWeakSource scene1;
OBSWeakSource scene2;
OBSWeakSource transition;
string sceneTransitionStr;
inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_, OBSWeakSource transition_,
string sceneTransitionStr_)
: scene1(scene1_)
, scene2(scene2_)
, transition(transition_)
, sceneTransitionStr(sceneTransitionStr_)
{
}
};
struct DefaultSceneTransition
{
OBSWeakSource scene;
OBSWeakSource transition;
string sceneTransitionStr;
inline DefaultSceneTransition(OBSWeakSource scene_, OBSWeakSource transition_,
string sceneTransitionStr_)
: scene(scene_)
, transition(transition_)
, sceneTransitionStr(sceneTransitionStr_)
{
}
};
struct FileSwitch
{
OBSWeakSource scene;
OBSWeakSource transition;
string file;
string text;
bool useRegex = false;
bool useTime = false;
QDateTime lastMod;
inline FileSwitch(
OBSWeakSource scene_, OBSWeakSource transition_, const char* file_, const char* text_, bool useRegex_, bool useTime_)
: scene(scene_)
, transition(transition_)
, file(file_)
, text(text_)
, useRegex(useRegex_)
, useTime(useTime_)
, lastMod()
{
}
};
struct FileIOData
{
bool readEnabled = false;
string readPath;
bool writeEnabled = false;
string writePath;
};
struct IdleData
{
bool idleEnable = false;
int time = DEFAULT_IDLE_TIME;
OBSWeakSource scene;
OBSWeakSource transition;
};
typedef enum {
NO_SWITCH = 0,
SWITCH = 1,
RANDOM_SWITCH = 2
} NoMatch;
struct SwitcherData
{
thread th;
condition_variable cv;
mutex m;
bool transitionActive = false;
bool waitForTransition = false;
condition_variable transitionCv;
bool stop = false;
vector<SceneSwitch> switches;
string lastTitle;
OBSWeakSource nonMatchingScene;
OBSWeakSource lastRandomScene;
int interval = DEFAULT_INTERVAL;
NoMatch switchIfNotMatching = NO_SWITCH;
bool startAtLaunch = false;
vector<ScreenRegionSwitch> screenRegionSwitches;
vector<OBSWeakSource> pauseScenesSwitches;
vector<string> pauseWindowsSwitches;
vector<string> ignoreWindowsSwitches;
vector<SceneRoundTripSwitch> sceneRoundTripSwitches;
vector<RandomSwitch> randomSwitches;
vector<FileSwitch> fileSwitches;
bool autoStopEnable = false;
OBSWeakSource autoStopScene;
string waitSceneName; //indicates which scene was active when we startet waiting on something
vector<SceneTransition> sceneTransitions;
vector<DefaultSceneTransition> defaultSceneTransitions;
vector<ExecutableSceneSwitch> executableSwitches;
FileIOData fileIO;
IdleData idleData;
vector<string> ignoreIdleWindows;
vector<int> functionNamesByPriority = vector<int>{
DEFAULT_PRIORITY_0,
DEFAULT_PRIORITY_1,
DEFAULT_PRIORITY_2,
DEFAULT_PRIORITY_3,
DEFAULT_PRIORITY_4,
DEFAULT_PRIORITY_5,
};
void Thread();
void Start();
void Stop();
bool sceneChangedDuringWait();
bool prioFuncsValid();
void writeSceneInfoToFile();
void setDefaultSceneTransitions(unique_lock<mutex>& lock);
void autoStopStreamAndRecording();
bool checkPause();
void checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, unique_lock<mutex>& lock);
void checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay);
void Prune()
{
for (size_t i = 0; i < switches.size(); i++)
{
SceneSwitch& s = switches[i];
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
switches.erase(switches.begin() + i--);
}
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene))
{
switchIfNotMatching = NO_SWITCH;
nonMatchingScene = nullptr;
}
for (size_t i = 0; i < randomSwitches.size(); i++)
{
RandomSwitch& s = randomSwitches[i];
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
randomSwitches.erase(randomSwitches.begin() + i--);
}
for (size_t i = 0; i < screenRegionSwitches.size(); i++)
{
ScreenRegionSwitch& s = screenRegionSwitches[i];
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
screenRegionSwitches.erase(screenRegionSwitches.begin() + i--);
}
for (size_t i = 0; i < pauseScenesSwitches.size(); i++)
{
OBSWeakSource& scene = pauseScenesSwitches[i];
if (!WeakSourceValid(scene))
pauseScenesSwitches.erase(pauseScenesSwitches.begin() + i--);
}
for (size_t i = 0; i < sceneRoundTripSwitches.size(); i++)
{
SceneRoundTripSwitch& s = sceneRoundTripSwitches[i];
if (!WeakSourceValid(s.scene1) || !WeakSourceValid(s.scene2)
|| !WeakSourceValid(s.transition))
sceneRoundTripSwitches.erase(sceneRoundTripSwitches.begin() + i--);
}
if (!WeakSourceValid(autoStopScene))
{
autoStopScene = nullptr;
autoStopEnable = false;
}
for (size_t i = 0; i < sceneTransitions.size(); i++)
{
SceneTransition& s = sceneTransitions[i];
if (!WeakSourceValid(s.scene1) || !WeakSourceValid(s.scene2)
|| !WeakSourceValid(s.transition))
sceneTransitions.erase(sceneTransitions.begin() + i--);
}
for (size_t i = 0; i < defaultSceneTransitions.size(); i++)
{
DefaultSceneTransition& s = defaultSceneTransitions[i];
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
defaultSceneTransitions.erase(defaultSceneTransitions.begin() + i--);
}
for (size_t i = 0; i < executableSwitches.size(); i++)
{
ExecutableSceneSwitch& s = executableSwitches[i];
if (!WeakSourceValid(s.mScene) || !WeakSourceValid(s.mTransition))
executableSwitches.erase(executableSwitches.begin() + i--);
}
for (size_t i = 0; i < fileSwitches.size(); i++)
{
FileSwitch& s = fileSwitches[i];
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
fileSwitches.erase(fileSwitches.begin() + i--);
}
if (!WeakSourceValid(idleData.scene) || !WeakSourceValid(idleData.transition))
{
idleData.idleEnable = false;
}
}
inline ~SwitcherData()
{
Stop();
}
};
#pragma once
#include <condition_variable>
#include <chrono>
#include <string>
#include <vector>
#include <thread>
#include <regex>
#include <mutex>
#include <fstream>
#include <QDateTime>
#include "utility.hpp"
#define DEFAULT_INTERVAL 300
#define DEFAULT_IDLE_TIME 60
#define READ_FILE_FUNC 0
#define ROUND_TRIP_FUNC 1
#define IDLE_FUNC 2
#define EXE_FUNC 3
#define SCREEN_REGION_FUNC 4
#define WINDOW_TITLE_FUNC 5
#define DEFAULT_PRIORITY_0 READ_FILE_FUNC
#define DEFAULT_PRIORITY_1 ROUND_TRIP_FUNC
#define DEFAULT_PRIORITY_2 IDLE_FUNC
#define DEFAULT_PRIORITY_3 EXE_FUNC
#define DEFAULT_PRIORITY_4 SCREEN_REGION_FUNC
#define DEFAULT_PRIORITY_5 WINDOW_TITLE_FUNC
using namespace std;
/********************************************************************************
* Data structs for each scene switching method
********************************************************************************/
struct WindowSceneSwitch
{
OBSWeakSource scene;
string window;
OBSWeakSource transition;
bool fullscreen;
inline WindowSceneSwitch(
OBSWeakSource scene_, const char* window_, OBSWeakSource transition_, bool fullscreen_)
: scene(scene_)
, window(window_)
, transition(transition_)
, fullscreen(fullscreen_)
{
}
};
struct ExecutableSceneSwitch
{
OBSWeakSource mScene;
OBSWeakSource mTransition;
QString mExe;
bool mInFocus;
inline ExecutableSceneSwitch(
OBSWeakSource scene, OBSWeakSource transition, const QString& exe, bool inFocus)
: mScene(scene)
, mTransition(transition)
, mExe(exe)
, mInFocus(inFocus)
{
}
};
struct ScreenRegionSwitch
{
OBSWeakSource scene;
OBSWeakSource transition;
int minX, minY, maxX, maxY;
string regionStr;
inline ScreenRegionSwitch(OBSWeakSource scene_, OBSWeakSource transition_, int minX_, int minY_,
int maxX_, int maxY_, string regionStr_)
: scene(scene_)
, transition(transition_)
, minX(minX_)
, minY(minY_)
, maxX(maxX_)
, maxY(maxY_)
, regionStr(regionStr_)
{
}
};
struct SceneRoundTripSwitch
{
OBSWeakSource scene1;
OBSWeakSource scene2;
OBSWeakSource transition;
int delay;
string sceneRoundTripStr;
inline SceneRoundTripSwitch(OBSWeakSource scene1_, OBSWeakSource scene2_,
OBSWeakSource transition_, int delay_, string str)
: scene1(scene1_)
, scene2(scene2_)
, transition(transition_)
, delay(delay_)
, sceneRoundTripStr(str)
{
}
};
struct RandomSwitch
{
OBSWeakSource scene;
OBSWeakSource transition;
double delay;
string randomSwitchStr;
inline RandomSwitch(OBSWeakSource scene_, OBSWeakSource transition_
, double delay_, string str)
: scene(scene_)
, transition(transition_)
, delay(delay_)
, randomSwitchStr(str)
{
}
};
struct SceneTransition
{
OBSWeakSource scene1;
OBSWeakSource scene2;
OBSWeakSource transition;
string sceneTransitionStr;
inline SceneTransition(OBSWeakSource scene1_, OBSWeakSource scene2_, OBSWeakSource transition_,
string sceneTransitionStr_)
: scene1(scene1_)
, scene2(scene2_)
, transition(transition_)
, sceneTransitionStr(sceneTransitionStr_)
{
}
};
struct DefaultSceneTransition
{
OBSWeakSource scene;
OBSWeakSource transition;
string sceneTransitionStr;
inline DefaultSceneTransition(OBSWeakSource scene_, OBSWeakSource transition_,
string sceneTransitionStr_)
: scene(scene_)
, transition(transition_)
, sceneTransitionStr(sceneTransitionStr_)
{
}
};
struct FileSwitch
{
OBSWeakSource scene;
OBSWeakSource transition;
string file;
string text;
bool useRegex = false;
bool useTime = false;
QDateTime lastMod;
inline FileSwitch(
OBSWeakSource scene_, OBSWeakSource transition_, const char* file_, const char* text_, bool useRegex_, bool useTime_)
: scene(scene_)
, transition(transition_)
, file(file_)
, text(text_)
, useRegex(useRegex_)
, useTime(useTime_)
, lastMod()
{
}
};
struct FileIOData
{
bool readEnabled = false;
string readPath;
bool writeEnabled = false;
string writePath;
};
struct IdleData
{
bool idleEnable = false;
int time = DEFAULT_IDLE_TIME;
OBSWeakSource scene;
OBSWeakSource transition;
};
typedef enum {
NO_SWITCH = 0,
SWITCH = 1,
RANDOM_SWITCH = 2
} NoMatch;
/********************************************************************************
* SwitcherData
********************************************************************************/
struct SwitcherData
{
thread th;
condition_variable cv;
mutex m;
bool transitionActive = false;
bool waitForTransition = false;
condition_variable transitionCv;
bool startAtLaunch = false;
bool stop = false;
obs_source_t* waitScene = NULL; //scene during which wait started
int interval = DEFAULT_INTERVAL;
OBSWeakSource nonMatchingScene;
OBSWeakSource lastRandomScene;
NoMatch switchIfNotMatching = NO_SWITCH;
vector<WindowSceneSwitch> windowSwitches;
vector<string> ignoreIdleWindows;
string lastTitle;
vector<ScreenRegionSwitch> screenRegionSwitches;
vector<OBSWeakSource> pauseScenesSwitches;
vector<string> pauseWindowsSwitches;
vector<string> ignoreWindowsSwitches;
vector<SceneRoundTripSwitch> sceneRoundTripSwitches;
vector<RandomSwitch> randomSwitches;
FileIOData fileIO;
IdleData idleData;
vector<FileSwitch> fileSwitches;
vector<ExecutableSceneSwitch> executableSwitches;
bool autoStopEnable = false;
OBSWeakSource autoStopScene;
vector<SceneTransition> sceneTransitions;
vector<DefaultSceneTransition> defaultSceneTransitions;
vector<int> functionNamesByPriority = vector<int>{
DEFAULT_PRIORITY_0,
DEFAULT_PRIORITY_1,
DEFAULT_PRIORITY_2,
DEFAULT_PRIORITY_3,
DEFAULT_PRIORITY_4,
DEFAULT_PRIORITY_5,
};
void Thread();
void Start();
void Stop();
bool sceneChangedDuringWait();
bool prioFuncsValid();
void writeSceneInfoToFile();
void setDefaultSceneTransitions(unique_lock<mutex>& lock);
void autoStopStreamAndRecording();
bool checkPause();
void checkSceneRoundTrip(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, unique_lock<mutex>& lock);
void checkIdleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkExeSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkScreenRegionSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkSwitchInfoFromFile(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkFileContent(bool& match, OBSWeakSource& scene, OBSWeakSource& transition);
void checkRandom(bool& match, OBSWeakSource& scene, OBSWeakSource& transition, int& delay);
void Prune()
{
for (size_t i = 0; i < windowSwitches.size(); i++)
{
WindowSceneSwitch& s = windowSwitches[i];
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
windowSwitches.erase(windowSwitches.begin() + i--);
}
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene))
{
switchIfNotMatching = NO_SWITCH;
nonMatchingScene = nullptr;
}
for (size_t i = 0; i < randomSwitches.size(); i++)
{
RandomSwitch& s = randomSwitches[i];
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
randomSwitches.erase(randomSwitches.begin() + i--);
}
for (size_t i = 0; i < screenRegionSwitches.size(); i++)
{
ScreenRegionSwitch& s = screenRegionSwitches[i];
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
screenRegionSwitches.erase(screenRegionSwitches.begin() + i--);
}
for (size_t i = 0; i < pauseScenesSwitches.size(); i++)
{
OBSWeakSource& scene = pauseScenesSwitches[i];
if (!WeakSourceValid(scene))
pauseScenesSwitches.erase(pauseScenesSwitches.begin() + i--);
}
for (size_t i = 0; i < sceneRoundTripSwitches.size(); i++)
{
SceneRoundTripSwitch& s = sceneRoundTripSwitches[i];
if (!WeakSourceValid(s.scene1) || !WeakSourceValid(s.scene2)
|| !WeakSourceValid(s.transition))
sceneRoundTripSwitches.erase(sceneRoundTripSwitches.begin() + i--);
}
if (!WeakSourceValid(autoStopScene))
{
autoStopScene = nullptr;
autoStopEnable = false;
}
for (size_t i = 0; i < sceneTransitions.size(); i++)
{
SceneTransition& s = sceneTransitions[i];
if (!WeakSourceValid(s.scene1) || !WeakSourceValid(s.scene2)
|| !WeakSourceValid(s.transition))
sceneTransitions.erase(sceneTransitions.begin() + i--);
}
for (size_t i = 0; i < defaultSceneTransitions.size(); i++)
{
DefaultSceneTransition& s = defaultSceneTransitions[i];
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
defaultSceneTransitions.erase(defaultSceneTransitions.begin() + i--);
}
for (size_t i = 0; i < executableSwitches.size(); i++)
{
ExecutableSceneSwitch& s = executableSwitches[i];
if (!WeakSourceValid(s.mScene) || !WeakSourceValid(s.mTransition))
executableSwitches.erase(executableSwitches.begin() + i--);
}
for (size_t i = 0; i < fileSwitches.size(); i++)
{
FileSwitch& s = fileSwitches[i];
if (!WeakSourceValid(s.scene) || !WeakSourceValid(s.transition))
fileSwitches.erase(fileSwitches.begin() + i--);
}
if (!WeakSourceValid(idleData.scene) || !WeakSourceValid(idleData.transition))
{
idleData.idleEnable = false;
}
}
inline ~SwitcherData()
{
Stop();
}
};

View File

@ -1,167 +1,166 @@
#pragma once
#include <obs.hpp>
#include <QString>
#include <obs-frontend-api.h>
#include "switcher-data-structs.hpp"
using namespace std;
static inline bool WeakSourceValid(obs_weak_source_t* ws)
{
obs_source_t* source = obs_weak_source_get_source(ws);
if (source)
obs_source_release(source);
return !!source;
}
static inline QString MakeSwitchName(
const QString& scene, const QString& value, const QString& transition, bool fullscreen)
{
if (!fullscreen)
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition
+ QStringLiteral("]: ") + value;
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
+ value + QStringLiteral(" (only if window is fullscreen)");
}
static inline QString MakeSwitchNameExecutable(
const QString& scene, const QString& value, const QString& transition, bool inFocus)
{
if (!inFocus)
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition
+ QStringLiteral("]: ") + value;
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
+ value + QStringLiteral(" (only if window is focused)");
}
static inline QString MakeScreenRegionSwitchName(
const QString& scene, const QString& transition, int minX, int minY, int maxX, int maxY)
{
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
+ QString::number(minX) + QStringLiteral(", ") + QString::number(minY)
+ QStringLiteral(" x ") + QString::number(maxX) + QStringLiteral(", ")
+ QString::number(maxY);
}
static inline QString MakeSceneRoundTripSwitchName(
const QString& scene1, const QString& scene2, const QString& transition, double delay)
{
return scene1 + QStringLiteral(" -> wait for ") + QString::number(delay)
+ QStringLiteral(" seconds -> ") + scene2 + QStringLiteral(" (using ") + transition
+ QStringLiteral(" transition)");
}
static inline QString MakeSceneTransitionName(
const QString& scene1, const QString& scene2, const QString& transition)
{
return scene1 + QStringLiteral(" --- ") + transition + QStringLiteral(" --> ") + scene2;
}
static inline QString MakeDefaultSceneTransitionName(
const QString& scene, const QString& transition)
{
return scene + QStringLiteral(" --> ") + transition;
}
static inline QString MakeRandomSwitchName(
const QString& scene, const QString& transition, double& delay)
{
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
+ QString::number(delay) + QStringLiteral(" seconds");
}
static inline QString MakeFileSwitchName(
const QString& scene, const QString& transition, const QString& fileName, const QString& text, bool useRegex, bool useTime)
{
QString switchName = QStringLiteral("Switch to ") + scene + QStringLiteral(" using ") + transition + QStringLiteral(" if ")
+ fileName;
if (useTime)
switchName += QStringLiteral(" was modified and");
switchName += QStringLiteral(" contains");
if (useRegex)
switchName += QStringLiteral(" (RegEx): \n\"");
else
switchName += QStringLiteral(": \n\"");
if (text.length() > 30)
switchName += text.left(27) + QStringLiteral("...\"");
else
switchName += text + QStringLiteral("\"");
return switchName;
}
static inline string GetWeakSourceName(obs_weak_source_t* weak_source)
{
string name;
obs_source_t* source = obs_weak_source_get_source(weak_source);
if (source)
{
name = obs_source_get_name(source);
obs_source_release(source);
}
return name;
}
static inline OBSWeakSource GetWeakSourceByName(const char* name)
{
OBSWeakSource weak;
obs_source_t* source = obs_get_source_by_name(name);
if (source)
{
weak = obs_source_get_weak_source(source);
obs_weak_source_release(weak);
obs_source_release(source);
}
return weak;
}
static inline OBSWeakSource GetWeakSourceByQString(const QString& name)
{
return GetWeakSourceByName(name.toUtf8().constData());
}
static inline OBSWeakSource GetWeakTransitionByName(const char* transitionName)
{
OBSWeakSource weak;
obs_source_t* source = nullptr;
if (strcmp(transitionName, "Default") == 0)
{
source = obs_frontend_get_current_transition();
weak = obs_source_get_weak_source(source);
obs_source_release(source);
obs_weak_source_release(weak);
return weak;
}
obs_frontend_source_list* transitions = new obs_frontend_source_list();
obs_frontend_get_transitions(transitions);
bool match = false;
for (size_t i = 0; i < transitions->sources.num; i++)
{
const char* name = obs_source_get_name(transitions->sources.array[i]);
if (strcmp(transitionName, name) == 0)
{
match = true;
source = transitions->sources.array[i];
break;
}
}
if (match){
weak = obs_source_get_weak_source(source);
obs_weak_source_release(weak);
}
obs_frontend_source_list_free(transitions);
return weak;
}
static inline OBSWeakSource GetWeakTransitionByQString(const QString& name)
{
return GetWeakTransitionByName(name.toUtf8().constData());
}
#pragma once
#include <obs.hpp>
#include <QString>
#include <obs-frontend-api.h>
#include "switcher-data-structs.hpp"
using namespace std;
static inline bool WeakSourceValid(obs_weak_source_t* ws)
{
obs_source_t* source = obs_weak_source_get_source(ws);
if (source)
obs_source_release(source);
return !!source;
}
static inline QString MakeSwitchName(
const QString& scene, const QString& value, const QString& transition, bool fullscreen)
{
if (!fullscreen)
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition
+ QStringLiteral("]: ") + value;
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
+ value + QStringLiteral(" (only if window is fullscreen)");
}
static inline QString MakeSwitchNameExecutable(
const QString& scene, const QString& value, const QString& transition, bool inFocus)
{
if (!inFocus)
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition
+ QStringLiteral("]: ") + value;
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
+ value + QStringLiteral(" (only if window is focused)");
}
static inline QString MakeScreenRegionSwitchName(
const QString& scene, const QString& transition, int minX, int minY, int maxX, int maxY)
{
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
+ QString::number(minX) + QStringLiteral(", ") + QString::number(minY)
+ QStringLiteral(" x ") + QString::number(maxX) + QStringLiteral(", ")
+ QString::number(maxY);
}
static inline QString MakeSceneRoundTripSwitchName(
const QString& scene1, const QString& scene2, const QString& transition, double delay)
{
return scene1 + QStringLiteral(" -> wait for ") + QString::number(delay)
+ QStringLiteral(" seconds -> ") + scene2 + QStringLiteral(" (using ") + transition
+ QStringLiteral(" transition)");
}
static inline QString MakeSceneTransitionName(
const QString& scene1, const QString& scene2, const QString& transition)
{
return scene1 + QStringLiteral(" --- ") + transition + QStringLiteral(" --> ") + scene2;
}
static inline QString MakeDefaultSceneTransitionName(
const QString& scene, const QString& transition)
{
return scene + QStringLiteral(" --> ") + transition;
}
static inline QString MakeRandomSwitchName(
const QString& scene, const QString& transition, double& delay)
{
return QStringLiteral("[") + scene + QStringLiteral(", ") + transition + QStringLiteral("]: ")
+ QString::number(delay) + QStringLiteral(" seconds");
}
static inline QString MakeFileSwitchName(
const QString& scene, const QString& transition, const QString& fileName, const QString& text, bool useRegex, bool useTime)
{
QString switchName = QStringLiteral("Switch to ") + scene + QStringLiteral(" using ") + transition + QStringLiteral(" if ")
+ fileName;
if (useTime)
switchName += QStringLiteral(" was modified and");
switchName += QStringLiteral(" contains");
if (useRegex)
switchName += QStringLiteral(" (RegEx): \n\"");
else
switchName += QStringLiteral(": \n\"");
if (text.length() > 30)
switchName += text.left(27) + QStringLiteral("...\"");
else
switchName += text + QStringLiteral("\"");
return switchName;
}
static inline string GetWeakSourceName(obs_weak_source_t* weak_source)
{
string name;
obs_source_t* source = obs_weak_source_get_source(weak_source);
if (source)
{
name = obs_source_get_name(source);
obs_source_release(source);
}
return name;
}
static inline OBSWeakSource GetWeakSourceByName(const char* name)
{
OBSWeakSource weak;
obs_source_t* source = obs_get_source_by_name(name);
if (source)
{
weak = obs_source_get_weak_source(source);
obs_weak_source_release(weak);
obs_source_release(source);
}
return weak;
}
static inline OBSWeakSource GetWeakSourceByQString(const QString& name)
{
return GetWeakSourceByName(name.toUtf8().constData());
}
static inline OBSWeakSource GetWeakTransitionByName(const char* transitionName)
{
OBSWeakSource weak;
obs_source_t* source = nullptr;
if (strcmp(transitionName, "Default") == 0)
{
source = obs_frontend_get_current_transition();
weak = obs_source_get_weak_source(source);
obs_source_release(source);
obs_weak_source_release(weak);
return weak;
}
obs_frontend_source_list* transitions = new obs_frontend_source_list();
obs_frontend_get_transitions(transitions);
bool match = false;
for (size_t i = 0; i < transitions->sources.num; i++)
{
const char* name = obs_source_get_name(transitions->sources.array[i]);
if (strcmp(transitionName, name) == 0)
{
match = true;
source = transitions->sources.array[i];
break;
}
}
if (match){
weak = obs_source_get_weak_source(source);
obs_weak_source_release(weak);
}
obs_frontend_source_list_free(transitions);
return weak;
}
static inline OBSWeakSource GetWeakTransitionByQString(const QString& name)
{
return GetWeakTransitionByName(name.toUtf8().constData());
}

View File

@ -1,283 +1,280 @@
#include <obs-module.h>
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_add_clicked()
{
QString sceneName = ui->scenes->currentText();
QString windowName = ui->windows->currentText();
QString transitionName = ui->transitions->currentText();
bool fullscreen = ui->fullscreenCheckBox->isChecked();
if (windowName.isEmpty() || sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(windowName);
QString text = MakeSwitchName(sceneName, windowName, transitionName, fullscreen);
int idx = FindByData(windowName);
if (idx == -1)
{
lock_guard<mutex> lock(switcher->m);
switcher->switches.emplace_back(
source, windowName.toUtf8().constData(), transition, fullscreen);
QListWidgetItem* item = new QListWidgetItem(text, ui->switches);
item->setData(Qt::UserRole, v);
}
else
{
QListWidgetItem* item = ui->switches->item(idx);
item->setText(text);
string window = windowName.toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->switches)
{
if (s.window == window)
{
s.scene = source;
s.transition = transition;
s.fullscreen = fullscreen;
break;
}
}
}
ui->switches->sortItems();
}
}
void SceneSwitcher::on_remove_clicked()
{
QListWidgetItem* item = ui->switches->currentItem();
if (!item)
return;
string window = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->switches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.window == window)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_ignoreWindowsAdd_clicked()
{
QString windowName = ui->ignoreWindowsWindows->currentText();
if (windowName.isEmpty())
return;
QVariant v = QVariant::fromValue(windowName);
QList<QListWidgetItem*> items = ui->ignoreWindows->findItems(windowName, Qt::MatchExactly);
if (items.size() == 0)
{
QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreWindows);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->ignoreWindowsSwitches.emplace_back(windowName.toUtf8().constData());
ui->ignoreWindows->sortItems();
}
}
void SceneSwitcher::on_ignoreWindowsRemove_clicked()
{
QListWidgetItem* item = ui->ignoreWindows->currentItem();
if (!item)
return;
QString windowName = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->ignoreWindowsSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s == windowName.toUtf8().constData())
{
switches.erase(it);
break;
}
}
}
delete item;
}
int SceneSwitcher::FindByData(const QString& window)
{
int count = ui->switches->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->switches->item(i);
QString itemWindow = item->data(Qt::UserRole).toString();
if (itemWindow == window)
{
idx = i;
break;
}
}
return idx;
}
int SceneSwitcher::IgnoreWindowsFindByData(const QString& window)
{
int count = ui->ignoreWindows->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->ignoreWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window)
{
idx = i;
break;
}
}
return idx;
}
void SceneSwitcher::on_switches_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->switches->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->switches)
{
if (window.compare(s.window.c_str()) == 0)
{
string name = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition);
ui->scenes->setCurrentText(name.c_str());
ui->windows->setCurrentText(window);
ui->transitions->setCurrentText(transitionName.c_str());
ui->fullscreenCheckBox->setChecked(s.fullscreen);
break;
}
}
}
void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->ignoreWindows->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->ignoreWindowsSwitches)
{
if (window.compare(s.c_str()) == 0)
{
ui->ignoreWindowsWindows->setCurrentText(s.c_str());
break;
}
}
}
void SwitcherData::checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
{
//check if title should be ignored
string title;
GetCurrentWindowTitle(title);
for (auto& window : ignoreWindowsSwitches)
{
try
{
bool matches = regex_match(title, regex(window));
if (matches)
{
title = lastTitle;
break;
}
}
catch (const regex_error&)
{
}
}
lastTitle = title;
//direct match
for (SceneSwitch& s : switches)
{
if (s.window == title)
{
match = !s.fullscreen || (s.fullscreen && isFullscreen());
scene = s.scene;
transition = s.transition;
return;
}
}
//regex match
for (SceneSwitch& s : switches)
{
try
{
bool matches = regex_match(title, regex(s.window));
if (matches)
{
match = !s.fullscreen || (s.fullscreen && isFullscreen());
scene = s.scene;
transition = s.transition;
}
}
catch (const regex_error&)
{
}
}
}
#include <obs-module.h>
#include "advanced-scene-switcher.hpp"
void SceneSwitcher::on_add_clicked()
{
QString sceneName = ui->scenes->currentText();
QString windowName = ui->windows->currentText();
QString transitionName = ui->transitions->currentText();
bool fullscreen = ui->fullscreenCheckBox->isChecked();
if (windowName.isEmpty() || sceneName.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QVariant v = QVariant::fromValue(windowName);
QString text = MakeSwitchName(sceneName, windowName, transitionName, fullscreen);
int idx = FindByData(windowName);
if (idx == -1)
{
lock_guard<mutex> lock(switcher->m);
switcher->windowSwitches.emplace_back(
source, windowName.toUtf8().constData(), transition, fullscreen);
QListWidgetItem* item = new QListWidgetItem(text, ui->switches);
item->setData(Qt::UserRole, v);
}
else
{
QListWidgetItem* item = ui->switches->item(idx);
item->setText(text);
string window = windowName.toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->windowSwitches)
{
if (s.window == window)
{
s.scene = source;
s.transition = transition;
s.fullscreen = fullscreen;
break;
}
}
}
ui->switches->sortItems();
}
}
void SceneSwitcher::on_remove_clicked()
{
QListWidgetItem* item = ui->switches->currentItem();
if (!item)
return;
string window = item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->windowSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s.window == window)
{
switches.erase(it);
break;
}
}
}
delete item;
}
void SceneSwitcher::on_ignoreWindowsAdd_clicked()
{
QString windowName = ui->ignoreWindowsWindows->currentText();
if (windowName.isEmpty())
return;
QVariant v = QVariant::fromValue(windowName);
QList<QListWidgetItem*> items = ui->ignoreWindows->findItems(windowName, Qt::MatchExactly);
if (items.size() == 0)
{
QListWidgetItem* item = new QListWidgetItem(windowName, ui->ignoreWindows);
item->setData(Qt::UserRole, v);
lock_guard<mutex> lock(switcher->m);
switcher->ignoreWindowsSwitches.emplace_back(windowName.toUtf8().constData());
ui->ignoreWindows->sortItems();
}
}
void SceneSwitcher::on_ignoreWindowsRemove_clicked()
{
QListWidgetItem* item = ui->ignoreWindows->currentItem();
if (!item)
return;
QString windowName = item->data(Qt::UserRole).toString();
{
lock_guard<mutex> lock(switcher->m);
auto& switches = switcher->ignoreWindowsSwitches;
for (auto it = switches.begin(); it != switches.end(); ++it)
{
auto& s = *it;
if (s == windowName.toUtf8().constData())
{
switches.erase(it);
break;
}
}
}
delete item;
}
int SceneSwitcher::FindByData(const QString& window)
{
int count = ui->switches->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->switches->item(i);
QString itemWindow = item->data(Qt::UserRole).toString();
if (itemWindow == window)
{
idx = i;
break;
}
}
return idx;
}
int SceneSwitcher::IgnoreWindowsFindByData(const QString& window)
{
int count = ui->ignoreWindows->count();
int idx = -1;
for (int i = 0; i < count; i++)
{
QListWidgetItem* item = ui->ignoreWindows->item(i);
QString itemRegion = item->data(Qt::UserRole).toString();
if (itemRegion == window)
{
idx = i;
break;
}
}
return idx;
}
void SceneSwitcher::on_switches_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->switches->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->windowSwitches)
{
if (window.compare(s.window.c_str()) == 0)
{
string name = GetWeakSourceName(s.scene);
string transitionName = GetWeakSourceName(s.transition);
ui->scenes->setCurrentText(name.c_str());
ui->windows->setCurrentText(window);
ui->transitions->setCurrentText(transitionName.c_str());
ui->fullscreenCheckBox->setChecked(s.fullscreen);
break;
}
}
}
void SceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
{
if (loading)
return;
if (idx == -1)
return;
QListWidgetItem* item = ui->ignoreWindows->item(idx);
QString window = item->data(Qt::UserRole).toString();
lock_guard<mutex> lock(switcher->m);
for (auto& s : switcher->ignoreWindowsSwitches)
{
if (window.compare(s.c_str()) == 0)
{
ui->ignoreWindowsWindows->setCurrentText(s.c_str());
break;
}
}
}
void SwitcherData::checkWindowTitleSwitch(bool& match, OBSWeakSource& scene, OBSWeakSource& transition)
{
//check if title should be ignored
string title;
GetCurrentWindowTitle(title);
for (auto& window : ignoreWindowsSwitches)
{
try
{
bool matches = regex_match(title, regex(window));
if (matches)
{
title = lastTitle;
break;
}
}
catch (const regex_error&)
{
}
}
lastTitle = title;
//direct match
for (WindowSceneSwitch& s : windowSwitches)
{
if (s.window == title)
{
match = !s.fullscreen || (s.fullscreen && isFullscreen());
scene = s.scene;
transition = s.transition;
return;
}
}
//regex match
for (WindowSceneSwitch& s : windowSwitches)
{
try
{
bool matches = regex_match(title, regex(s.window));
if (matches)
{
match = !s.fullscreen || (s.fullscreen && isFullscreen());
scene = s.scene;
transition = s.transition;
}
}
catch (const regex_error&)
{
}
}
}