316 lines
9.5 KiB
C++
316 lines
9.5 KiB
C++
/********************************************************************************
|
|
Copyright (C) 2013 Christophe Jeannin <chris.j84@free.fr>
|
|
Hugh Bailey <obs.jim@gmail.com>
|
|
Eric Bataille <e.c.p.bataille@gmail.com>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
********************************************************************************/
|
|
|
|
#include "scenesw.h"
|
|
|
|
SceneSwitcher::SceneSwitcher(HINSTANCE hinstMain, OBSHOTKEYPROC ToggleHotkeyProc)
|
|
{
|
|
hinstDll = hinstMain;
|
|
|
|
// The localization part
|
|
pluginLocale = new LocaleStringLookup;
|
|
|
|
if(!pluginLocale->LoadStringFile(TEXT("plugins/scenesw/locale/en.txt")))
|
|
AppWarning(TEXT("Could not open locale string file '%s'"), TEXT("plugins/scenesw/locale/en.txt"));
|
|
|
|
if(scmpi(API->GetLanguage(), TEXT("en")) != 0)
|
|
{
|
|
String pluginStringFile;
|
|
pluginStringFile << TEXT("plugins/scenesw/locale/") << API->GetLanguage() << TEXT(".txt");
|
|
if(!pluginLocale->LoadStringFile(pluginStringFile))
|
|
AppWarning(TEXT("Could not open locale string file '%s'"), pluginStringFile.Array());
|
|
}
|
|
|
|
timeToSleep = TTS_DEFAULT;
|
|
thread = 0;
|
|
timer = 0;
|
|
bKillThread = true;
|
|
mainSceneName.Clear();
|
|
altSceneName.Clear();
|
|
mainWndName.Clear();
|
|
altDoSwitch = 1;
|
|
|
|
// Start with an empty list of window-scene assignments
|
|
nWindowsDefined = 0;
|
|
scenes.Clear();
|
|
windows.Clear();
|
|
|
|
config.Open(OBSGetPluginDataPath() + CONFIGFILENAME, true);
|
|
ReadSettings();
|
|
|
|
stopReq = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
if(startAuto)
|
|
{
|
|
StartThread();
|
|
}
|
|
|
|
settings = new SceneSwitcherSettings(this, ToggleHotkeyProc);
|
|
OBSAddSettingsPane(settings);
|
|
}
|
|
|
|
SceneSwitcher::~SceneSwitcher()
|
|
{
|
|
OBSRemoveSettingsPane(settings);
|
|
delete settings;
|
|
|
|
delete pluginLocale;
|
|
|
|
StopThread();
|
|
config.Close();
|
|
CloseHandle(stopReq);
|
|
}
|
|
|
|
|
|
void SceneSwitcher::ReadSettings()
|
|
{
|
|
mainWndName = config.GetString(TEXT("General"), TEXT("MainWindow"));
|
|
mainSceneName = config.GetString(TEXT("General"), TEXT("MainScene"));
|
|
altSceneName = config.GetString(TEXT("General"), TEXT("AltScene"));
|
|
startAuto = config.GetInt(TEXT("General"), TEXT("StartAuto"));
|
|
timeToSleep = (DWORD)config.GetInt(TEXT("General"), TEXT("CheckFrequency"));
|
|
nWindowsDefined = config.GetInt(TEXT("GENERAL"), TEXT("nWindows"));
|
|
altDoSwitch = config.GetInt(TEXT("GENERAL"), TEXT("AltDoSwitch"));
|
|
toggleHotkey = (DWORD)config.GetInt(TEXT("GENERAL"), TEXT("ToggleHotkey"));
|
|
scenes.Clear();
|
|
windows.Clear();
|
|
config.GetStringList(TEXT("SceneDef"), TEXT("window"), windows);
|
|
config.GetStringList(TEXT("SceneDef"), TEXT("scene"), scenes);
|
|
if ((int)windows.Num() < nWindowsDefined) nWindowsDefined = windows.Num();
|
|
if ((int)scenes.Num() < nWindowsDefined) nWindowsDefined = scenes.Num();
|
|
|
|
if(!timeToSleep)
|
|
timeToSleep = TTS_DEFAULT;
|
|
else
|
|
TTS_CLAMP(timeToSleep);
|
|
}
|
|
|
|
|
|
void SceneSwitcher::WriteSettings()
|
|
{
|
|
config.SetString(TEXT("General"), TEXT("MainWindow"), mainWndName);
|
|
config.SetString(TEXT("General"), TEXT("MainScene"), mainSceneName);
|
|
config.SetString(TEXT("General"), TEXT("AltScene"), altSceneName);
|
|
config.SetInt(TEXT("General"), TEXT("StartAuto"), startAuto);
|
|
config.SetInt(TEXT("General"), TEXT("CheckFrequency"), timeToSleep);
|
|
config.SetInt(TEXT("General"), TEXT("nWindows"), nWindowsDefined);
|
|
config.SetInt(TEXT("General"), TEXT("AltDoSwitch"), altDoSwitch);
|
|
config.SetInt(TEXT("General"), TEXT("ToggleHotkey"), toggleHotkey);
|
|
config.SetStringList(TEXT("SceneDef"), TEXT("window"), windows);
|
|
config.SetStringList(TEXT("SceneDef"), TEXT("scene"), scenes);
|
|
}
|
|
|
|
|
|
|
|
DWORD SceneSwitcher::Run()
|
|
{
|
|
LARGE_INTEGER dueTime;
|
|
|
|
if((timer = CreateWaitableTimer(NULL, FALSE, NULL)) == NULL)
|
|
return -1;
|
|
dueTime.QuadPart=0;
|
|
SetWaitableTimer(timer, &dueTime, timeToSleep, NULL, NULL, FALSE);
|
|
HANDLE handles[] = { timer, stopReq };
|
|
|
|
String currentWindowText;
|
|
while(!bKillThread)
|
|
{
|
|
HWND hwndCurrent = GetForegroundWindow();
|
|
DWORD_PTR textLength;
|
|
if (!SendMessageTimeout(hwndCurrent, WM_GETTEXTLENGTH, 0, 0, SMTO_ABORTIFHUNG, 1000, &textLength))
|
|
continue;
|
|
currentWindowText.SetLength((UINT)textLength);
|
|
//GetWindowText(hwndCurrent, currentWindowText, currentWindowText.Length() + 1);
|
|
if (!SendMessageTimeout(hwndCurrent, WM_GETTEXT, currentWindowText.Length() + 1, (LPARAM)currentWindowText.Array(), SMTO_ABORTIFHUNG, 1000, NULL))
|
|
continue;
|
|
|
|
String currentScene = OBSGetSceneName();
|
|
String sceneToSwitch;
|
|
|
|
// See if we get matches
|
|
bool found = false;
|
|
for (int i = 0; i < nWindowsDefined; i++)
|
|
{
|
|
String toCheck = GetWindow(i);
|
|
BOOL match = currentWindowText == toCheck;
|
|
|
|
if (!toCheck.IsEmpty())
|
|
{
|
|
// Check for wildcards.
|
|
BOOL matchStart = toCheck.Left(1) != "*";
|
|
BOOL matchEnd = toCheck.Right(1) != "*";
|
|
|
|
// Remove the wildcards.
|
|
if (!matchStart)
|
|
toCheck = toCheck.Right(toCheck.Length() - 1);
|
|
// Single character % toCheck is handled by this.
|
|
if (!matchEnd && !toCheck.IsEmpty())
|
|
toCheck = toCheck.Left(toCheck.Length() - 1);
|
|
|
|
if (!matchStart &&
|
|
!toCheck.IsEmpty() &&
|
|
currentWindowText.Length() >= toCheck.Length() &&
|
|
currentWindowText.Right(toCheck.Length()) == toCheck)
|
|
match = TRUE;
|
|
|
|
if (!matchEnd &&
|
|
!toCheck.IsEmpty() &&
|
|
currentWindowText.Length() >= toCheck.Length() &&
|
|
currentWindowText.Left(toCheck.Length()) == toCheck)
|
|
match = TRUE;
|
|
|
|
// Empty string does not match anything, even if one or more wildcards are used.
|
|
if (!matchStart && !matchEnd && !toCheck.IsEmpty() &&
|
|
sstr(currentWindowText.Array(), toCheck.Array()))
|
|
match = TRUE;
|
|
}
|
|
|
|
if (match)
|
|
{
|
|
sceneToSwitch = GetScene(i);
|
|
found = true;
|
|
break; // take the first one
|
|
}
|
|
}
|
|
if (!found) // Otherwise, take the alternate scene
|
|
sceneToSwitch = altSceneName;
|
|
|
|
// Make the switch if it isn't already selected
|
|
if (sceneToSwitch != currentScene && (found || altDoSwitch != 0))
|
|
OBSSetScene(sceneToSwitch, true);
|
|
|
|
WaitForMultipleObjects(2, handles, FALSE, INFINITE);
|
|
}
|
|
|
|
CloseHandle(timer);
|
|
return 0;
|
|
}
|
|
|
|
|
|
void SceneSwitcher::StartThread(HWND hDialog)
|
|
{
|
|
if(!thread)
|
|
{
|
|
bKillThread = false;
|
|
thread = CreateThread(NULL, 0, ThreadProc, (LPVOID)this, 0, NULL);
|
|
|
|
if(hDialog && thread)
|
|
{
|
|
SetWindowText(GetDlgItem(hDialog, IDC_RUN), pluginLocale->LookupString(TEXT("Settings.Running")));
|
|
SetWindowText(GetDlgItem(hDialog, IDC_STOP), pluginLocale->LookupString(TEXT("Settings.Stop")));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SceneSwitcher::StopThread(HWND hDialog)
|
|
{
|
|
if(thread)
|
|
{
|
|
bKillThread = true;
|
|
|
|
SetEvent(stopReq);
|
|
WaitForSingleObject(thread, INFINITE);
|
|
ResetEvent(stopReq);
|
|
|
|
if(thread)
|
|
{
|
|
CloseHandle(thread);
|
|
thread = 0;
|
|
}
|
|
}
|
|
|
|
if(hDialog)
|
|
{
|
|
SetWindowText(GetDlgItem(hDialog, IDC_RUN), pluginLocale->LookupString(TEXT("Settings.NotRunning")));
|
|
SetWindowText(GetDlgItem(hDialog, IDC_STOP), pluginLocale->LookupString(TEXT("Settings.Start")));
|
|
}
|
|
}
|
|
|
|
|
|
void SceneSwitcher::ApplyConfig(HWND hDialog)
|
|
{
|
|
if(!hDialog) // Noes.. Dialog don't exist?
|
|
return;
|
|
|
|
// Get the listbox control handles
|
|
HWND hwndMainScn = GetDlgItem(hDialog, IDC_MAINSCN);
|
|
HWND hwndAltScn = GetDlgItem(hDialog, IDC_ALTSCN);
|
|
HWND hwndAppList = GetDlgItem(hDialog, IDC_APPLIST);
|
|
HWND hwndWSMap = GetDlgItem(hDialog, IDC_WSMAP);
|
|
HWND hwndHotkey = GetDlgItem(hDialog, IDC_TOGGLEHOTKEY);
|
|
|
|
// Get the options names from the controls
|
|
String newMainSceneName = GetCBText(hwndMainScn, CB_ERR);
|
|
String newAltSceneName = GetCBText(hwndAltScn, CB_ERR);
|
|
String newMainWndName = GetCBText(hwndAppList, CB_ERR);
|
|
|
|
// Get the new frequency from the frequency control
|
|
DWORD newTimeToSleep = GetDlgItemInt(hDialog, IDC_FREQ, NULL, FALSE);
|
|
TTS_CLAMP(newTimeToSleep);
|
|
|
|
// Get the toggle hotkey if any
|
|
toggleHotkey = (DWORD)SendMessage(hwndHotkey, HKM_GETHOTKEY, 0, 0);
|
|
|
|
// Get the checkboxes state
|
|
altDoSwitch = IsDlgButtonChecked(hDialog, IDC_ALTSWITCH);
|
|
startAuto = IsDlgButtonChecked(hDialog, IDC_STARTAUTO);
|
|
|
|
if(newAltSceneName.IsEmpty() && IsAltDoSwitch())
|
|
StopThread(hDialog); // if we're applying a bad config stop thread first
|
|
|
|
if((timeToSleep != newTimeToSleep) && thread && timer)
|
|
{ // reset timer with new value
|
|
LARGE_INTEGER dueTime;
|
|
dueTime.QuadPart=0;
|
|
SetWaitableTimer(timer, &dueTime, newTimeToSleep, NULL, NULL, FALSE);
|
|
}
|
|
|
|
|
|
nWindowsDefined = SendMessage(hwndWSMap, LVM_GETITEMCOUNT, 0, 0);
|
|
scenes.Clear();
|
|
windows.Clear();
|
|
for (int i = 0; i < nWindowsDefined; i++)
|
|
{
|
|
// Get the window name
|
|
String wnd;
|
|
wnd.SetLength(256);
|
|
ListView_GetItemText(hwndWSMap, i, 0, wnd, 256);
|
|
wnd = String(wnd.Array());
|
|
windows.Add(wnd);
|
|
|
|
// Get the scene name
|
|
String scn;
|
|
scn.SetLength(256);
|
|
ListView_GetItemText(hwndWSMap, i, 1, scn, 256);
|
|
scn = String(scn.Array());
|
|
scenes.Add(scn);
|
|
}
|
|
|
|
// Set the new global values
|
|
timeToSleep = newTimeToSleep;
|
|
mainSceneName = newMainSceneName;
|
|
altSceneName = newAltSceneName;
|
|
mainWndName = newMainWndName;
|
|
|
|
WriteSettings(); // Write the settings to config
|
|
}
|
|
|