mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-09-07 09:05:57 -05:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df358de5fb | ||
|
|
6d7e23c88f | ||
|
|
9fff05c57c | ||
|
|
6da151f7d7 | ||
|
|
61ee58ba70 | ||
|
|
312fe1d648 | ||
|
|
5d3c83c292 | ||
|
|
964b6c6c71 | ||
|
|
27116c0cd3 | ||
|
|
06c29bced5 | ||
|
|
4f3d9e3a00 | ||
|
|
c02896ea17 | ||
|
|
4bfd40219b | ||
|
|
6a3de18069 | ||
|
|
8c51b44fbb | ||
|
|
10daa38921 | ||
|
|
6e0f7ab38f | ||
|
|
86061b3cf1 | ||
|
|
c3669cae3e | ||
|
|
a116360f87 | ||
|
|
713f695aa4 | ||
|
|
dec5c2d763 | ||
|
|
f090dea136 | ||
|
|
d00986df03 | ||
|
|
03e5397b7e | ||
|
|
94d49db196 | ||
|
|
1483f9d9dc | ||
|
|
99629e8c66 | ||
|
|
ba38b8bf27 | ||
|
|
38513735dd |
4
.github/scripts/.build.zsh
vendored
4
.github/scripts/.build.zsh
vendored
@@ -255,6 +255,10 @@ ${_usage_host:-}"
|
|||||||
|
|
||||||
cmake_args+=(
|
cmake_args+=(
|
||||||
-DCMAKE_PREFIX_PATH="${advss_deps_path}"
|
-DCMAKE_PREFIX_PATH="${advss_deps_path}"
|
||||||
|
-DOPENSSL_ROOT_DIR="${advss_deps_path}"
|
||||||
|
-DOPENSSL_INCLUDE_DIR="${advss_deps_path}/include"
|
||||||
|
-DOPENSSL_CRYPTO_LIBRARY="${advss_deps_path}/lib/libcrypto.a"
|
||||||
|
-DOPENSSL_SSL_LIBRARY="${advss_deps_path}/lib/libssl.a"
|
||||||
--preset ${_preset}
|
--preset ${_preset}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
3
.github/scripts/utils.zsh/check_macos
vendored
3
.github/scripts/utils.zsh/check_macos
vendored
@@ -18,7 +18,4 @@ if (( ! ${+commands[brew]} )) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
brew bundle --file ${SCRIPT_HOME}/.Brewfile
|
brew bundle --file ${SCRIPT_HOME}/.Brewfile
|
||||||
# Workaround to make sure locally built openssl is picked up by cmake
|
|
||||||
brew uninstall --ignore-dependencies openssl@3 || true
|
|
||||||
rehash || true
|
|
||||||
log_group
|
log_group
|
||||||
|
|||||||
2
.github/workflows/build-project.yaml
vendored
2
.github/workflows/build-project.yaml
vendored
@@ -6,7 +6,7 @@ on:
|
|||||||
description: "Project name detected by parsing build spec file"
|
description: "Project name detected by parsing build spec file"
|
||||||
value: ${{ jobs.check-event.outputs.pluginName }}
|
value: ${{ jobs.check-event.outputs.pluginName }}
|
||||||
env:
|
env:
|
||||||
DEP_DIR: .deps/advss-build-dependencies-3
|
DEP_DIR: .deps/advss-build-dependencies-4
|
||||||
jobs:
|
jobs:
|
||||||
check-event:
|
check-event:
|
||||||
name: Check GitHub Event Data 🔎
|
name: Check GitHub Event Data 🔎
|
||||||
|
|||||||
@@ -504,7 +504,11 @@ endif()
|
|||||||
# --- End of section ---
|
# --- End of section ---
|
||||||
|
|
||||||
add_subdirectory(plugins)
|
add_subdirectory(plugins)
|
||||||
add_subdirectory(tests)
|
|
||||||
|
option(ADVSS_ENABLE_TESTS "Build advanced-scene-switcher unit tests" OFF)
|
||||||
|
if(ADVSS_ENABLE_TESTS)
|
||||||
|
add_subdirectory(tests)
|
||||||
|
endif()
|
||||||
|
|
||||||
# --- Install ---
|
# --- Install ---
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,8 @@
|
|||||||
"description": "Build for macOS 11.0+ (Universal binary) for CI",
|
"description": "Build for macOS 11.0+ (Universal binary) for CI",
|
||||||
"generator": "Xcode",
|
"generator": "Xcode",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true
|
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||||
|
"ADVSS_ENABLE_TESTS": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -69,7 +70,8 @@
|
|||||||
"displayName": "Windows x64 CI build",
|
"displayName": "Windows x64 CI build",
|
||||||
"description": "Build for Windows x64 on CI",
|
"description": "Build for Windows x64 on CI",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true
|
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||||
|
"ADVSS_ENABLE_TESTS": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -97,7 +99,8 @@
|
|||||||
"description": "Build for Linux x86_64 on CI",
|
"description": "Build for Linux x86_64 on CI",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true
|
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||||
|
"ADVSS_ENABLE_TESTS": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -125,7 +128,8 @@
|
|||||||
"description": "Build for Linux aarch64 on CI",
|
"description": "Build for Linux aarch64 on CI",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true
|
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||||
|
"ADVSS_ENABLE_TESTS": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -99,7 +99,6 @@ AdvSceneSwitcher.macroList.deleted="gelöscht"
|
|||||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" ist bereits ausgewählt!"
|
AdvSceneSwitcher.macroList.duplicate="\"%1\" ist bereits ausgewählt!"
|
||||||
|
|
||||||
; Macro Logic
|
; Macro Logic
|
||||||
AdvSceneSwitcher.logic.none="Eintrag ignorieren"
|
|
||||||
AdvSceneSwitcher.logic.and="Und"
|
AdvSceneSwitcher.logic.and="Und"
|
||||||
AdvSceneSwitcher.logic.or="Oder"
|
AdvSceneSwitcher.logic.or="Oder"
|
||||||
AdvSceneSwitcher.logic.andNot="Und nicht"
|
AdvSceneSwitcher.logic.andNot="Und nicht"
|
||||||
@@ -211,8 +210,8 @@ AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
|
|||||||
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
|
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="Aufnahme gestoppt"
|
AdvSceneSwitcher.condition.record.state.stop="Aufnahme gestoppt"
|
||||||
AdvSceneSwitcher.condition.process="Prozess"
|
AdvSceneSwitcher.condition.process="Prozess"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}läuft{{focused}}und ist fokusiert"
|
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}läuft{{focused}}und ist fokusiert"
|
||||||
AdvSceneSwitcher.condition.process.entry.focus="Aktueller Vordergrundprozess: {{focusProcess}}"
|
AdvSceneSwitcher.condition.process.layout.focus="Aktueller Vordergrundprozess: {{focusProcess}}"
|
||||||
AdvSceneSwitcher.condition.idle="Leerlauf"
|
AdvSceneSwitcher.condition.idle="Leerlauf"
|
||||||
AdvSceneSwitcher.condition.idle.entry="Keine Tastatur- oder Mauseingaben für {{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="Keine Tastatur- oder Mauseingaben für {{duration}}"
|
||||||
AdvSceneSwitcher.condition.pluginState="Plugin-Status"
|
AdvSceneSwitcher.condition.pluginState="Plugin-Status"
|
||||||
@@ -416,7 +415,6 @@ AdvSceneSwitcher.action.replay.type.save="Replay Buffer speichern"
|
|||||||
AdvSceneSwitcher.action.streaming="Stream"
|
AdvSceneSwitcher.action.streaming="Stream"
|
||||||
AdvSceneSwitcher.action.streaming.type.stop="Stream stoppen"
|
AdvSceneSwitcher.action.streaming.type.stop="Stream stoppen"
|
||||||
AdvSceneSwitcher.action.streaming.type.start="Stream starten"
|
AdvSceneSwitcher.action.streaming.type.start="Stream starten"
|
||||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
|
||||||
AdvSceneSwitcher.action.run="Ausführen"
|
AdvSceneSwitcher.action.run="Ausführen"
|
||||||
AdvSceneSwitcher.action.sceneVisibility="Sichtbarkeit von Szenenelementen"
|
AdvSceneSwitcher.action.sceneVisibility="Sichtbarkeit von Szenenelementen"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Anzeigen"
|
AdvSceneSwitcher.action.sceneVisibility.type.show="Anzeigen"
|
||||||
@@ -452,7 +450,7 @@ AdvSceneSwitcher.action.macro="Makro"
|
|||||||
AdvSceneSwitcher.action.macro.type.pause="Pausieren"
|
AdvSceneSwitcher.action.macro.type.pause="Pausieren"
|
||||||
AdvSceneSwitcher.action.macro.type.unpause="Nicht mehr pausieren"
|
AdvSceneSwitcher.action.macro.type.unpause="Nicht mehr pausieren"
|
||||||
AdvSceneSwitcher.action.macro.type.resetCounter="Zähler zurücksetzen"
|
AdvSceneSwitcher.action.macro.type.resetCounter="Zähler zurücksetzen"
|
||||||
AdvSceneSwitcher.action.macro.type.run="Aktionen ausführen"
|
AdvSceneSwitcher.action.macro.type.runActions="Aktionen ausführen"
|
||||||
AdvSceneSwitcher.action.macro.type.stop="Aktionen stoppen"
|
AdvSceneSwitcher.action.macro.type.stop="Aktionen stoppen"
|
||||||
AdvSceneSwitcher.action.pluginState="Plugin-Status"
|
AdvSceneSwitcher.action.pluginState="Plugin-Status"
|
||||||
AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenwechsler stoppen"
|
AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenwechsler stoppen"
|
||||||
|
|||||||
@@ -306,7 +306,6 @@ AdvSceneSwitcher.macroList.deleted="deleted"
|
|||||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" is alreay selected!"
|
AdvSceneSwitcher.macroList.duplicate="\"%1\" is alreay selected!"
|
||||||
|
|
||||||
# Macro Logic
|
# Macro Logic
|
||||||
AdvSceneSwitcher.logic.none="Ignore entry"
|
|
||||||
AdvSceneSwitcher.logic.and="And"
|
AdvSceneSwitcher.logic.and="And"
|
||||||
AdvSceneSwitcher.logic.or="Or"
|
AdvSceneSwitcher.logic.or="Or"
|
||||||
AdvSceneSwitcher.logic.andNot="And not"
|
AdvSceneSwitcher.logic.andNot="And not"
|
||||||
@@ -484,8 +483,9 @@ AdvSceneSwitcher.condition.record.state.stop="Recording stopped"
|
|||||||
AdvSceneSwitcher.condition.record.state.duration="Recording duration is longer than"
|
AdvSceneSwitcher.condition.record.state.duration="Recording duration is longer than"
|
||||||
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
||||||
AdvSceneSwitcher.condition.process="Process"
|
AdvSceneSwitcher.condition.process="Process"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}is running{{focused}}and is focused"
|
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}is running{{focused}}and is focused"
|
||||||
AdvSceneSwitcher.condition.process.entry.focus="Current foreground process:{{focusProcess}}"
|
AdvSceneSwitcher.condition.process.layout.focus="Current foreground process:{{focusProcess}}"
|
||||||
|
AdvSceneSwitcher.condition.process.layout.path="{{checkPath}}Match binary path:{{path}}{{pathRegex}}"
|
||||||
AdvSceneSwitcher.condition.idle="Idle"
|
AdvSceneSwitcher.condition.idle="Idle"
|
||||||
AdvSceneSwitcher.condition.idle.entry="No keyboard or mouse inputs for{{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="No keyboard or mouse inputs for{{duration}}"
|
||||||
AdvSceneSwitcher.condition.pluginState="Plugin state"
|
AdvSceneSwitcher.condition.pluginState="Plugin state"
|
||||||
@@ -941,7 +941,8 @@ AdvSceneSwitcher.action.streaming.type.server="Set server URL"
|
|||||||
AdvSceneSwitcher.action.streaming.type.streamKey="Set stream key"
|
AdvSceneSwitcher.action.streaming.type.streamKey="Set stream key"
|
||||||
AdvSceneSwitcher.action.streaming.type.username="Set username"
|
AdvSceneSwitcher.action.streaming.type.username="Set username"
|
||||||
AdvSceneSwitcher.action.streaming.type.password="Set password"
|
AdvSceneSwitcher.action.streaming.type.password="Set password"
|
||||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
AdvSceneSwitcher.action.streaming.getCurrentValue="Get current value"
|
||||||
|
AdvSceneSwitcher.action.streaming.layout="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}{{getCurrentValue}}"
|
||||||
AdvSceneSwitcher.action.run="Run"
|
AdvSceneSwitcher.action.run="Run"
|
||||||
AdvSceneSwitcher.action.run.wait.entry="{{wait}}Wait for process exit or at most {{timeout}}{{waitHelp}}"
|
AdvSceneSwitcher.action.run.wait.entry="{{wait}}Wait for process exit or at most {{timeout}}{{waitHelp}}"
|
||||||
AdvSceneSwitcher.action.run.wait.help.tooltip="Note that macro properties won't work if you leave this unticked, as the process spawns detached from the rest of logic and there's no control over it."
|
AdvSceneSwitcher.action.run.wait.help.tooltip="Note that macro properties won't work if you leave this unticked, as the process spawns detached from the rest of logic and there's no control over it."
|
||||||
@@ -1070,12 +1071,12 @@ AdvSceneSwitcher.action.macro.type.pause="Pause"
|
|||||||
AdvSceneSwitcher.action.macro.type.unpause="Unpause"
|
AdvSceneSwitcher.action.macro.type.unpause="Unpause"
|
||||||
AdvSceneSwitcher.action.macro.type.togglePause="Toggle pause"
|
AdvSceneSwitcher.action.macro.type.togglePause="Toggle pause"
|
||||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter"
|
AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter"
|
||||||
AdvSceneSwitcher.action.macro.type.run="Run macro"
|
AdvSceneSwitcher.action.macro.type.runActions="Run macro actions"
|
||||||
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Do not consider condition state"
|
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Do not consider condition state"
|
||||||
AdvSceneSwitcher.action.macro.type.run.conditions.true="Only if conditions evaluate to true"
|
AdvSceneSwitcher.action.macro.type.run.conditions.true="Only if conditions evaluate to true"
|
||||||
AdvSceneSwitcher.action.macro.type.run.conditions.false="Only if conditions evaluate to false"
|
AdvSceneSwitcher.action.macro.type.run.conditions.false="Only if conditions evaluate to false"
|
||||||
AdvSceneSwitcher.action.macro.type.run.updateConditionMatchState="Reevaluate the condition state before executing this action"
|
AdvSceneSwitcher.action.macro.type.run.updateConditionMatchState="Check conditions now, even if macro is paused"
|
||||||
AdvSceneSwitcher.action.macro.type.run.updateConditionMatchState.help="The plugin operates in phases:\n * The phase evaluating the macro conditions\n * The phase running macro actions\nMacros executed before this particular action might have side effects on the condition state of macros.\nCheck this option if you want those side effects to be taken into account when evaluating the condition state."
|
AdvSceneSwitcher.action.macro.type.run.updateConditionMatchState.help="The plugin operates in phases:\n * The phase evaluating the macro conditions\n * The phase running macro actions\nMacros executed before this particular action might have side effects on the condition state of macros.\nAdditionally, paused macros are assumed to not match their conditions.\nCheck this option to force a fresh condition evaluation before running this action, regardless of whether the macro is paused."
|
||||||
AdvSceneSwitcher.action.macro.type.run.actionType.regular="actions"
|
AdvSceneSwitcher.action.macro.type.run.actionType.regular="actions"
|
||||||
AdvSceneSwitcher.action.macro.type.run.actionType.else="else-actions"
|
AdvSceneSwitcher.action.macro.type.run.actionType.else="else-actions"
|
||||||
AdvSceneSwitcher.action.macro.type.run.skipWhenPaused="Skip execution when macro is paused"
|
AdvSceneSwitcher.action.macro.type.run.skipWhenPaused="Skip execution when macro is paused"
|
||||||
@@ -1086,6 +1087,9 @@ AdvSceneSwitcher.action.macro.type.disableAction="Disable action"
|
|||||||
AdvSceneSwitcher.action.macro.type.enableAction="Enable action"
|
AdvSceneSwitcher.action.macro.type.enableAction="Enable action"
|
||||||
AdvSceneSwitcher.action.macro.type.toggleAction="Toggle action"
|
AdvSceneSwitcher.action.macro.type.toggleAction="Toggle action"
|
||||||
AdvSceneSwitcher.action.macro.type.getInfo="Get macro info"
|
AdvSceneSwitcher.action.macro.type.getInfo="Get macro info"
|
||||||
|
AdvSceneSwitcher.action.macro.type.runMacro="Run macro"
|
||||||
|
AdvSceneSwitcher.action.macro.type.runMacro.noConditionsWarning="Warning: The selected macro has no conditions!"
|
||||||
|
AdvSceneSwitcher.action.macro.type.runMacro.help="Unlike \"Run macro actions\", this option will immediately re-evaluate the conditions of the selected macro and then run either its actions or else-actions depending on the result."
|
||||||
AdvSceneSwitcher.action.macro.type.nestedMacro="Nested macro"
|
AdvSceneSwitcher.action.macro.type.nestedMacro="Nested macro"
|
||||||
AdvSceneSwitcher.action.macro.actionSelectionType.index="at index"
|
AdvSceneSwitcher.action.macro.actionSelectionType.index="at index"
|
||||||
AdvSceneSwitcher.action.macro.actionSelectionType.label="with label"
|
AdvSceneSwitcher.action.macro.actionSelectionType.label="with label"
|
||||||
@@ -1096,6 +1100,7 @@ AdvSceneSwitcher.action.macro.type.nestedMacro.elseActionHelp="This section allo
|
|||||||
AdvSceneSwitcher.action.macro.layout.run="{{actions}}{{actionSections}}of{{macros}}"
|
AdvSceneSwitcher.action.macro.layout.run="{{actions}}{{actionSections}}of{{macros}}"
|
||||||
AdvSceneSwitcher.action.macro.layout.run.condition="{{conditionBehaviors}}of{{conditionMacros}}"
|
AdvSceneSwitcher.action.macro.layout.run.condition="{{conditionBehaviors}}of{{conditionMacros}}"
|
||||||
AdvSceneSwitcher.action.macro.layout.actionState="{{actions}}{{actionSelectionType}}{{actionIndex}}{{label}}{{regex}}{{actionTypes}}in{{actionSections}}section of{{macros}}"
|
AdvSceneSwitcher.action.macro.layout.actionState="{{actions}}{{actionSelectionType}}{{actionIndex}}{{label}}{{regex}}{{actionTypes}}in{{actionSections}}section of{{macros}}"
|
||||||
|
AdvSceneSwitcher.action.macro.layout.runMacro="{{actions}}{{runMacroHelp}}{{macros}}"
|
||||||
AdvSceneSwitcher.action.macro.layout.other="{{actions}}{{macros}}"
|
AdvSceneSwitcher.action.macro.layout.other="{{actions}}{{macros}}"
|
||||||
AdvSceneSwitcher.action.pluginState="Plugin state"
|
AdvSceneSwitcher.action.pluginState="Plugin state"
|
||||||
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
|
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
|
||||||
@@ -1789,6 +1794,10 @@ AdvSceneSwitcher.script.file.layout="Script file:{{path}}{{open}}"
|
|||||||
|
|
||||||
AdvSceneSwitcher.tempVar.select="--select value--"
|
AdvSceneSwitcher.tempVar.select="--select value--"
|
||||||
AdvSceneSwitcher.tempVar.selectionInfo.lastValues="Last values:"
|
AdvSceneSwitcher.tempVar.selectionInfo.lastValues="Last values:"
|
||||||
|
AdvSceneSwitcher.tempVar.outputMappings="Save outputs to variables:"
|
||||||
|
AdvSceneSwitcher.tempVar.outputMappings.add="+ Add output mapping"
|
||||||
|
AdvSceneSwitcher.tempVar.outputMappings.toggle="Assign outputs to variables"
|
||||||
|
AdvSceneSwitcher.tempVar.outputMappings.remove="Remove output mapping"
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.twitch.broadcaster_user_id="Twitch broadcaster user ID"
|
AdvSceneSwitcher.tempVar.twitch.broadcaster_user_id="Twitch broadcaster user ID"
|
||||||
AdvSceneSwitcher.tempVar.twitch.broadcaster_user_id.description="The numerical Twitch user ID of the broadcaster."
|
AdvSceneSwitcher.tempVar.twitch.broadcaster_user_id.description="The numerical Twitch user ID of the broadcaster."
|
||||||
@@ -2312,6 +2321,7 @@ AdvSceneSwitcher.tempVar.macro.info.secondsSinceLastRun="Seconds since last run"
|
|||||||
AdvSceneSwitcher.tempVar.macro.info.secondsSinceLastRun.description="The number of seconds elapsed since the macro was last executed. Value is -1 if the macro has never been executed."
|
AdvSceneSwitcher.tempVar.macro.info.secondsSinceLastRun.description="The number of seconds elapsed since the macro was last executed. Value is -1 if the macro has never been executed."
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.process.name="Process name"
|
AdvSceneSwitcher.tempVar.process.name="Process name"
|
||||||
|
AdvSceneSwitcher.tempVar.process.path="Process path"
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.run.process.id="Process ID"
|
AdvSceneSwitcher.tempVar.run.process.id="Process ID"
|
||||||
AdvSceneSwitcher.tempVar.run.process.id.description="PID of the process assigned by the system."
|
AdvSceneSwitcher.tempVar.run.process.id.description="PID of the process assigned by the system."
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ AdvSceneSwitcher.macroTab.highlightTrueConditions="Resaltar condiciones de la ma
|
|||||||
AdvSceneSwitcher.macroTab.highlightPerformedActions="Resaltar acciones realizadas recientemente de la macro seleccionada actualmente"
|
AdvSceneSwitcher.macroTab.highlightPerformedActions="Resaltar acciones realizadas recientemente de la macro seleccionada actualmente"
|
||||||
|
|
||||||
; Lógica de macros
|
; Lógica de macros
|
||||||
AdvSceneSwitcher.logic.none="Omitir entrada"
|
|
||||||
AdvSceneSwitcher.logic.and="Y"
|
AdvSceneSwitcher.logic.and="Y"
|
||||||
AdvSceneSwitcher.logic.or="O"
|
AdvSceneSwitcher.logic.or="O"
|
||||||
AdvSceneSwitcher.logic.andNot="Y no"
|
AdvSceneSwitcher.logic.andNot="Y no"
|
||||||
@@ -173,7 +172,7 @@ AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
|
|||||||
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
|
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="Grabación detenida"
|
AdvSceneSwitcher.condition.record.state.stop="Grabación detenida"
|
||||||
AdvSceneSwitcher.condition.process="Proceso"
|
AdvSceneSwitcher.condition.process="Proceso"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}se está ejecutando{{focused}}y está enfocado"
|
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}se está ejecutando{{focused}}y está enfocado"
|
||||||
AdvSceneSwitcher.condition.idle="Inactivo"
|
AdvSceneSwitcher.condition.idle="Inactivo"
|
||||||
AdvSceneSwitcher.condition.idle.entry="No hay entradas de teclado o ratón durante {{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="No hay entradas de teclado o ratón durante {{duration}}"
|
||||||
AdvSceneSwitcher.condition.pluginState="Estado del complemento"
|
AdvSceneSwitcher.condition.pluginState="Estado del complemento"
|
||||||
@@ -340,7 +339,6 @@ AdvSceneSwitcher.action.replay.type.save="Guardar búfer de reproducción"
|
|||||||
AdvSceneSwitcher.action.streaming="Transmisión"
|
AdvSceneSwitcher.action.streaming="Transmisión"
|
||||||
AdvSceneSwitcher.action.streaming.type.stop="Detener transmisión"
|
AdvSceneSwitcher.action.streaming.type.stop="Detener transmisión"
|
||||||
AdvSceneSwitcher.action.streaming.type.start="Iniciar transmisión"
|
AdvSceneSwitcher.action.streaming.type.start="Iniciar transmisión"
|
||||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
|
||||||
AdvSceneSwitcher.action.run="Ejecutar"
|
AdvSceneSwitcher.action.run="Ejecutar"
|
||||||
AdvSceneSwitcher.action.sceneVisibility="Visibilidad del elemento de escena"
|
AdvSceneSwitcher.action.sceneVisibility="Visibilidad del elemento de escena"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Mostrar"
|
AdvSceneSwitcher.action.sceneVisibility.type.show="Mostrar"
|
||||||
@@ -372,7 +370,7 @@ AdvSceneSwitcher.action.macro="Macro"
|
|||||||
AdvSceneSwitcher.action.macro.type.pause="Pausa"
|
AdvSceneSwitcher.action.macro.type.pause="Pausa"
|
||||||
AdvSceneSwitcher.action.macro.type.unpause="Reanudar"
|
AdvSceneSwitcher.action.macro.type.unpause="Reanudar"
|
||||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
|
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
|
||||||
AdvSceneSwitcher.action.macro.type.run="Ejecutar"
|
AdvSceneSwitcher.action.macro.type.runActions="Ejecutar"
|
||||||
AdvSceneSwitcher.action.macro.type.stop="Detener"
|
AdvSceneSwitcher.action.macro.type.stop="Detener"
|
||||||
AdvSceneSwitcher.action.pluginState="Estado del complemento"
|
AdvSceneSwitcher.action.pluginState="Estado del complemento"
|
||||||
AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced Scene Switcher"
|
AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced Scene Switcher"
|
||||||
|
|||||||
@@ -131,7 +131,6 @@ AdvSceneSwitcher.macroList.deleted="supprimé"
|
|||||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" est déjà sélectionné !"
|
AdvSceneSwitcher.macroList.duplicate="\"%1\" est déjà sélectionné !"
|
||||||
|
|
||||||
; Macro Logic
|
; Macro Logic
|
||||||
AdvSceneSwitcher.logic.none="Ignorer l'entrée"
|
|
||||||
AdvSceneSwitcher.logic.and="Et"
|
AdvSceneSwitcher.logic.and="Et"
|
||||||
AdvSceneSwitcher.logic.or="Ou"
|
AdvSceneSwitcher.logic.or="Ou"
|
||||||
AdvSceneSwitcher.logic.andNot="Et pas"
|
AdvSceneSwitcher.logic.andNot="Et pas"
|
||||||
@@ -279,8 +278,8 @@ AdvSceneSwitcher.condition.record.state.start="Enregistrement en cours"
|
|||||||
AdvSceneSwitcher.condition.record.state.pause="Enregistrement en pause"
|
AdvSceneSwitcher.condition.record.state.pause="Enregistrement en pause"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="Arrêt de l'enregistrement"
|
AdvSceneSwitcher.condition.record.state.stop="Arrêt de l'enregistrement"
|
||||||
AdvSceneSwitcher.condition.process="Processus"
|
AdvSceneSwitcher.condition.process="Processus"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}en cours d'exécution{{focused}}et est au premier plan"
|
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}en cours d'exécution{{focused}}et est au premier plan"
|
||||||
AdvSceneSwitcher.condition.process.entry.focus="Processus au premier plan actuel :{{focusProcess}}"
|
AdvSceneSwitcher.condition.process.layout.focus="Processus au premier plan actuel :{{focusProcess}}"
|
||||||
AdvSceneSwitcher.condition.idle="Inactif"
|
AdvSceneSwitcher.condition.idle="Inactif"
|
||||||
AdvSceneSwitcher.condition.idle.entry="Aucune entrée de clavier ou de souris pendant{{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="Aucune entrée de clavier ou de souris pendant{{duration}}"
|
||||||
AdvSceneSwitcher.condition.pluginState="État du plugin"
|
AdvSceneSwitcher.condition.pluginState="État du plugin"
|
||||||
@@ -551,7 +550,7 @@ AdvSceneSwitcher.action.macro="Macro"
|
|||||||
AdvSceneSwitcher.action.macro.type.pause="Pause"
|
AdvSceneSwitcher.action.macro.type.pause="Pause"
|
||||||
AdvSceneSwitcher.action.macro.type.unpause="Reprendre"
|
AdvSceneSwitcher.action.macro.type.unpause="Reprendre"
|
||||||
AdvSceneSwitcher.action.macro.type.resetCounter="Réinitialiser le compteur"
|
AdvSceneSwitcher.action.macro.type.resetCounter="Réinitialiser le compteur"
|
||||||
AdvSceneSwitcher.action.macro.type.run="Exécuter les actions"
|
AdvSceneSwitcher.action.macro.type.runActions="Exécuter les actions"
|
||||||
AdvSceneSwitcher.action.macro.type.stop="Arrêter les actions"
|
AdvSceneSwitcher.action.macro.type.stop="Arrêter les actions"
|
||||||
AdvSceneSwitcher.action.macro.type.disableAction="Désactiver l'action"
|
AdvSceneSwitcher.action.macro.type.disableAction="Désactiver l'action"
|
||||||
AdvSceneSwitcher.action.macro.type.enableAction="Activer l'action"
|
AdvSceneSwitcher.action.macro.type.enableAction="Activer l'action"
|
||||||
|
|||||||
@@ -275,7 +275,6 @@ AdvSceneSwitcher.macroList.deleted="削除"
|
|||||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" はすでに選択されています!"
|
AdvSceneSwitcher.macroList.duplicate="\"%1\" はすでに選択されています!"
|
||||||
|
|
||||||
# Macro Logic
|
# Macro Logic
|
||||||
AdvSceneSwitcher.logic.none="入力無視"
|
|
||||||
; AdvSceneSwitcher.logic.and="And"
|
; AdvSceneSwitcher.logic.and="And"
|
||||||
; AdvSceneSwitcher.logic.or="Or"
|
; AdvSceneSwitcher.logic.or="Or"
|
||||||
; AdvSceneSwitcher.logic.andNot="And not"
|
; AdvSceneSwitcher.logic.andNot="And not"
|
||||||
@@ -445,8 +444,8 @@ AdvSceneSwitcher.condition.stream.service.tooltip="現在のサービス名: %1"
|
|||||||
AdvSceneSwitcher.condition.record.state.duration="録音時間が長くなっています。"
|
AdvSceneSwitcher.condition.record.state.duration="録音時間が長くなっています。"
|
||||||
; AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
; AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
||||||
AdvSceneSwitcher.condition.process="プロセス"
|
AdvSceneSwitcher.condition.process="プロセス"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}が実行中{{focused}}に集中しています"
|
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}が実行中{{focused}}に集中しています"
|
||||||
AdvSceneSwitcher.condition.process.entry.focus="現在のフォアグラウンドプロセス:{{focusProcess}}"
|
AdvSceneSwitcher.condition.process.layout.focus="現在のフォアグラウンドプロセス:{{focusProcess}}"
|
||||||
AdvSceneSwitcher.condition.idle="アイドル"
|
AdvSceneSwitcher.condition.idle="アイドル"
|
||||||
AdvSceneSwitcher.condition.idle.entry="{{duration}}の間、キーボードまたはマウスの入力がありません"
|
AdvSceneSwitcher.condition.idle.entry="{{duration}}の間、キーボードまたはマウスの入力がありません"
|
||||||
AdvSceneSwitcher.condition.pluginState="プラグインの状態"
|
AdvSceneSwitcher.condition.pluginState="プラグインの状態"
|
||||||
@@ -923,7 +922,7 @@ AdvSceneSwitcher.action.macro.type.pause="一時停止"
|
|||||||
AdvSceneSwitcher.action.macro.type.unpause="一時停止解除"
|
AdvSceneSwitcher.action.macro.type.unpause="一時停止解除"
|
||||||
AdvSceneSwitcher.action.macro.type.togglePause="一時停止を切り替え"
|
AdvSceneSwitcher.action.macro.type.togglePause="一時停止を切り替え"
|
||||||
AdvSceneSwitcher.action.macro.type.resetCounter="カウンターリセット"
|
AdvSceneSwitcher.action.macro.type.resetCounter="カウンターリセット"
|
||||||
AdvSceneSwitcher.action.macro.type.run="マクロを実行"
|
AdvSceneSwitcher.action.macro.type.runActions="マクロを実行"
|
||||||
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="条件の状態を考慮しない"
|
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="条件の状態を考慮しない"
|
||||||
AdvSceneSwitcher.action.macro.type.run.conditions.true="条件が true と評価された場合のみ"
|
AdvSceneSwitcher.action.macro.type.run.conditions.true="条件が true と評価された場合のみ"
|
||||||
AdvSceneSwitcher.action.macro.type.run.conditions.false="条件が false と評価された場合のみ"
|
AdvSceneSwitcher.action.macro.type.run.conditions.false="条件が false と評価された場合のみ"
|
||||||
|
|||||||
@@ -239,7 +239,6 @@ AdvSceneSwitcher.macroList.deleted="excluída"
|
|||||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" já está selecionada!"
|
AdvSceneSwitcher.macroList.duplicate="\"%1\" já está selecionada!"
|
||||||
|
|
||||||
; Macro Logic
|
; Macro Logic
|
||||||
AdvSceneSwitcher.logic.none="Ignorar entrada"
|
|
||||||
AdvSceneSwitcher.logic.and="E"
|
AdvSceneSwitcher.logic.and="E"
|
||||||
AdvSceneSwitcher.logic.or="Ou"
|
AdvSceneSwitcher.logic.or="Ou"
|
||||||
AdvSceneSwitcher.logic.andNot="E não"
|
AdvSceneSwitcher.logic.andNot="E não"
|
||||||
@@ -395,8 +394,8 @@ AdvSceneSwitcher.condition.record.state.stop="Gravação parada"
|
|||||||
AdvSceneSwitcher.condition.record.state.duration="Duração da gravação é maior que"
|
AdvSceneSwitcher.condition.record.state.duration="Duração da gravação é maior que"
|
||||||
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
||||||
AdvSceneSwitcher.condition.process="Processo"
|
AdvSceneSwitcher.condition.process="Processo"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}está em execução{{focused}}e está em foco"
|
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}está em execução{{focused}}e está em foco"
|
||||||
AdvSceneSwitcher.condition.process.entry.focus="Processo atual em primeiro plano:{{focusProcess}}"
|
AdvSceneSwitcher.condition.process.layout.focus="Processo atual em primeiro plano:{{focusProcess}}"
|
||||||
AdvSceneSwitcher.condition.idle="Inativo"
|
AdvSceneSwitcher.condition.idle="Inativo"
|
||||||
AdvSceneSwitcher.condition.idle.entry="Sem entradas de teclado ou mouse por {{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="Sem entradas de teclado ou mouse por {{duration}}"
|
||||||
AdvSceneSwitcher.condition.pluginState="Estado do plugin"
|
AdvSceneSwitcher.condition.pluginState="Estado do plugin"
|
||||||
@@ -765,7 +764,6 @@ AdvSceneSwitcher.action.streaming.type.server="Definir URL do servidor"
|
|||||||
AdvSceneSwitcher.action.streaming.type.streamKey="Definir chave de transmissão"
|
AdvSceneSwitcher.action.streaming.type.streamKey="Definir chave de transmissão"
|
||||||
AdvSceneSwitcher.action.streaming.type.username="Definir nome de usuário"
|
AdvSceneSwitcher.action.streaming.type.username="Definir nome de usuário"
|
||||||
AdvSceneSwitcher.action.streaming.type.password="Definir senha"
|
AdvSceneSwitcher.action.streaming.type.password="Definir senha"
|
||||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
|
||||||
AdvSceneSwitcher.action.run="Executar"
|
AdvSceneSwitcher.action.run="Executar"
|
||||||
AdvSceneSwitcher.action.run.wait.entry="{{wait}}Aguardar a saída do processo ou no máximo {{timeout}}{{waitHelp}}"
|
AdvSceneSwitcher.action.run.wait.entry="{{wait}}Aguardar a saída do processo ou no máximo {{timeout}}{{waitHelp}}"
|
||||||
AdvSceneSwitcher.action.run.wait.help.tooltip="Observe que as propriedades da macro não funcionarão se você deixar isso desmarcado, pois o processo é iniciado de forma independente do restante da lógica e não há controle sobre ele."
|
AdvSceneSwitcher.action.run.wait.help.tooltip="Observe que as propriedades da macro não funcionarão se você deixar isso desmarcado, pois o processo é iniciado de forma independente do restante da lógica e não há controle sobre ele."
|
||||||
@@ -840,7 +838,7 @@ AdvSceneSwitcher.action.macro="Macro"
|
|||||||
AdvSceneSwitcher.action.macro.type.pause="Pausar"
|
AdvSceneSwitcher.action.macro.type.pause="Pausar"
|
||||||
AdvSceneSwitcher.action.macro.type.unpause="Retomar"
|
AdvSceneSwitcher.action.macro.type.unpause="Retomar"
|
||||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
|
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
|
||||||
AdvSceneSwitcher.action.macro.type.run="Executar macro"
|
AdvSceneSwitcher.action.macro.type.runActions="Executar macro"
|
||||||
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Não considerar o estado da condição"
|
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Não considerar o estado da condição"
|
||||||
AdvSceneSwitcher.action.macro.type.run.conditions.true="Apenas se as condições forem verdadeiras"
|
AdvSceneSwitcher.action.macro.type.run.conditions.true="Apenas se as condições forem verdadeiras"
|
||||||
AdvSceneSwitcher.action.macro.type.run.conditions.false="Apenas se as condições forem falsas"
|
AdvSceneSwitcher.action.macro.type.run.conditions.false="Apenas se as condições forem falsas"
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ AdvSceneSwitcher.macroTab.name="Имя:"
|
|||||||
AdvSceneSwitcher.macroTab.defaultname="Макрос %1"
|
AdvSceneSwitcher.macroTab.defaultname="Макрос %1"
|
||||||
AdvSceneSwitcher.macroTab.copy="Создать копию"
|
AdvSceneSwitcher.macroTab.copy="Создать копию"
|
||||||
; Macro Logic
|
; Macro Logic
|
||||||
AdvSceneSwitcher.logic.none="Игнорировать вход"
|
|
||||||
AdvSceneSwitcher.logic.and="И"
|
AdvSceneSwitcher.logic.and="И"
|
||||||
AdvSceneSwitcher.logic.or="Или"
|
AdvSceneSwitcher.logic.or="Или"
|
||||||
AdvSceneSwitcher.logic.andNot="И не"
|
AdvSceneSwitcher.logic.andNot="И не"
|
||||||
@@ -103,7 +102,7 @@ AdvSceneSwitcher.condition.record.state.start="Запись запущена"
|
|||||||
AdvSceneSwitcher.condition.record.state.pause="Запись приостановлена"
|
AdvSceneSwitcher.condition.record.state.pause="Запись приостановлена"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="Запись остановлена"
|
AdvSceneSwitcher.condition.record.state.stop="Запись остановлена"
|
||||||
AdvSceneSwitcher.condition.process="Процесс"
|
AdvSceneSwitcher.condition.process="Процесс"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}запущен{{focused}}и сфокусирован"
|
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}запущен{{focused}}и сфокусирован"
|
||||||
AdvSceneSwitcher.condition.idle="Простой"
|
AdvSceneSwitcher.condition.idle="Простой"
|
||||||
AdvSceneSwitcher.condition.idle.entry="Не было ни клавиатуры, ни мыши в течении{{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="Не было ни клавиатуры, ни мыши в течении{{duration}}"
|
||||||
AdvSceneSwitcher.condition.pluginState="Состояние плагина"
|
AdvSceneSwitcher.condition.pluginState="Состояние плагина"
|
||||||
@@ -135,7 +134,6 @@ AdvSceneSwitcher.action.replay.type.save="Сохранить буфер восп
|
|||||||
AdvSceneSwitcher.action.streaming="Потоковое вещание"
|
AdvSceneSwitcher.action.streaming="Потоковое вещание"
|
||||||
AdvSceneSwitcher.action.streaming.type.stop="Остановить потоковое вещание"
|
AdvSceneSwitcher.action.streaming.type.stop="Остановить потоковое вещание"
|
||||||
AdvSceneSwitcher.action.streaming.type.start="Начать потоковое вещание"
|
AdvSceneSwitcher.action.streaming.type.start="Начать потоковое вещание"
|
||||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
|
||||||
AdvSceneSwitcher.action.run="Запустить"
|
AdvSceneSwitcher.action.run="Запустить"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ AdvSceneSwitcher.macroTab.expandAll="Hepsini Genişlet"
|
|||||||
AdvSceneSwitcher.macroTab.collapseAll="Hepsini Küçült"
|
AdvSceneSwitcher.macroTab.collapseAll="Hepsini Küçült"
|
||||||
|
|
||||||
; Macro Logic
|
; Macro Logic
|
||||||
AdvSceneSwitcher.logic.none="Girişi yoksay"
|
|
||||||
AdvSceneSwitcher.logic.and="Ve"
|
AdvSceneSwitcher.logic.and="Ve"
|
||||||
AdvSceneSwitcher.logic.or="Ya da"
|
AdvSceneSwitcher.logic.or="Ya da"
|
||||||
AdvSceneSwitcher.logic.andNot="ve değil"
|
AdvSceneSwitcher.logic.andNot="ve değil"
|
||||||
@@ -150,7 +149,7 @@ AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
|
|||||||
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
|
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="Kayıt durdu"
|
AdvSceneSwitcher.condition.record.state.stop="Kayıt durdu"
|
||||||
AdvSceneSwitcher.condition.process="İşlem"
|
AdvSceneSwitcher.condition.process="İşlem"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}çalışıyor{{focused}}ve odaklandı"
|
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}çalışıyor{{focused}}ve odaklandı"
|
||||||
AdvSceneSwitcher.condition.idle="Boşta"
|
AdvSceneSwitcher.condition.idle="Boşta"
|
||||||
AdvSceneSwitcher.condition.idle.entry="...için klavye veya fare girişi yok {{duration}}"
|
AdvSceneSwitcher.condition.idle.entry="...için klavye veya fare girişi yok {{duration}}"
|
||||||
AdvSceneSwitcher.condition.pluginState="Eklenti durumu"
|
AdvSceneSwitcher.condition.pluginState="Eklenti durumu"
|
||||||
@@ -270,7 +269,6 @@ AdvSceneSwitcher.action.replay.type.save="Tekrar arabelleğini kaydet"
|
|||||||
AdvSceneSwitcher.action.streaming="Yayın"
|
AdvSceneSwitcher.action.streaming="Yayın"
|
||||||
AdvSceneSwitcher.action.streaming.type.stop="Yayın durdur"
|
AdvSceneSwitcher.action.streaming.type.stop="Yayın durdur"
|
||||||
AdvSceneSwitcher.action.streaming.type.start="Yayın başlat"
|
AdvSceneSwitcher.action.streaming.type.start="Yayın başlat"
|
||||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
|
||||||
AdvSceneSwitcher.action.run="Çalıştır"
|
AdvSceneSwitcher.action.run="Çalıştır"
|
||||||
AdvSceneSwitcher.action.sceneVisibility="Sahne öğesi görünürlüğü"
|
AdvSceneSwitcher.action.sceneVisibility="Sahne öğesi görünürlüğü"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Göster"
|
AdvSceneSwitcher.action.sceneVisibility.type.show="Göster"
|
||||||
@@ -301,7 +299,7 @@ AdvSceneSwitcher.action.macro="Makro"
|
|||||||
AdvSceneSwitcher.action.macro.type.pause="Duraklat"
|
AdvSceneSwitcher.action.macro.type.pause="Duraklat"
|
||||||
AdvSceneSwitcher.action.macro.type.unpause="Duraklatma"
|
AdvSceneSwitcher.action.macro.type.unpause="Duraklatma"
|
||||||
AdvSceneSwitcher.action.macro.type.resetCounter="Sayacı sıfırla"
|
AdvSceneSwitcher.action.macro.type.resetCounter="Sayacı sıfırla"
|
||||||
AdvSceneSwitcher.action.macro.type.run="Çalıştır"
|
AdvSceneSwitcher.action.macro.type.runActions="Çalıştır"
|
||||||
AdvSceneSwitcher.action.pluginState="Eklenti durumu"
|
AdvSceneSwitcher.action.pluginState="Eklenti durumu"
|
||||||
AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisini durdurun"
|
AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisini durdurun"
|
||||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:"
|
AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:"
|
||||||
|
|||||||
@@ -259,7 +259,6 @@ AdvSceneSwitcher.macroList.deleted="删除"
|
|||||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" 已选择!"
|
AdvSceneSwitcher.macroList.duplicate="\"%1\" 已选择!"
|
||||||
|
|
||||||
; Macro Logic
|
; Macro Logic
|
||||||
AdvSceneSwitcher.logic.none="忽略条件"
|
|
||||||
AdvSceneSwitcher.logic.and="且"
|
AdvSceneSwitcher.logic.and="且"
|
||||||
AdvSceneSwitcher.logic.or="或"
|
AdvSceneSwitcher.logic.or="或"
|
||||||
AdvSceneSwitcher.logic.andNot="且不"
|
AdvSceneSwitcher.logic.andNot="且不"
|
||||||
@@ -424,8 +423,8 @@ AdvSceneSwitcher.condition.record.state.stop="录制停止"
|
|||||||
AdvSceneSwitcher.condition.record.state.duration="录制时间长于"
|
AdvSceneSwitcher.condition.record.state.duration="录制时间长于"
|
||||||
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
||||||
AdvSceneSwitcher.condition.process="进程"
|
AdvSceneSwitcher.condition.process="进程"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}为正在运行中{{focused}}且为焦点"
|
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}为正在运行中{{focused}}且为焦点"
|
||||||
AdvSceneSwitcher.condition.process.entry.focus="当前焦点进程: {{focusProcess}}"
|
AdvSceneSwitcher.condition.process.layout.focus="当前焦点进程: {{focusProcess}}"
|
||||||
AdvSceneSwitcher.condition.idle="闲置检测"
|
AdvSceneSwitcher.condition.idle="闲置检测"
|
||||||
AdvSceneSwitcher.condition.idle.entry="{{duration}}内没有键盘或鼠标输入"
|
AdvSceneSwitcher.condition.idle.entry="{{duration}}内没有键盘或鼠标输入"
|
||||||
AdvSceneSwitcher.condition.pluginState="插件状态"
|
AdvSceneSwitcher.condition.pluginState="插件状态"
|
||||||
@@ -825,7 +824,6 @@ AdvSceneSwitcher.action.streaming.type.server="设置服务器"
|
|||||||
AdvSceneSwitcher.action.streaming.type.streamKey="设置推流码"
|
AdvSceneSwitcher.action.streaming.type.streamKey="设置推流码"
|
||||||
AdvSceneSwitcher.action.streaming.type.username="设置用户名"
|
AdvSceneSwitcher.action.streaming.type.username="设置用户名"
|
||||||
AdvSceneSwitcher.action.streaming.type.password="设置密码"
|
AdvSceneSwitcher.action.streaming.type.password="设置密码"
|
||||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
|
||||||
AdvSceneSwitcher.action.run="运行"
|
AdvSceneSwitcher.action.run="运行"
|
||||||
AdvSceneSwitcher.action.run.wait.entry="{{wait}}进程退出或最多等待{{timeout}}{{waitHelp}}"
|
AdvSceneSwitcher.action.run.wait.entry="{{wait}}进程退出或最多等待{{timeout}}{{waitHelp}}"
|
||||||
AdvSceneSwitcher.action.run.wait.help.tooltip="请注意,如果不勾选此选项,宏属性将不起作用,因为进程的启动会脱离逻辑的其他部分,因此无法对其进行控制."
|
AdvSceneSwitcher.action.run.wait.help.tooltip="请注意,如果不勾选此选项,宏属性将不起作用,因为进程的启动会脱离逻辑的其他部分,因此无法对其进行控制."
|
||||||
@@ -900,7 +898,7 @@ AdvSceneSwitcher.action.macro="宏"
|
|||||||
AdvSceneSwitcher.action.macro.type.pause="停用"
|
AdvSceneSwitcher.action.macro.type.pause="停用"
|
||||||
AdvSceneSwitcher.action.macro.type.unpause="启用"
|
AdvSceneSwitcher.action.macro.type.unpause="启用"
|
||||||
AdvSceneSwitcher.action.macro.type.resetCounter="重置计数器"
|
AdvSceneSwitcher.action.macro.type.resetCounter="重置计数器"
|
||||||
AdvSceneSwitcher.action.macro.type.run="运行宏"
|
AdvSceneSwitcher.action.macro.type.runActions="运行宏"
|
||||||
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="忽略条件结果"
|
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="忽略条件结果"
|
||||||
AdvSceneSwitcher.action.macro.type.run.conditions.true="仅当条件结果为真时"
|
AdvSceneSwitcher.action.macro.type.run.conditions.true="仅当条件结果为真时"
|
||||||
AdvSceneSwitcher.action.macro.type.run.conditions.false="仅当条件结果为假时"
|
AdvSceneSwitcher.action.macro.type.run.conditions.false="仅当条件结果为假时"
|
||||||
|
|||||||
10
data/res/images/DarkVariable.svg
Normal file
10
data/res/images/DarkVariable.svg
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#fefefe" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="800px" height="800px" viewBox="0 0 52 52" enable-background="new 0 0 52 52" xml:space="preserve">
|
||||||
|
<path d="M42.6,17.8c2.4,0,7.2-2,7.2-8.4c0-6.4-4.6-6.8-6.1-6.8c-2.8,0-5.6,2-8.1,6.3c-2.5,4.4-5.3,9.1-5.3,9.1
|
||||||
|
l-0.1,0c-0.6-3.1-1.1-5.6-1.3-6.7c-0.5-2.7-3.6-8.4-9.9-8.4c-6.4,0-12.2,3.7-12.2,3.7l0,0C5.8,7.3,5.1,8.5,5.1,9.9
|
||||||
|
c0,2.1,1.7,3.9,3.9,3.9c0.6,0,1.2-0.2,1.7-0.4l0,0c0,0,4.8-2.7,5.9,0c0.3,0.8,0.6,1.7,0.9,2.7c1.2,4.2,2.4,9.1,3.3,13.5l-4.2,6
|
||||||
|
c0,0-4.7-1.7-7.1-1.7s-7.2,2-7.2,8.4s4.6,6.8,6.1,6.8c2.8,0,5.6-2,8.1-6.3c2.5-4.4,5.3-9.1,5.3-9.1c0.8,4,1.5,7.1,1.9,8.5
|
||||||
|
c1.6,4.5,5.3,7.2,10.1,7.2c0,0,5,0,10.9-3.3c1.4-0.6,2.4-2,2.4-3.6c0-2.1-1.7-3.9-3.9-3.9c-0.6,0-1.2,0.2-1.7,0.4l0,0
|
||||||
|
c0,0-4.2,2.4-5.6,0.5c-1-2-1.9-4.6-2.6-7.8c-0.6-2.8-1.3-6.2-2-9.5l4.3-6.2C35.5,16.1,40.2,17.8,42.6,17.8z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 973 B |
10
data/res/images/LightVariable.svg
Normal file
10
data/res/images/LightVariable.svg
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#202020" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="800px" height="800px" viewBox="0 0 52 52" enable-background="new 0 0 52 52" xml:space="preserve">
|
||||||
|
<path d="M42.6,17.8c2.4,0,7.2-2,7.2-8.4c0-6.4-4.6-6.8-6.1-6.8c-2.8,0-5.6,2-8.1,6.3c-2.5,4.4-5.3,9.1-5.3,9.1
|
||||||
|
l-0.1,0c-0.6-3.1-1.1-5.6-1.3-6.7c-0.5-2.7-3.6-8.4-9.9-8.4c-6.4,0-12.2,3.7-12.2,3.7l0,0C5.8,7.3,5.1,8.5,5.1,9.9
|
||||||
|
c0,2.1,1.7,3.9,3.9,3.9c0.6,0,1.2-0.2,1.7-0.4l0,0c0,0,4.8-2.7,5.9,0c0.3,0.8,0.6,1.7,0.9,2.7c1.2,4.2,2.4,9.1,3.3,13.5l-4.2,6
|
||||||
|
c0,0-4.7-1.7-7.1-1.7s-7.2,2-7.2,8.4s4.6,6.8,6.1,6.8c2.8,0,5.6-2,8.1-6.3c2.5-4.4,5.3-9.1,5.3-9.1c0.8,4,1.5,7.1,1.9,8.5
|
||||||
|
c1.6,4.5,5.3,7.2,10.1,7.2c0,0,5,0,10.9-3.3c1.4-0.6,2.4-2,2.4-3.6c0-2.1-1.7-3.9-3.9-3.9c-0.6,0-1.2,0.2-1.7,0.4l0,0
|
||||||
|
c0,0-4.2,2.4-5.6,0.5c-1-2-1.9-4.6-2.6-7.8c-0.6-2.8-1.3-6.2-2-9.5l4.3-6.2C35.5,16.1,40.2,17.8,42.6,17.8z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 973 B |
@@ -322,8 +322,7 @@ void SwitcherData::SetPreconditions()
|
|||||||
{
|
{
|
||||||
// Window title
|
// Window title
|
||||||
lastTitle = currentTitle;
|
lastTitle = currentTitle;
|
||||||
std::string title;
|
auto title = GetCurrentWindowTitle();
|
||||||
GetCurrentWindowTitle(title);
|
|
||||||
for (auto &window : ignoreWindowsSwitches) {
|
for (auto &window : ignoreWindowsSwitches) {
|
||||||
bool equals = (title == window);
|
bool equals = (title == window);
|
||||||
bool matches = false;
|
bool matches = false;
|
||||||
@@ -343,7 +342,7 @@ void SwitcherData::SetPreconditions()
|
|||||||
currentTitle = title;
|
currentTitle = title;
|
||||||
|
|
||||||
// Process name
|
// Process name
|
||||||
GetForegroundProcessName(currentForegroundProcess);
|
currentForegroundProcess = GetForegroundProcessName();
|
||||||
|
|
||||||
// Macro
|
// Macro
|
||||||
InvalidateMacroTempVarValues();
|
InvalidateMacroTempVarValues();
|
||||||
@@ -507,6 +506,8 @@ bool SwitcherData::AnySceneTransitionStarted()
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
extern "C" EXPORT void FreeSceneSwitcher()
|
extern "C" EXPORT void FreeSceneSwitcher()
|
||||||
{
|
{
|
||||||
|
switcher->Stop();
|
||||||
|
|
||||||
PlatformCleanup();
|
PlatformCleanup();
|
||||||
RunPluginCleanupSteps();
|
RunPluginCleanupSteps();
|
||||||
|
|
||||||
@@ -628,13 +629,20 @@ static void handleSceneCollectionCleanup()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP is also called on
|
||||||
|
// shutdown.
|
||||||
|
// Here we also don't want to clear the settings.
|
||||||
|
if (switcher->obsIsShuttingDown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SaveSceneSwitcher(nullptr, false, nullptr);
|
SaveSceneSwitcher(nullptr, false, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note to future self:
|
// Note to future self:
|
||||||
// be careful using switcher->m here as there is potential for deadlocks when using
|
// be careful using switcher->m here as there is potential for deadlocks when using
|
||||||
// frontend functions such as obs_frontend_set_current_scene()
|
// frontend functions such as obs_frontend_set_current_scene()
|
||||||
static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
static void OBSEvent(enum obs_frontend_event event, void *)
|
||||||
{
|
{
|
||||||
if (!switcher) {
|
if (!switcher) {
|
||||||
return;
|
return;
|
||||||
@@ -768,8 +776,6 @@ void HighlightMacroSettingsButton(bool enable)
|
|||||||
enable);
|
enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupActionQueues();
|
|
||||||
|
|
||||||
extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module,
|
extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module,
|
||||||
translateFunc translate)
|
translateFunc translate)
|
||||||
{
|
{
|
||||||
@@ -781,12 +787,11 @@ extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module,
|
|||||||
PlatformInit();
|
PlatformInit();
|
||||||
LoadPlugins();
|
LoadPlugins();
|
||||||
SetupDock();
|
SetupDock();
|
||||||
SetupActionQueues();
|
|
||||||
|
|
||||||
RunPluginInitSteps();
|
RunPluginInitSteps();
|
||||||
|
|
||||||
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
|
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
|
||||||
obs_frontend_add_event_callback(OBSEvent, switcher);
|
obs_frontend_add_event_callback(OBSEvent, nullptr);
|
||||||
|
|
||||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||||
obs_module_text("AdvSceneSwitcher.pluginName"));
|
obs_module_text("AdvSceneSwitcher.pluginName"));
|
||||||
|
|||||||
@@ -468,7 +468,6 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
|||||||
// Needs to be loaded before any entries which might rely on scene group
|
// Needs to be loaded before any entries which might rely on scene group
|
||||||
// selections to be available.
|
// selections to be available.
|
||||||
loadSceneGroups(obj);
|
loadSceneGroups(obj);
|
||||||
LoadVariables(obj);
|
|
||||||
|
|
||||||
RunLoadSteps(obj);
|
RunLoadSteps(obj);
|
||||||
|
|
||||||
@@ -507,7 +506,6 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
|
|||||||
saveSceneGroups(obj);
|
saveSceneGroups(obj);
|
||||||
SaveMacros(obj);
|
SaveMacros(obj);
|
||||||
SaveGlobalMacroSettings(obj);
|
SaveGlobalMacroSettings(obj);
|
||||||
SaveVariables(obj);
|
|
||||||
saveWindowTitleSwitches(obj);
|
saveWindowTitleSwitches(obj);
|
||||||
saveScreenRegionSwitches(obj);
|
saveScreenRegionSwitches(obj);
|
||||||
savePauseSwitches(obj);
|
savePauseSwitches(obj);
|
||||||
|
|||||||
@@ -92,12 +92,11 @@ bool SwitcherData::checkExeSwitch(OBSWeakSource &scene,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string title = switcher->currentTitle;
|
std::string title = switcher->currentTitle;
|
||||||
QStringList runningProcesses;
|
|
||||||
bool ignored = false;
|
bool ignored = false;
|
||||||
bool match = false;
|
bool match = false;
|
||||||
|
|
||||||
// Check for match
|
// Check for match
|
||||||
GetProcessList(runningProcesses);
|
const auto runningProcesses = GetProcessList();
|
||||||
for (ExecutableSwitch &s : executableSwitches) {
|
for (ExecutableSwitch &s : executableSwitches) {
|
||||||
if (!s.initialized()) {
|
if (!s.initialized()) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -230,8 +230,7 @@ bool SwitcherData::checkWindowTitleSwitch(OBSWeakSource &scene,
|
|||||||
|
|
||||||
std::string currentWindowTitle = switcher->currentTitle;
|
std::string currentWindowTitle = switcher->currentTitle;
|
||||||
bool match = false;
|
bool match = false;
|
||||||
std::vector<std::string> windowList;
|
const auto windowList = GetWindowList();
|
||||||
GetWindowList(windowList);
|
|
||||||
|
|
||||||
for (WindowSwitch &s : windowSwitches) {
|
for (WindowSwitch &s : windowSwitches) {
|
||||||
if (!s.initialized()) {
|
if (!s.initialized()) {
|
||||||
|
|||||||
@@ -32,6 +32,9 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <climits>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include "kwin-helpers.h"
|
#include "kwin-helpers.h"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -233,9 +236,9 @@ std::string getWindowName(Window window)
|
|||||||
return windowTitle;
|
return windowTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetWindowList(std::vector<std::string> &windows)
|
std::vector<std::string> GetWindowList()
|
||||||
{
|
{
|
||||||
windows.resize(0);
|
std::vector<std::string> windows;
|
||||||
for (auto window : getTopLevelWindows()) {
|
for (auto window : getTopLevelWindows()) {
|
||||||
auto name = getWindowName(window);
|
auto name = getWindowName(window);
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
@@ -243,18 +246,7 @@ void GetWindowList(std::vector<std::string> &windows)
|
|||||||
}
|
}
|
||||||
windows.emplace_back(name);
|
windows.emplace_back(name);
|
||||||
}
|
}
|
||||||
}
|
return windows;
|
||||||
|
|
||||||
void GetWindowList(QStringList &windows)
|
|
||||||
{
|
|
||||||
windows.clear();
|
|
||||||
for (auto window : getTopLevelWindows()) {
|
|
||||||
auto name = getWindowName(window);
|
|
||||||
if (name.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
windows << QString::fromStdString(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int getActiveWindow(Window *&window)
|
int getActiveWindow(Window *&window)
|
||||||
@@ -278,29 +270,24 @@ int getActiveWindow(Window *&window)
|
|||||||
&bytes, (uint8_t **)&window);
|
&bytes, (uint8_t **)&window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetCurrentWindowTitle(std::string &title)
|
std::string GetCurrentWindowTitle()
|
||||||
{
|
{
|
||||||
if (KWin) {
|
if (KWin) {
|
||||||
title = FocusNotifier::getActiveWindowTitle();
|
return FocusNotifier::getActiveWindowTitle();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Window *data = 0;
|
Window *data = 0;
|
||||||
if (getActiveWindow(data) != Success || !data) {
|
if (getActiveWindow(data) != Success || !data) {
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
if (!data[0]) {
|
if (!data[0]) {
|
||||||
XFree(data);
|
XFree(data);
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto name = getWindowName(data[0]);
|
auto name = getWindowName(data[0]);
|
||||||
XFree(data);
|
XFree(data);
|
||||||
|
return name;
|
||||||
if (name.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
title = name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool windowStatesAreSet(const std::string &windowTitle,
|
bool windowStatesAreSet(const std::string &windowTitle,
|
||||||
@@ -409,16 +396,17 @@ static void getProcessListProcps2(QStringList &processes)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetProcessList(QStringList &processes)
|
QStringList GetProcessList()
|
||||||
{
|
{
|
||||||
processes.clear();
|
QStringList processes;
|
||||||
if (libprocpsSupported) {
|
if (libprocpsSupported) {
|
||||||
getProcessListProcps(processes);
|
getProcessListProcps(processes);
|
||||||
return;
|
return processes;
|
||||||
}
|
}
|
||||||
if (libprocps2Supported) {
|
if (libprocps2Supported) {
|
||||||
getProcessListProcps2(processes);
|
getProcessListProcps2(processes);
|
||||||
}
|
}
|
||||||
|
return processes;
|
||||||
}
|
}
|
||||||
|
|
||||||
long getForegroundProcessPid()
|
long getForegroundProcessPid()
|
||||||
@@ -469,24 +457,83 @@ std::string getProcNameFromPid(long pid)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetForegroundProcessName(QString &proc)
|
std::string GetForegroundProcessName()
|
||||||
{
|
{
|
||||||
std::string temp;
|
auto pid = getForegroundProcessPid();
|
||||||
GetForegroundProcessName(temp);
|
return getProcNameFromPid(pid);
|
||||||
proc = QString::fromStdString(temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetForegroundProcessName(std::string &proc)
|
static std::string getProcessPathFromPid(long pid)
|
||||||
|
{
|
||||||
|
std::string linkPath = "/proc/" + std::to_string(pid) + "/exe";
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
ssize_t len = readlink(linkPath.c_str(), buf, sizeof(buf) - 1);
|
||||||
|
if (len <= 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
buf[len] = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetForegroundProcessPath()
|
||||||
{
|
{
|
||||||
proc.resize(0);
|
|
||||||
auto pid = getForegroundProcessPid();
|
auto pid = getForegroundProcessPid();
|
||||||
proc = getProcNameFromPid(pid);
|
if (pid <= 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return getProcessPathFromPid(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList GetProcessPathsFromName(const QString &name)
|
||||||
|
{
|
||||||
|
QStringList paths;
|
||||||
|
const std::string nameStr = name.toStdString();
|
||||||
|
DIR *procDir = opendir("/proc");
|
||||||
|
if (!procDir) {
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dirent *entry;
|
||||||
|
while ((entry = readdir(procDir)) != nullptr) {
|
||||||
|
bool isPid = (entry->d_name[0] != '\0');
|
||||||
|
for (const char *c = entry->d_name; *c; c++) {
|
||||||
|
if (!isdigit(*c)) {
|
||||||
|
isPid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isPid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string pid = entry->d_name;
|
||||||
|
std::string commPath = "/proc/" + pid + "/comm";
|
||||||
|
std::ifstream commFile(commPath);
|
||||||
|
if (!commFile) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string comm;
|
||||||
|
std::getline(commFile, comm);
|
||||||
|
if (comm != nameStr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string path = getProcessPathFromPid(std::stol(pid));
|
||||||
|
if (path.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
QString qPath = QString::fromStdString(path);
|
||||||
|
if (!paths.contains(qPath)) {
|
||||||
|
paths.append(qPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(procDir);
|
||||||
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInFocus(const QString &executable)
|
bool IsInFocus(const QString &executable)
|
||||||
{
|
{
|
||||||
std::string current;
|
const auto current = GetForegroundProcessName();
|
||||||
GetForegroundProcessName(current);
|
|
||||||
|
|
||||||
// True if executable switch equals current window
|
// True if executable switch equals current window
|
||||||
bool equals = (executable.toStdString() == current);
|
bool equals = (executable.toStdString() == current);
|
||||||
|
|||||||
@@ -49,10 +49,12 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
|||||||
_section->AddHeaderWidget(_enable);
|
_section->AddHeaderWidget(_enable);
|
||||||
_section->AddHeaderWidget(_actionSelection);
|
_section->AddHeaderWidget(_actionSelection);
|
||||||
_section->AddHeaderWidget(_headerInfo);
|
_section->AddHeaderWidget(_headerInfo);
|
||||||
|
_section->AddHeaderWidget(_varMappingToggle);
|
||||||
|
|
||||||
auto actionLayout = new QVBoxLayout;
|
auto actionLayout = new QVBoxLayout;
|
||||||
actionLayout->setContentsMargins({7, 7, 7, 7});
|
actionLayout->setContentsMargins({7, 7, 7, 7});
|
||||||
actionLayout->addWidget(_section);
|
actionLayout->addWidget(_section);
|
||||||
|
actionLayout->addWidget(_outputMappings);
|
||||||
_contentLayout->addLayout(actionLayout);
|
_contentLayout->addLayout(actionLayout);
|
||||||
|
|
||||||
auto mainLayout = new QHBoxLayout;
|
auto mainLayout = new QHBoxLayout;
|
||||||
@@ -61,7 +63,6 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
|||||||
mainLayout->addWidget(_frame);
|
mainLayout->addWidget(_frame);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
_entryData = entryData;
|
|
||||||
SetupWidgets(true);
|
SetupWidgets(true);
|
||||||
|
|
||||||
actionStateTimer->start(300);
|
actionStateTimer->start(300);
|
||||||
@@ -90,7 +91,10 @@ void MacroActionEdit::SetupWidgets(bool basicSetup)
|
|||||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||||
|
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
|
||||||
|
SLOT(ShowVariableMappings(bool)));
|
||||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||||
|
SetupVarMappings((*_entryData).get());
|
||||||
SetFocusPolicyOfWidgets();
|
SetFocusPolicyOfWidgets();
|
||||||
|
|
||||||
_allWidgetsAreSetup = true;
|
_allWidgetsAreSetup = true;
|
||||||
@@ -121,7 +125,10 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
|||||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||||
|
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
|
||||||
|
SLOT(ShowVariableMappings(bool)));
|
||||||
_section->SetContent(widget);
|
_section->SetContent(widget);
|
||||||
|
SetupVarMappings((*_entryData).get());
|
||||||
SetFocusPolicyOfWidgets();
|
SetFocusPolicyOfWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,6 +120,15 @@ bool MacroActionMacro::PerformAction()
|
|||||||
case Action::TOGGLE_ACTION:
|
case Action::TOGGLE_ACTION:
|
||||||
AdjustActionState(macro);
|
AdjustActionState(macro);
|
||||||
break;
|
break;
|
||||||
|
case Action::RUN_MACRO: {
|
||||||
|
if (_runOptions.skipWhenPaused && macro->Paused()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const bool conditionsMatched =
|
||||||
|
macro->CheckConditions(true);
|
||||||
|
macro->PerformActions(conditionsMatched, false, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Action::GET_INFO: {
|
case Action::GET_INFO: {
|
||||||
SetTempVarValue(
|
SetTempVarValue(
|
||||||
"conditionCount",
|
"conditionCount",
|
||||||
@@ -210,6 +219,9 @@ void MacroActionMacro::LogAction() const
|
|||||||
case Action::GET_INFO:
|
case Action::GET_INFO:
|
||||||
ablog(LOG_INFO, "get info for \"%s\"", macro->Name().c_str());
|
ablog(LOG_INFO, "get info for \"%s\"", macro->Name().c_str());
|
||||||
break;
|
break;
|
||||||
|
case Action::RUN_MACRO:
|
||||||
|
ablog(LOG_INFO, "run macro \"%s\"", macro->Name().c_str());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -403,7 +415,9 @@ static void populateActionSelection(QComboBox *list)
|
|||||||
{MacroActionMacro::Action::NESTED_MACRO,
|
{MacroActionMacro::Action::NESTED_MACRO,
|
||||||
"AdvSceneSwitcher.action.macro.type.nestedMacro"},
|
"AdvSceneSwitcher.action.macro.type.nestedMacro"},
|
||||||
{MacroActionMacro::Action::RUN_ACTIONS,
|
{MacroActionMacro::Action::RUN_ACTIONS,
|
||||||
"AdvSceneSwitcher.action.macro.type.run"},
|
"AdvSceneSwitcher.action.macro.type.runActions"},
|
||||||
|
{MacroActionMacro::Action::RUN_MACRO,
|
||||||
|
"AdvSceneSwitcher.action.macro.type.runMacro"},
|
||||||
{MacroActionMacro::Action::STOP,
|
{MacroActionMacro::Action::STOP,
|
||||||
"AdvSceneSwitcher.action.macro.type.stop"},
|
"AdvSceneSwitcher.action.macro.type.stop"},
|
||||||
{MacroActionMacro::Action::DISABLE_ACTION,
|
{MacroActionMacro::Action::DISABLE_ACTION,
|
||||||
@@ -483,6 +497,10 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
|||||||
_actionSections(new QComboBox(this)),
|
_actionSections(new QComboBox(this)),
|
||||||
_skipWhenPaused(new QCheckBox(obs_module_text(
|
_skipWhenPaused(new QCheckBox(obs_module_text(
|
||||||
"AdvSceneSwitcher.action.macro.type.run.skipWhenPaused"))),
|
"AdvSceneSwitcher.action.macro.type.run.skipWhenPaused"))),
|
||||||
|
_noConditionsWarning(new QLabel(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.macro.type.runMacro.noConditionsWarning"))),
|
||||||
|
_runMacroHelp(new HelpIcon(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.macro.type.runMacro.help"))),
|
||||||
_setInputs(new QCheckBox(obs_module_text(
|
_setInputs(new QCheckBox(obs_module_text(
|
||||||
"AdvSceneSwitcher.action.macro.type.run.setInputs"))),
|
"AdvSceneSwitcher.action.macro.type.run.setInputs"))),
|
||||||
_inputs(new MacroInputEdit()),
|
_inputs(new MacroInputEdit()),
|
||||||
@@ -556,6 +574,7 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
|||||||
layout->addLayout(_setInputsLayout);
|
layout->addLayout(_setInputsLayout);
|
||||||
layout->addWidget(_inputs);
|
layout->addWidget(_inputs);
|
||||||
layout->addWidget(_skipWhenPaused);
|
layout->addWidget(_skipWhenPaused);
|
||||||
|
layout->addWidget(_noConditionsWarning);
|
||||||
layout->addWidget(_nestedMacro);
|
layout->addWidget(_nestedMacro);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
@@ -725,6 +744,7 @@ void MacroActionMacroEdit::InputsChanged(const StringList &inputs)
|
|||||||
void MacroActionMacroEdit::SetWidgetVisibility()
|
void MacroActionMacroEdit::SetWidgetVisibility()
|
||||||
{
|
{
|
||||||
_entryLayout->removeWidget(_actions);
|
_entryLayout->removeWidget(_actions);
|
||||||
|
_entryLayout->removeWidget(_runMacroHelp);
|
||||||
_entryLayout->removeWidget(_actionIndex);
|
_entryLayout->removeWidget(_actionIndex);
|
||||||
_entryLayout->removeWidget(_macros);
|
_entryLayout->removeWidget(_macros);
|
||||||
_entryLayout->removeWidget(_actionSections);
|
_entryLayout->removeWidget(_actionSections);
|
||||||
@@ -740,6 +760,7 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
|||||||
|
|
||||||
const std::unordered_map<std::string, QWidget *> placeholders = {
|
const std::unordered_map<std::string, QWidget *> placeholders = {
|
||||||
{"{{actions}}", _actions},
|
{"{{actions}}", _actions},
|
||||||
|
{"{{runMacroHelp}}", _runMacroHelp},
|
||||||
{"{{actionIndex}}", _actionIndex},
|
{"{{actionIndex}}", _actionIndex},
|
||||||
{"{{macros}}", _macros},
|
{"{{macros}}", _macros},
|
||||||
{"{{actionSections}}", _actionSections},
|
{"{{actionSections}}", _actionSections},
|
||||||
@@ -764,6 +785,9 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
|||||||
case MacroActionMacro::Action::GET_INFO:
|
case MacroActionMacro::Action::GET_INFO:
|
||||||
layoutText = "AdvSceneSwitcher.action.macro.layout.other";
|
layoutText = "AdvSceneSwitcher.action.macro.layout.other";
|
||||||
break;
|
break;
|
||||||
|
case MacroActionMacro::Action::RUN_MACRO:
|
||||||
|
layoutText = "AdvSceneSwitcher.action.macro.layout.runMacro";
|
||||||
|
break;
|
||||||
case MacroActionMacro::Action::RUN_ACTIONS:
|
case MacroActionMacro::Action::RUN_ACTIONS:
|
||||||
layoutText = "AdvSceneSwitcher.action.macro.layout.run";
|
layoutText = "AdvSceneSwitcher.action.macro.layout.run";
|
||||||
break;
|
break;
|
||||||
@@ -790,7 +814,8 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action == MacroActionMacro::Action::RUN_ACTIONS ||
|
if (action == MacroActionMacro::Action::RUN_ACTIONS ||
|
||||||
action == MacroActionMacro::Action::STOP) {
|
action == MacroActionMacro::Action::STOP ||
|
||||||
|
action == MacroActionMacro::Action::RUN_MACRO) {
|
||||||
_macros->HideSelectedMacro();
|
_macros->HideSelectedMacro();
|
||||||
} else {
|
} else {
|
||||||
_macros->ShowAllMacros();
|
_macros->ShowAllMacros();
|
||||||
@@ -835,8 +860,19 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
|||||||
_actionSections->setVisible(
|
_actionSections->setVisible(
|
||||||
action == MacroActionMacro::Action::RUN_ACTIONS ||
|
action == MacroActionMacro::Action::RUN_ACTIONS ||
|
||||||
isModifyingActionState);
|
isModifyingActionState);
|
||||||
_skipWhenPaused->setVisible(action ==
|
_skipWhenPaused->setVisible(
|
||||||
MacroActionMacro::Action::RUN_ACTIONS);
|
action == MacroActionMacro::Action::RUN_ACTIONS ||
|
||||||
|
action == MacroActionMacro::Action::RUN_MACRO);
|
||||||
|
|
||||||
|
if (action == MacroActionMacro::Action::RUN_MACRO) {
|
||||||
|
auto macro = _entryData->_macro.GetMacro();
|
||||||
|
_noConditionsWarning->setVisible(!macro ||
|
||||||
|
macro->Conditions().empty());
|
||||||
|
} else {
|
||||||
|
_noConditionsWarning->setVisible(false);
|
||||||
|
}
|
||||||
|
_runMacroHelp->setVisible(action ==
|
||||||
|
MacroActionMacro::Action::RUN_MACRO);
|
||||||
|
|
||||||
_nestedMacro->setVisible(action ==
|
_nestedMacro->setVisible(action ==
|
||||||
MacroActionMacro::Action::NESTED_MACRO);
|
MacroActionMacro::Action::NESTED_MACRO);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -57,6 +58,7 @@ public:
|
|||||||
TOGGLE_PAUSE,
|
TOGGLE_PAUSE,
|
||||||
NESTED_MACRO,
|
NESTED_MACRO,
|
||||||
GET_INFO,
|
GET_INFO,
|
||||||
|
RUN_MACRO,
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetAction(Action);
|
void SetAction(Action);
|
||||||
@@ -131,6 +133,8 @@ private:
|
|||||||
QCheckBox *_reevaluateConditionState;
|
QCheckBox *_reevaluateConditionState;
|
||||||
QComboBox *_actionSections;
|
QComboBox *_actionSections;
|
||||||
QCheckBox *_skipWhenPaused;
|
QCheckBox *_skipWhenPaused;
|
||||||
|
QLabel *_noConditionsWarning;
|
||||||
|
HelpIcon *_runMacroHelp;
|
||||||
QCheckBox *_setInputs;
|
QCheckBox *_setInputs;
|
||||||
MacroInputEdit *_inputs;
|
MacroInputEdit *_inputs;
|
||||||
QHBoxLayout *_entryLayout;
|
QHBoxLayout *_entryLayout;
|
||||||
|
|||||||
@@ -19,10 +19,11 @@ const std::string MacroActionVariable::id = "variable";
|
|||||||
|
|
||||||
std::vector<TempVariableRef> MacroActionVariable::GetTempVarRefs() const
|
std::vector<TempVariableRef> MacroActionVariable::GetTempVarRefs() const
|
||||||
{
|
{
|
||||||
if (!_tempVar.HasValidID()) {
|
auto refs = MacroSegment::GetTempVarRefs();
|
||||||
return {};
|
if (_tempVar.HasValidID()) {
|
||||||
|
refs.push_back(_tempVar);
|
||||||
}
|
}
|
||||||
return {_tempVar};
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroActionVariable::_registered = MacroActionFactory::Register(
|
bool MacroActionVariable::_registered = MacroActionFactory::Register(
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "path-helpers.hpp"
|
#include "path-helpers.hpp"
|
||||||
#include "plugin-state-helpers.hpp"
|
#include "plugin-state-helpers.hpp"
|
||||||
#include "section.hpp"
|
#include "section.hpp"
|
||||||
|
#include "switch-button.hpp"
|
||||||
#include "ui-helpers.hpp"
|
#include "ui-helpers.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
@@ -102,12 +103,15 @@ MacroConditionEdit::MacroConditionEdit(
|
|||||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
||||||
bool isRootCondition)
|
bool isRootCondition)
|
||||||
: MacroSegmentEdit(parent),
|
: MacroSegmentEdit(parent),
|
||||||
|
_enable(new SwitchButton()),
|
||||||
_logicSelection(new QComboBox()),
|
_logicSelection(new QComboBox()),
|
||||||
_conditionSelection(new FilterComboBox()),
|
_conditionSelection(new FilterComboBox()),
|
||||||
_dur(new DurationModifierEdit()),
|
_dur(new DurationModifierEdit()),
|
||||||
_entryData(entryData),
|
_entryData(entryData),
|
||||||
_isRoot(isRootCondition)
|
_isRoot(isRootCondition)
|
||||||
{
|
{
|
||||||
|
QWidget::connect(_enable, SIGNAL(checked(bool)), this,
|
||||||
|
SLOT(ConditionEnableChanged(bool)));
|
||||||
QWidget::connect(_logicSelection, SIGNAL(currentIndexChanged(int)),
|
QWidget::connect(_logicSelection, SIGNAL(currentIndexChanged(int)),
|
||||||
this, SLOT(LogicSelectionChanged(int)));
|
this, SLOT(LogicSelectionChanged(int)));
|
||||||
QWidget::connect(_conditionSelection,
|
QWidget::connect(_conditionSelection,
|
||||||
@@ -122,14 +126,17 @@ MacroConditionEdit::MacroConditionEdit(
|
|||||||
Logic::PopulateLogicTypeSelection(_logicSelection, isRootCondition);
|
Logic::PopulateLogicTypeSelection(_logicSelection, isRootCondition);
|
||||||
populateConditionSelection(_conditionSelection);
|
populateConditionSelection(_conditionSelection);
|
||||||
|
|
||||||
|
_section->AddHeaderWidget(_enable);
|
||||||
_section->AddHeaderWidget(_logicSelection);
|
_section->AddHeaderWidget(_logicSelection);
|
||||||
_section->AddHeaderWidget(_conditionSelection);
|
_section->AddHeaderWidget(_conditionSelection);
|
||||||
_section->AddHeaderWidget(_headerInfo);
|
_section->AddHeaderWidget(_headerInfo);
|
||||||
_section->AddHeaderWidget(_dur);
|
_section->AddHeaderWidget(_dur);
|
||||||
|
_section->AddHeaderWidget(_varMappingToggle);
|
||||||
|
|
||||||
QVBoxLayout *conditionLayout = new QVBoxLayout;
|
QVBoxLayout *conditionLayout = new QVBoxLayout;
|
||||||
conditionLayout->setContentsMargins({7, 7, 7, 7});
|
conditionLayout->setContentsMargins({7, 7, 7, 7});
|
||||||
conditionLayout->addWidget(_section);
|
conditionLayout->addWidget(_section);
|
||||||
|
conditionLayout->addWidget(_outputMappings);
|
||||||
_contentLayout->addLayout(conditionLayout);
|
_contentLayout->addLayout(conditionLayout);
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
@@ -152,8 +159,17 @@ void MacroConditionEdit::LogicSelectionChanged(int idx)
|
|||||||
const auto logic = static_cast<Logic::Type>(
|
const auto logic = static_cast<Logic::Type>(
|
||||||
_logicSelection->itemData(idx).toInt());
|
_logicSelection->itemData(idx).toInt());
|
||||||
(*_entryData)->SetLogicType(logic);
|
(*_entryData)->SetLogicType(logic);
|
||||||
|
}
|
||||||
|
|
||||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
void MacroConditionEdit::ConditionEnableChanged(bool value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
(*_entryData)->SetEnabled(value);
|
||||||
|
SetDisableEffect(!value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionEdit::IsRootNode() const
|
bool MacroConditionEdit::IsRootNode() const
|
||||||
@@ -166,7 +182,9 @@ void MacroConditionEdit::SetLogicSelection()
|
|||||||
const auto logic = (*_entryData)->GetLogicType();
|
const auto logic = (*_entryData)->GetLogicType();
|
||||||
_logicSelection->setCurrentIndex(
|
_logicSelection->setCurrentIndex(
|
||||||
_logicSelection->findData(static_cast<int>(logic)));
|
_logicSelection->findData(static_cast<int>(logic)));
|
||||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
const bool enabled = (*_entryData)->Enabled();
|
||||||
|
_enable->setChecked(enabled);
|
||||||
|
SetEnableAppearance(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionEdit::SetRootNode(bool root)
|
void MacroConditionEdit::SetRootNode(bool root)
|
||||||
@@ -204,7 +222,10 @@ void MacroConditionEdit::SetupWidgets(bool basicSetup)
|
|||||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||||
|
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
|
||||||
|
SLOT(ShowVariableMappings(bool)));
|
||||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||||
|
SetupVarMappings((*_entryData).get());
|
||||||
SetFocusPolicyOfWidgets();
|
SetFocusPolicyOfWidgets();
|
||||||
|
|
||||||
_allWidgetsAreSetup = true;
|
_allWidgetsAreSetup = true;
|
||||||
@@ -234,10 +255,12 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
|||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
auto logic = (*_entryData)->GetLogicType();
|
auto logic = (*_entryData)->GetLogicType();
|
||||||
|
const bool enabled = (*_entryData)->Enabled();
|
||||||
_entryData->reset();
|
_entryData->reset();
|
||||||
*_entryData = MacroConditionFactory::Create(id, macro);
|
*_entryData = MacroConditionFactory::Create(id, macro);
|
||||||
(*_entryData)->SetIndex(idx);
|
(*_entryData)->SetIndex(idx);
|
||||||
(*_entryData)->SetLogicType(logic);
|
(*_entryData)->SetLogicType(logic);
|
||||||
|
(*_entryData)->SetEnabled(enabled);
|
||||||
(*_entryData)->PostLoad();
|
(*_entryData)->PostLoad();
|
||||||
RunAndClearPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
}
|
}
|
||||||
@@ -245,7 +268,10 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
|||||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||||
|
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
|
||||||
|
SLOT(ShowVariableMappings(bool)));
|
||||||
_section->SetContent(widget);
|
_section->SetContent(widget);
|
||||||
|
SetupVarMappings((*_entryData).get());
|
||||||
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
|
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
|
||||||
SetFocusPolicyOfWidgets();
|
SetFocusPolicyOfWidgets();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
|
class SwitchButton;
|
||||||
|
|
||||||
class DurationModifierEdit : public QWidget {
|
class DurationModifierEdit : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@@ -47,11 +49,13 @@ private slots:
|
|||||||
void ConditionSelectionChanged(const QString &text);
|
void ConditionSelectionChanged(const QString &text);
|
||||||
void DurationChanged(const Duration &value);
|
void DurationChanged(const Duration &value);
|
||||||
void DurationModifierChanged(DurationModifier::Type m);
|
void DurationModifierChanged(DurationModifier::Type m);
|
||||||
|
void ConditionEnableChanged(bool);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetLogicSelection();
|
void SetLogicSelection();
|
||||||
std::shared_ptr<MacroSegment> Data() const;
|
std::shared_ptr<MacroSegment> Data() const;
|
||||||
|
|
||||||
|
SwitchButton *_enable;
|
||||||
QComboBox *_logicSelection;
|
QComboBox *_logicSelection;
|
||||||
FilterComboBox *_conditionSelection;
|
FilterComboBox *_conditionSelection;
|
||||||
DurationModifierEdit *_dur;
|
DurationModifierEdit *_dur;
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ const std::string MacroConditionTempVar::id = "temp_var";
|
|||||||
|
|
||||||
std::vector<TempVariableRef> MacroConditionTempVar::GetTempVarRefs() const
|
std::vector<TempVariableRef> MacroConditionTempVar::GetTempVarRefs() const
|
||||||
{
|
{
|
||||||
if (!_tempVar.HasValidID()) {
|
auto refs = MacroSegment::GetTempVarRefs();
|
||||||
return {};
|
if (_tempVar.HasValidID()) {
|
||||||
|
refs.push_back(_tempVar);
|
||||||
}
|
}
|
||||||
return {_tempVar};
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionTempVar::_registered = MacroConditionFactory::Register(
|
bool MacroConditionTempVar::_registered = MacroConditionFactory::Register(
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ bool MacroCondition::Load(obs_data_t *obj)
|
|||||||
{
|
{
|
||||||
MacroSegment::Load(obj);
|
MacroSegment::Load(obj);
|
||||||
_logic.Load(obj, "logic");
|
_logic.Load(obj, "logic");
|
||||||
|
if (_logic.GetType() == Logic::Type::NONE) {
|
||||||
|
SetEnabled(false);
|
||||||
|
_logic.SetType(Logic::Type::AND);
|
||||||
|
}
|
||||||
_durationModifier.Load(obj);
|
_durationModifier.Load(obj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -50,7 +54,8 @@ void MacroCondition::ValidateLogicSelection(bool isRootCondition,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logic.SetType(Logic::Type::NONE);
|
_logic.SetType(Logic::Type::AND);
|
||||||
|
SetEnabled(false);
|
||||||
blog(LOG_WARNING,
|
blog(LOG_WARNING,
|
||||||
"setting invalid logic selection to 'ignore' for macro %s",
|
"setting invalid logic selection to 'ignore' for macro %s",
|
||||||
context);
|
context);
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
#include "macro-segment.hpp"
|
#include "macro-segment.hpp"
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
#include "mouse-wheel-guard.hpp"
|
#include "mouse-wheel-guard.hpp"
|
||||||
|
#include "path-helpers.hpp"
|
||||||
#include "section.hpp"
|
#include "section.hpp"
|
||||||
#include "ui-helpers.hpp"
|
#include "ui-helpers.hpp"
|
||||||
|
#include "variable.hpp"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
@@ -15,7 +17,48 @@ namespace advss {
|
|||||||
|
|
||||||
std::vector<TempVariableRef> MacroSegment::GetTempVarRefs() const
|
std::vector<TempVariableRef> MacroSegment::GetTempVarRefs() const
|
||||||
{
|
{
|
||||||
return {};
|
std::vector<TempVariableRef> refs;
|
||||||
|
for (const auto &mapping : _varMappings) {
|
||||||
|
if (mapping.tempVar.HasValidID()) {
|
||||||
|
refs.push_back(mapping.tempVar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroSegment::ApplyVarMappings()
|
||||||
|
{
|
||||||
|
auto macro = GetMacro();
|
||||||
|
for (const auto &mapping : _varMappings) {
|
||||||
|
auto var = mapping.variable.lock();
|
||||||
|
if (!var) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto tempVar = mapping.tempVar.GetTempVariable(macro);
|
||||||
|
if (!tempVar) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto value = tempVar->Value();
|
||||||
|
if (!value) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var->SetValue(*value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<VarMapping> &MacroSegment::GetVarMappings() const
|
||||||
|
{
|
||||||
|
return _varMappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroSegment::SetVarMappings(const std::vector<VarMapping> &mappings)
|
||||||
|
{
|
||||||
|
_varMappings = mappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<TempVariable> MacroSegment::GetOwnTempVars() const
|
||||||
|
{
|
||||||
|
return _tempVariables;
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroSegment::MacroSegment(Macro *m, bool supportsVariableValue)
|
MacroSegment::MacroSegment(Macro *m, bool supportsVariableValue)
|
||||||
@@ -24,14 +67,32 @@ MacroSegment::MacroSegment(Macro *m, bool supportsVariableValue)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroSegment::SetVarMappingExpanded(bool expanded)
|
||||||
|
{
|
||||||
|
_varMappingExpanded = expanded;
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroSegment::Save(obs_data_t *obj) const
|
bool MacroSegment::Save(obs_data_t *obj) const
|
||||||
{
|
{
|
||||||
OBSDataAutoRelease data = obs_data_create();
|
OBSDataAutoRelease data = obs_data_create();
|
||||||
obs_data_set_bool(data, "collapsed", _collapsed);
|
obs_data_set_bool(data, "collapsed", _collapsed);
|
||||||
|
obs_data_set_bool(data, "varMappingExpanded", _varMappingExpanded);
|
||||||
obs_data_set_bool(data, "useCustomLabel", _useCustomLabel);
|
obs_data_set_bool(data, "useCustomLabel", _useCustomLabel);
|
||||||
obs_data_set_string(data, "customLabel", _customLabel.c_str());
|
obs_data_set_string(data, "customLabel", _customLabel.c_str());
|
||||||
obs_data_set_bool(data, "enabled", _enabled);
|
obs_data_set_bool(data, "enabled", _enabled);
|
||||||
obs_data_set_int(data, "version", 1);
|
obs_data_set_int(data, "version", 2);
|
||||||
|
|
||||||
|
OBSDataArrayAutoRelease mappingsArray = obs_data_array_create();
|
||||||
|
for (const auto &mapping : _varMappings) {
|
||||||
|
OBSDataAutoRelease item = obs_data_create();
|
||||||
|
mapping.tempVar.Save(item, GetMacro(), "tempVar");
|
||||||
|
obs_data_set_string(
|
||||||
|
item, "variable",
|
||||||
|
GetWeakVariableName(mapping.variable).c_str());
|
||||||
|
obs_data_array_push_back(mappingsArray, item);
|
||||||
|
}
|
||||||
|
obs_data_set_array(data, "varMappings", mappingsArray);
|
||||||
|
|
||||||
obs_data_set_obj(obj, "segmentSettings", data);
|
obs_data_set_obj(obj, "segmentSettings", data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -40,6 +101,7 @@ bool MacroSegment::Load(obs_data_t *obj)
|
|||||||
{
|
{
|
||||||
OBSDataAutoRelease data = obs_data_get_obj(obj, "segmentSettings");
|
OBSDataAutoRelease data = obs_data_get_obj(obj, "segmentSettings");
|
||||||
_collapsed = obs_data_get_bool(data, "collapsed");
|
_collapsed = obs_data_get_bool(data, "collapsed");
|
||||||
|
_varMappingExpanded = obs_data_get_bool(data, "varMappingExpanded");
|
||||||
_useCustomLabel = obs_data_get_bool(data, "useCustomLabel");
|
_useCustomLabel = obs_data_get_bool(data, "useCustomLabel");
|
||||||
_customLabel = obs_data_get_string(data, "customLabel");
|
_customLabel = obs_data_get_string(data, "customLabel");
|
||||||
obs_data_set_default_bool(data, "enabled", true);
|
obs_data_set_default_bool(data, "enabled", true);
|
||||||
@@ -50,6 +112,26 @@ bool MacroSegment::Load(obs_data_t *obj)
|
|||||||
_enabled = obs_data_get_bool(obj, "enabled");
|
_enabled = obs_data_get_bool(obj, "enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset the previously unused "enabled" value for conditions to "true"
|
||||||
|
if (obs_data_get_int(data, "version") < 2 &&
|
||||||
|
obs_data_has_user_value(obj, "logic")) {
|
||||||
|
_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_varMappings.clear();
|
||||||
|
OBSDataArrayAutoRelease mappingsArray =
|
||||||
|
obs_data_get_array(data, "varMappings");
|
||||||
|
const size_t count = obs_data_array_count(mappingsArray);
|
||||||
|
_varMappings.reserve(count);
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
OBSDataAutoRelease item = obs_data_array_item(mappingsArray, i);
|
||||||
|
VarMapping mapping;
|
||||||
|
mapping.variable = GetWeakVariableByName(
|
||||||
|
obs_data_get_string(item, "variable"));
|
||||||
|
_varMappings.push_back(std::move(mapping));
|
||||||
|
_varMappings.back().tempVar.Load(item, GetMacro(), "tempVar");
|
||||||
|
}
|
||||||
|
|
||||||
ClearAvailableTempvars();
|
ClearAvailableTempvars();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -167,24 +249,6 @@ bool MacroSegment::IsTempVarInUse(const std::string &id) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroSegment::CopyTempVarValuesFrom(const MacroSegment &other)
|
|
||||||
{
|
|
||||||
for (const auto &src : other._tempVariables) {
|
|
||||||
for (auto &dst : _tempVariables) {
|
|
||||||
if (dst.ID() != src.ID()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto value = src.Value();
|
|
||||||
if (value) {
|
|
||||||
dst.SetValue(*value);
|
|
||||||
} else {
|
|
||||||
dst.InvalidateValue();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroSegment::SetTempVarValue(const std::string &id,
|
void MacroSegment::SetTempVarValue(const std::string &id,
|
||||||
const std::string &value)
|
const std::string &value)
|
||||||
{
|
{
|
||||||
@@ -244,11 +308,38 @@ MacroSegmentEdit::MacroSegmentEdit(QWidget *parent)
|
|||||||
_headerInfo(new QLabel()),
|
_headerInfo(new QLabel()),
|
||||||
_frame(new QWidget),
|
_frame(new QWidget),
|
||||||
_contentLayout(new QVBoxLayout),
|
_contentLayout(new QVBoxLayout),
|
||||||
|
_outputMappings(new TempVarOutputMappingsWidget(this)),
|
||||||
|
_varMappingToggle(new QPushButton(this)),
|
||||||
_noBorderframe(new QFrame),
|
_noBorderframe(new QFrame),
|
||||||
_borderFrame(new QFrame),
|
_borderFrame(new QFrame),
|
||||||
_dropLineAbove(new QFrame),
|
_dropLineAbove(new QFrame),
|
||||||
_dropLineBelow(new QFrame)
|
_dropLineBelow(new QFrame)
|
||||||
{
|
{
|
||||||
|
const auto iconPath = QString::fromStdString(GetDataFilePath(
|
||||||
|
"res/images/" + GetThemeTypeName() + "Variable.svg"));
|
||||||
|
_varMappingToggle->setIcon(QIcon(iconPath));
|
||||||
|
_varMappingToggle->setMaximumWidth(22);
|
||||||
|
_varMappingToggle->setFlat(true);
|
||||||
|
_varMappingToggle->setCheckable(true);
|
||||||
|
_varMappingToggle->setVisible(false);
|
||||||
|
_varMappingToggle->setToolTip(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.outputMappings.toggle"));
|
||||||
|
|
||||||
|
QWidget::connect(_varMappingToggle, &QPushButton::toggled,
|
||||||
|
_outputMappings,
|
||||||
|
&TempVarOutputMappingsWidget::SetPanelExpanded);
|
||||||
|
QWidget::connect(_varMappingToggle, &QPushButton::toggled, this,
|
||||||
|
[this](bool checked) {
|
||||||
|
if (Data()) {
|
||||||
|
Data()->SetVarMappingExpanded(checked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
QWidget::connect(_outputMappings,
|
||||||
|
&TempVarOutputMappingsWidget::ExpandableChanged,
|
||||||
|
_varMappingToggle, &QPushButton::setVisible);
|
||||||
|
QWidget::connect(_section, &Section::Collapsed, _outputMappings,
|
||||||
|
&TempVarOutputMappingsWidget::SetSectionCollapsed);
|
||||||
|
|
||||||
_dropLineAbove->setLineWidth(3);
|
_dropLineAbove->setLineWidth(3);
|
||||||
_dropLineAbove->setFixedHeight(11);
|
_dropLineAbove->setFixedHeight(11);
|
||||||
_dropLineBelow->setLineWidth(3);
|
_dropLineBelow->setLineWidth(3);
|
||||||
@@ -310,6 +401,21 @@ MacroSegmentEdit::MacroSegmentEdit(QWidget *parent)
|
|||||||
_headerInfo->installEventFilter(this);
|
_headerInfo->installEventFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroSegmentEdit::SetupVarMappings(MacroSegment *segment)
|
||||||
|
{
|
||||||
|
_outputMappings->SetSegment(segment);
|
||||||
|
_varMappingToggle->setChecked(segment &&
|
||||||
|
segment->GetVarMappingExpanded());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroSegmentEdit::ShowVariableMappings(bool show)
|
||||||
|
{
|
||||||
|
_varMappingToggle->setChecked(show);
|
||||||
|
if (Data()) {
|
||||||
|
Data()->SetVarMappingExpanded(show);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroSegmentEdit::eventFilter(QObject *obj, QEvent *ev)
|
bool MacroSegmentEdit::eventFilter(QObject *obj, QEvent *ev)
|
||||||
{
|
{
|
||||||
if (obj == _headerInfo && ev->type() == QEvent::MouseMove) {
|
if (obj == _headerInfo && ev->type() == QEvent::MouseMove) {
|
||||||
|
|||||||
@@ -9,15 +9,23 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
|
#include <QPushButton>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <obs-data.h>
|
#include <obs-data.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
class Macro;
|
class Macro;
|
||||||
|
class Variable;
|
||||||
|
|
||||||
|
struct VarMapping {
|
||||||
|
TempVariableRef tempVar;
|
||||||
|
std::weak_ptr<Variable> variable;
|
||||||
|
};
|
||||||
|
|
||||||
class EXPORT MacroSegment : public Lockable {
|
class EXPORT MacroSegment : public Lockable {
|
||||||
public:
|
public:
|
||||||
@@ -28,6 +36,8 @@ public:
|
|||||||
int GetIndex() const { return _idx; }
|
int GetIndex() const { return _idx; }
|
||||||
void SetCollapsed(bool collapsed) { _collapsed = collapsed; }
|
void SetCollapsed(bool collapsed) { _collapsed = collapsed; }
|
||||||
bool GetCollapsed() const { return _collapsed; }
|
bool GetCollapsed() const { return _collapsed; }
|
||||||
|
void SetVarMappingExpanded(bool expanded);
|
||||||
|
bool GetVarMappingExpanded() const { return _varMappingExpanded; }
|
||||||
void SetUseCustomLabel(bool enable) { _useCustomLabel = enable; }
|
void SetUseCustomLabel(bool enable) { _useCustomLabel = enable; }
|
||||||
bool GetUseCustomLabel() const { return _useCustomLabel; }
|
bool GetUseCustomLabel() const { return _useCustomLabel; }
|
||||||
void SetCustomLabel(const std::string &label) { _customLabel = label; }
|
void SetCustomLabel(const std::string &label) { _customLabel = label; }
|
||||||
@@ -43,6 +53,10 @@ public:
|
|||||||
void SetEnabled(bool);
|
void SetEnabled(bool);
|
||||||
bool Enabled() const;
|
bool Enabled() const;
|
||||||
virtual std::string GetVariableValue() const;
|
virtual std::string GetVariableValue() const;
|
||||||
|
void ApplyVarMappings();
|
||||||
|
const std::vector<VarMapping> &GetVarMappings() const;
|
||||||
|
void SetVarMappings(const std::vector<VarMapping> &mappings);
|
||||||
|
std::vector<TempVariable> GetOwnTempVars() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend bool SupportsVariableValue(MacroSegment *);
|
friend bool SupportsVariableValue(MacroSegment *);
|
||||||
@@ -57,7 +71,6 @@ protected:
|
|||||||
|
|
||||||
bool IsTempVarInUse(const std::string &id) const;
|
bool IsTempVarInUse(const std::string &id) const;
|
||||||
void SetTempVarValue(const std::string &id, const std::string &value);
|
void SetTempVarValue(const std::string &id, const std::string &value);
|
||||||
void CopyTempVarValuesFrom(const MacroSegment &other);
|
|
||||||
|
|
||||||
template<typename T, typename = std::enable_if_t<
|
template<typename T, typename = std::enable_if_t<
|
||||||
std::is_same<std::decay_t<T>, bool>::value>>
|
std::is_same<std::decay_t<T>, bool>::value>>
|
||||||
@@ -88,6 +101,7 @@ private:
|
|||||||
// UI helper
|
// UI helper
|
||||||
bool _highlight = false;
|
bool _highlight = false;
|
||||||
bool _collapsed = false;
|
bool _collapsed = false;
|
||||||
|
bool _varMappingExpanded = false;
|
||||||
bool _enabled = true;
|
bool _enabled = true;
|
||||||
|
|
||||||
// Custom header labels
|
// Custom header labels
|
||||||
@@ -100,6 +114,7 @@ private:
|
|||||||
int _variableRefs = 0;
|
int _variableRefs = 0;
|
||||||
std::string _variableValue;
|
std::string _variableValue;
|
||||||
std::vector<TempVariable> _tempVariables;
|
std::vector<TempVariable> _tempVariables;
|
||||||
|
std::vector<VarMapping> _varMappings;
|
||||||
|
|
||||||
friend class Macro;
|
friend class Macro;
|
||||||
};
|
};
|
||||||
@@ -119,8 +134,11 @@ public:
|
|||||||
virtual std::shared_ptr<MacroSegment> Data() const = 0;
|
virtual std::shared_ptr<MacroSegment> Data() const = 0;
|
||||||
virtual void SetupWidgets(bool basicSetup = false) = 0;
|
virtual void SetupWidgets(bool basicSetup = false) = 0;
|
||||||
|
|
||||||
|
void SetupVarMappings(MacroSegment *segment);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
void ShowVariableMappings(bool show);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void Collapsed(bool) const;
|
void Collapsed(bool) const;
|
||||||
@@ -135,6 +153,8 @@ protected:
|
|||||||
QLabel *_headerInfo;
|
QLabel *_headerInfo;
|
||||||
QWidget *_frame;
|
QWidget *_frame;
|
||||||
QVBoxLayout *_contentLayout;
|
QVBoxLayout *_contentLayout;
|
||||||
|
TempVarOutputMappingsWidget *_outputMappings;
|
||||||
|
QPushButton *_varMappingToggle;
|
||||||
bool _allWidgetsAreSetup = false;
|
bool _allWidgetsAreSetup = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -557,6 +557,10 @@ void AdvSceneSwitcher::HighlightOnChange() const
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (macro->Paused()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (macro->ActionTriggerModePreventedActionsSince(
|
if (macro->ActionTriggerModePreventedActionsSince(
|
||||||
lastOnChangeHighlightCheckTime)) {
|
lastOnChangeHighlightCheckTime)) {
|
||||||
HighlightWidget(ui->actionTriggerMode, Qt::yellow,
|
HighlightWidget(ui->actionTriggerMode, Qt::yellow,
|
||||||
|
|||||||
@@ -17,6 +17,17 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
|
static bool setup()
|
||||||
|
{
|
||||||
|
AddPluginCleanupStep([]() {
|
||||||
|
GetTopLevelMacros().clear();
|
||||||
|
GetTemporaryMacros().clear();
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setupDone = setup();
|
||||||
|
|
||||||
Macro::Macro(const std::string &name) : _dockSettings(this)
|
Macro::Macro(const std::string &name) : _dockSettings(this)
|
||||||
{
|
{
|
||||||
SetName(name);
|
SetName(name);
|
||||||
@@ -113,6 +124,7 @@ static bool checkCondition(const std::shared_ptr<MacroCondition> &condition)
|
|||||||
condition->WithLock([&condition, &conditionMatched]() {
|
condition->WithLock([&condition, &conditionMatched]() {
|
||||||
conditionMatched = condition->EvaluateCondition();
|
conditionMatched = condition->EvaluateCondition();
|
||||||
});
|
});
|
||||||
|
condition->ApplyVarMappings();
|
||||||
const auto endTime = std::chrono::high_resolution_clock::now();
|
const auto endTime = std::chrono::high_resolution_clock::now();
|
||||||
const auto timeSpent = endTime - startTime;
|
const auto timeSpent = endTime - startTime;
|
||||||
|
|
||||||
@@ -145,6 +157,15 @@ bool Macro::CheckConditionHelper(
|
|||||||
return conditionMatched;
|
return conditionMatched;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!condition->Enabled()) {
|
||||||
|
vblog(LOG_INFO, "ignoring condition '%s' for '%s'",
|
||||||
|
condition->GetId().c_str(), _name.c_str());
|
||||||
|
if (!_useShortCircuitEvaluation) {
|
||||||
|
(void)evaluateCondition();
|
||||||
|
}
|
||||||
|
return _matched;
|
||||||
|
}
|
||||||
|
|
||||||
const auto logicType = condition->GetLogicType();
|
const auto logicType = condition->GetLogicType();
|
||||||
if (logicType == Logic::Type::NONE) {
|
if (logicType == Logic::Type::NONE) {
|
||||||
vblog(LOG_INFO, "ignoring condition '%s' for '%s'",
|
vblog(LOG_INFO, "ignoring condition '%s' for '%s'",
|
||||||
@@ -269,7 +290,7 @@ bool Macro::CheckConditions(bool ignorePause)
|
|||||||
|
|
||||||
const bool hasActionsToExecute = _matched ? (_actions.size() > 0)
|
const bool hasActionsToExecute = _matched ? (_actions.size() > 0)
|
||||||
: (_elseActions.size() > 0);
|
: (_elseActions.size() > 0);
|
||||||
if (!_actionModeMatch && hasActionsToExecute) {
|
if (!_actionModeMatch && hasActionsToExecute && !_paused) {
|
||||||
_lastActionRunModePreventTime =
|
_lastActionRunModePreventTime =
|
||||||
std::chrono::high_resolution_clock::now();
|
std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
@@ -368,7 +389,7 @@ bool Macro::ShouldRunActions() const
|
|||||||
!_paused && (_matched || _elseActions.size() > 0) &&
|
!_paused && (_matched || _elseActions.size() > 0) &&
|
||||||
_actionModeMatch;
|
_actionModeMatch;
|
||||||
|
|
||||||
if (VerboseLoggingEnabled() && !_actionModeMatch) {
|
if (VerboseLoggingEnabled() && !_actionModeMatch && !_paused) {
|
||||||
if (_matched && _actions.size() > 0) {
|
if (_matched && _actions.size() > 0) {
|
||||||
blog(LOG_INFO, "skip actions for Macro %s (on change)",
|
blog(LOG_INFO, "skip actions for Macro %s (on change)",
|
||||||
_name.c_str());
|
_name.c_str());
|
||||||
@@ -428,14 +449,11 @@ bool Macro::RunActionsHelper(
|
|||||||
}
|
}
|
||||||
if (action->Enabled()) {
|
if (action->Enabled()) {
|
||||||
action->LogAction();
|
action->LogAction();
|
||||||
std::shared_ptr<MacroAction> actionCopy;
|
bool actionResult = false;
|
||||||
action->WithLock([&action, &actionCopy]() {
|
action->WithLock([&action, &actionResult]() {
|
||||||
actionCopy = action->Copy();
|
actionResult = action->PerformAction();
|
||||||
});
|
|
||||||
bool actionResult = actionCopy->PerformAction();
|
|
||||||
action->WithLock([&action, &actionCopy]() {
|
|
||||||
action->CopyTempVarValuesFrom(*actionCopy);
|
|
||||||
});
|
});
|
||||||
|
action->ApplyVarMappings();
|
||||||
actionsExecutedSuccessfully =
|
actionsExecutedSuccessfully =
|
||||||
actionsExecutedSuccessfully && actionResult;
|
actionsExecutedSuccessfully && actionResult;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -14,10 +14,9 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
void GetWindowList(std::vector<std::string> &windows)
|
std::vector<std::string> GetWindowList()
|
||||||
{
|
{
|
||||||
windows.resize(0);
|
std::vector<std::string> windows;
|
||||||
|
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
CFArrayRef cfApps = CGWindowListCopyWindowInfo(
|
CFArrayRef cfApps = CGWindowListCopyWindowInfo(
|
||||||
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||||
@@ -49,21 +48,12 @@ void GetWindowList(std::vector<std::string> &windows)
|
|||||||
apps = nil;
|
apps = nil;
|
||||||
CFRelease(cfApps);
|
CFRelease(cfApps);
|
||||||
}
|
}
|
||||||
|
return windows;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetWindowList(QStringList &windows)
|
std::string GetCurrentWindowTitle()
|
||||||
{
|
{
|
||||||
windows.clear();
|
std::string title;
|
||||||
std::vector<std::string> temp;
|
|
||||||
GetWindowList(temp);
|
|
||||||
for (auto &w : temp) {
|
|
||||||
windows << QString::fromStdString(w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetCurrentWindowTitle(std::string &title)
|
|
||||||
{
|
|
||||||
title.resize(0);
|
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
CFArrayRef cfApps = CGWindowListCopyWindowInfo(
|
CFArrayRef cfApps = CGWindowListCopyWindowInfo(
|
||||||
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||||
@@ -107,6 +97,7 @@ void GetCurrentWindowTitle(std::string &title)
|
|||||||
apps = nil;
|
apps = nil;
|
||||||
CFRelease(cfApps);
|
CFRelease(cfApps);
|
||||||
}
|
}
|
||||||
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isWindowOriginOnScreen(NSDictionary *app, NSScreen *screen,
|
bool isWindowOriginOnScreen(NSDictionary *app, NSScreen *screen,
|
||||||
@@ -273,9 +264,9 @@ int SecondsSinceLastInput()
|
|||||||
return (int)time;
|
return (int)time;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetProcessList(QStringList &list)
|
QStringList GetProcessList()
|
||||||
{
|
{
|
||||||
list.clear();
|
QStringList list;
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||||
NSArray *array = [ws runningApplications];
|
NSArray *array = [ws runningApplications];
|
||||||
@@ -291,11 +282,11 @@ void GetProcessList(QStringList &list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetForegroundProcessName(std::string &proc)
|
std::string GetForegroundProcessName()
|
||||||
{
|
{
|
||||||
proc.resize(0);
|
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||||
NSArray *array = [ws runningApplications];
|
NSArray *array = [ws runningApplications];
|
||||||
@@ -308,23 +299,73 @@ void GetForegroundProcessName(std::string &proc)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const char *str = name.UTF8String;
|
const char *str = name.UTF8String;
|
||||||
proc = std::string(str);
|
if (str) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetForegroundProcessName(QString &proc)
|
std::string GetForegroundProcessPath()
|
||||||
{
|
{
|
||||||
std::string temp;
|
@autoreleasepool {
|
||||||
GetForegroundProcessName(temp);
|
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||||
proc = QString::fromStdString(temp);
|
for (NSRunningApplication *app in [ws runningApplications]) {
|
||||||
|
if (!app.isActive) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NSURL *url = app.executableURL;
|
||||||
|
if (!url) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const char *str = url.path.UTF8String;
|
||||||
|
if (str) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList GetProcessPathsFromName(const QString &name)
|
||||||
|
{
|
||||||
|
QStringList paths;
|
||||||
|
@autoreleasepool {
|
||||||
|
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||||
|
for (NSRunningApplication *app in [ws runningApplications]) {
|
||||||
|
NSString *appName = app.localizedName;
|
||||||
|
if (!appName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const char *nameStr = appName.UTF8String;
|
||||||
|
if (!nameStr ||
|
||||||
|
name != QString::fromUtf8(nameStr)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NSURL *url = app.executableURL;
|
||||||
|
if (!url) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const char *pathStr = url.path.UTF8String;
|
||||||
|
if (!pathStr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
QString path = QString::fromUtf8(pathStr);
|
||||||
|
if (!paths.contains(path)) {
|
||||||
|
paths.append(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInFocus(const QString &executable)
|
bool IsInFocus(const QString &executable)
|
||||||
{
|
{
|
||||||
std::string current;
|
const auto current = GetForegroundProcessName();
|
||||||
GetForegroundProcessName(current);
|
|
||||||
|
|
||||||
// True if executable switch equals current window
|
// True if executable switch equals current window
|
||||||
bool equals = (executable.toStdString() == current);
|
bool equals = (executable.toStdString() == current);
|
||||||
|
|||||||
@@ -11,15 +11,16 @@ namespace advss {
|
|||||||
|
|
||||||
enum class HotkeyType;
|
enum class HotkeyType;
|
||||||
|
|
||||||
EXPORT void GetWindowList(std::vector<std::string> &windows);
|
EXPORT std::vector<std::string> GetWindowList();
|
||||||
EXPORT void GetWindowList(QStringList &windows);
|
EXPORT std::string GetCurrentWindowTitle();
|
||||||
EXPORT void GetCurrentWindowTitle(std::string &title);
|
|
||||||
EXPORT bool IsFullscreen(const std::string &title);
|
EXPORT bool IsFullscreen(const std::string &title);
|
||||||
EXPORT bool IsMaximized(const std::string &title);
|
EXPORT bool IsMaximized(const std::string &title);
|
||||||
EXPORT std::optional<std::string> GetTextInWindow(const std::string &window);
|
EXPORT std::optional<std::string> GetTextInWindow(const std::string &window);
|
||||||
EXPORT int SecondsSinceLastInput();
|
EXPORT int SecondsSinceLastInput();
|
||||||
EXPORT void GetProcessList(QStringList &processes);
|
EXPORT QStringList GetProcessList();
|
||||||
EXPORT void GetForegroundProcessName(std::string &name);
|
EXPORT std::string GetForegroundProcessName();
|
||||||
|
EXPORT std::string GetForegroundProcessPath();
|
||||||
|
EXPORT QStringList GetProcessPathsFromName(const QString &name);
|
||||||
EXPORT bool IsInFocus(const QString &executable);
|
EXPORT bool IsInFocus(const QString &executable);
|
||||||
void PlatformInit();
|
void PlatformInit();
|
||||||
void PlatformCleanup();
|
void PlatformCleanup();
|
||||||
|
|||||||
@@ -16,14 +16,17 @@ static void setupTab(QTabWidget *);
|
|||||||
|
|
||||||
static ActionQueueTable *tabWidget = nullptr;
|
static ActionQueueTable *tabWidget = nullptr;
|
||||||
|
|
||||||
void RegisterActionQueueTab()
|
static bool setup()
|
||||||
{
|
{
|
||||||
AddPluginInitStep([]() {
|
AddPluginInitStep([] {
|
||||||
AddSetupTabCallback("actionQueueTab", ActionQueueTable::Create,
|
AddSetupTabCallback("actionQueueTab", ActionQueueTable::Create,
|
||||||
setupTab);
|
setupTab);
|
||||||
});
|
});
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool setupDone = setup();
|
||||||
|
|
||||||
static void setTabVisible(QTabWidget *tabWidget, bool visible)
|
static void setTabVisible(QTabWidget *tabWidget, bool visible)
|
||||||
{
|
{
|
||||||
SetTabVisibleByName(
|
SetTabVisibleByName(
|
||||||
|
|||||||
@@ -12,20 +12,16 @@ std::deque<std::shared_ptr<Item>> &GetActionQueues()
|
|||||||
return queues;
|
return queues;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterActionQueueTab();
|
static bool setup()
|
||||||
|
|
||||||
void SetupActionQueues()
|
|
||||||
{
|
{
|
||||||
static bool done = false;
|
|
||||||
if (done) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AddSaveStep(SaveActionQueues);
|
AddSaveStep(SaveActionQueues);
|
||||||
AddLoadStep(LoadActionQueues);
|
AddLoadStep(LoadActionQueues);
|
||||||
RegisterActionQueueTab();
|
AddPluginCleanupStep([]() { queues.clear(); });
|
||||||
done = true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool setupDone = setup();
|
||||||
|
|
||||||
ActionQueue::ActionQueue() : Item()
|
ActionQueue::ActionQueue() : Item()
|
||||||
{
|
{
|
||||||
_lastEmpty = std::chrono::high_resolution_clock::now();
|
_lastEmpty = std::chrono::high_resolution_clock::now();
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ signals:
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::deque<std::shared_ptr<Item>> &GetActionQueues();
|
std::deque<std::shared_ptr<Item>> &GetActionQueues();
|
||||||
void SetupActionQueues();
|
|
||||||
void SaveActionQueues(obs_data_t *);
|
void SaveActionQueues(obs_data_t *);
|
||||||
void LoadActionQueues(obs_data_t *);
|
void LoadActionQueues(obs_data_t *);
|
||||||
void ImportQueues(obs_data_t *);
|
void ImportQueues(obs_data_t *);
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
const std::map<Logic::Type, const char *> Logic::localeMap = {
|
const std::map<Logic::Type, const char *> Logic::localeMap = {
|
||||||
{Logic::Type::NONE, {"AdvSceneSwitcher.logic.none"}},
|
|
||||||
{Logic::Type::AND, {"AdvSceneSwitcher.logic.and"}},
|
{Logic::Type::AND, {"AdvSceneSwitcher.logic.and"}},
|
||||||
{Logic::Type::OR, {"AdvSceneSwitcher.logic.or"}},
|
{Logic::Type::OR, {"AdvSceneSwitcher.logic.or"}},
|
||||||
{Logic::Type::AND_NOT, {"AdvSceneSwitcher.logic.andNot"}},
|
{Logic::Type::AND_NOT, {"AdvSceneSwitcher.logic.andNot"}},
|
||||||
@@ -67,7 +66,7 @@ void Logic::PopulateLogicTypeSelection(QComboBox *list, bool isRootCondition)
|
|||||||
return typeValue < rootOffset;
|
return typeValue < rootOffset;
|
||||||
}}
|
}}
|
||||||
: std::function<bool(int)>{[](int typeValue) {
|
: std::function<bool(int)>{[](int typeValue) {
|
||||||
return typeValue >= rootOffset;
|
return typeValue > rootOffset;
|
||||||
}};
|
}};
|
||||||
for (const auto &[type, name] : localeMap) {
|
for (const auto &[type, name] : localeMap) {
|
||||||
const int typeValue = static_cast<int>(type);
|
const int typeValue = static_cast<int>(type);
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ static constexpr bool handleUncleanShutdown = true;
|
|||||||
static bool wasCleanShutdown = false;
|
static bool wasCleanShutdown = false;
|
||||||
static bool suppressCrashDialog = false;
|
static bool suppressCrashDialog = false;
|
||||||
|
|
||||||
|
static char *sentinelFile = nullptr;
|
||||||
|
|
||||||
bool GetSuppressCrashDialog()
|
bool GetSuppressCrashDialog()
|
||||||
{
|
{
|
||||||
return suppressCrashDialog;
|
return suppressCrashDialog;
|
||||||
@@ -58,7 +60,6 @@ static void handleShutdown(enum obs_frontend_event event, void *)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *sentinelFile = obs_module_config_path(sentinel.data());
|
|
||||||
if (!sentinelFile) {
|
if (!sentinelFile) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -78,7 +79,8 @@ static void handleShutdown(enum obs_frontend_event event, void *)
|
|||||||
|
|
||||||
static void setup()
|
static void setup()
|
||||||
{
|
{
|
||||||
char *sentinelFile = obs_module_config_path(sentinel.data());
|
// Freed in handleShutdown()
|
||||||
|
sentinelFile = obs_module_config_path(sentinel.data());
|
||||||
if (!sentinelFile) {
|
if (!sentinelFile) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -106,7 +108,6 @@ static void setup()
|
|||||||
|
|
||||||
file.write("running");
|
file.write("running");
|
||||||
file.close();
|
file.close();
|
||||||
bfree(sentinelFile);
|
|
||||||
|
|
||||||
obs_frontend_add_event_callback(handleShutdown, nullptr);
|
obs_frontend_add_event_callback(handleShutdown, nullptr);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -55,9 +55,7 @@ static void WriteFirstRun(bool value)
|
|||||||
|
|
||||||
static QString DetectFocusedWindow()
|
static QString DetectFocusedWindow()
|
||||||
{
|
{
|
||||||
std::string title;
|
return QString::fromStdString(GetCurrentWindowTitle());
|
||||||
GetCurrentWindowTitle(title);
|
|
||||||
return QString::fromStdString(title);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|||||||
@@ -75,6 +75,18 @@ static std::vector<std::function<void()>> &getStopSteps()
|
|||||||
return steps;
|
return steps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<std::function<void(obs_data_t *)>> &getEarlySaveSteps()
|
||||||
|
{
|
||||||
|
static std::vector<std::function<void(obs_data_t *)>> steps;
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::function<void(obs_data_t *)>> &getEarlyLoadSteps()
|
||||||
|
{
|
||||||
|
static std::vector<std::function<void(obs_data_t *)>> steps;
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
static std::vector<std::function<void(obs_data_t *)>> &getSaveSteps()
|
static std::vector<std::function<void(obs_data_t *)>> &getSaveSteps()
|
||||||
{
|
{
|
||||||
static std::vector<std::function<void(obs_data_t *)>> steps;
|
static std::vector<std::function<void(obs_data_t *)>> steps;
|
||||||
@@ -109,6 +121,18 @@ void LoadPluginSettings(obs_data_t *obj)
|
|||||||
GetSwitcher()->LoadSettings(obj);
|
GetSwitcher()->LoadSettings(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddEarlySaveStep(std::function<void(obs_data_t *)> step)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
getEarlySaveSteps().emplace_back(step);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddEarlyLoadStep(std::function<void(obs_data_t *)> step)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
getEarlyLoadSteps().emplace_back(step);
|
||||||
|
}
|
||||||
|
|
||||||
void AddSaveStep(std::function<void(obs_data_t *)> step)
|
void AddSaveStep(std::function<void(obs_data_t *)> step)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
@@ -136,6 +160,9 @@ void AddIntervalResetStep(std::function<void()> step)
|
|||||||
void RunSaveSteps(obs_data_t *obj)
|
void RunSaveSteps(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
for (const auto &func : getEarlySaveSteps()) {
|
||||||
|
func(obj);
|
||||||
|
}
|
||||||
for (const auto &func : getSaveSteps()) {
|
for (const auto &func : getSaveSteps()) {
|
||||||
func(obj);
|
func(obj);
|
||||||
}
|
}
|
||||||
@@ -144,6 +171,9 @@ void RunSaveSteps(obs_data_t *obj)
|
|||||||
void RunLoadSteps(obs_data_t *obj)
|
void RunLoadSteps(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
for (const auto &func : getEarlyLoadSteps()) {
|
||||||
|
func(obj);
|
||||||
|
}
|
||||||
for (const auto &func : getLoadSteps()) {
|
for (const auto &func : getLoadSteps()) {
|
||||||
func(obj);
|
func(obj);
|
||||||
}
|
}
|
||||||
@@ -310,7 +340,7 @@ bool HighlightUIElementsEnabled()
|
|||||||
|
|
||||||
bool OBSIsShuttingDown()
|
bool OBSIsShuttingDown()
|
||||||
{
|
{
|
||||||
return GetSwitcher() && GetSwitcher()->obsIsShuttingDown;
|
return !GetSwitcher() || GetSwitcher()->obsIsShuttingDown;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InitialLoadIsComplete()
|
bool InitialLoadIsComplete()
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ namespace advss {
|
|||||||
void SavePluginSettings(obs_data_t *);
|
void SavePluginSettings(obs_data_t *);
|
||||||
EXPORT void LoadPluginSettings(obs_data_t *);
|
EXPORT void LoadPluginSettings(obs_data_t *);
|
||||||
|
|
||||||
|
void AddEarlySaveStep(std::function<void(obs_data_t *)>);
|
||||||
|
void AddEarlyLoadStep(std::function<void(obs_data_t *)>);
|
||||||
EXPORT void AddSaveStep(std::function<void(obs_data_t *)>);
|
EXPORT void AddSaveStep(std::function<void(obs_data_t *)>);
|
||||||
EXPORT void AddLoadStep(std::function<void(obs_data_t *)>);
|
EXPORT void AddLoadStep(std::function<void(obs_data_t *)>);
|
||||||
EXPORT void AddPostLoadStep(std::function<void()>);
|
EXPORT void AddPostLoadStep(std::function<void()>);
|
||||||
|
|||||||
@@ -173,10 +173,9 @@ void PopulateTransitionSelection(QComboBox *sel, bool addCurrent, bool addAny,
|
|||||||
void PopulateWindowSelection(QComboBox *sel, bool addSelect)
|
void PopulateWindowSelection(QComboBox *sel, bool addSelect)
|
||||||
{
|
{
|
||||||
|
|
||||||
std::vector<std::string> windows;
|
const auto windows = GetWindowList();
|
||||||
GetWindowList(windows);
|
|
||||||
|
|
||||||
for (std::string &window : windows) {
|
for (const std::string &window : windows) {
|
||||||
sel->addItem(window.c_str());
|
sel->addItem(window.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,8 +256,7 @@ void PopulateMediaSelection(QComboBox *sel, bool addSelect)
|
|||||||
|
|
||||||
void PopulateProcessSelection(QComboBox *sel, bool addSelect)
|
void PopulateProcessSelection(QComboBox *sel, bool addSelect)
|
||||||
{
|
{
|
||||||
QStringList processes;
|
auto processes = GetProcessList();
|
||||||
GetProcessList(processes);
|
|
||||||
processes.sort();
|
processes.sort();
|
||||||
for (QString &process : processes) {
|
for (QString &process : processes) {
|
||||||
sel->addItem(process);
|
sel->addItem(process);
|
||||||
|
|||||||
@@ -66,4 +66,15 @@ void Lockable::WithLock(const std::function<void()> &func)
|
|||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SuspendLock::SuspendLock(Lockable &lockable)
|
||||||
|
: _mtx(static_cast<std::mutex &>(lockable._mtx))
|
||||||
|
{
|
||||||
|
_mtx.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
SuspendLock::~SuspendLock()
|
||||||
|
{
|
||||||
|
_mtx.lock();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -51,6 +51,24 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
PerInstanceMutex _mtx;
|
PerInstanceMutex _mtx;
|
||||||
|
|
||||||
|
friend class SuspendLock;
|
||||||
|
};
|
||||||
|
|
||||||
|
// RAII guard that temporarily releases a Lockable's per-segment lock.
|
||||||
|
// Use this inside PerformAction() / CheckCondition() to unblock the UI
|
||||||
|
// during long-running operations while still running on the original segment.
|
||||||
|
// The caller MUST be holding the lock (i.e. be inside WithLock) when
|
||||||
|
// constructing this object; the lock is re-acquired on destruction.
|
||||||
|
class EXPORT SuspendLock {
|
||||||
|
public:
|
||||||
|
SuspendLock(Lockable &lockable);
|
||||||
|
~SuspendLock();
|
||||||
|
SuspendLock(const SuspendLock &) = delete;
|
||||||
|
SuspendLock &operator=(const SuspendLock &) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::mutex &_mtx;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -5,11 +5,20 @@
|
|||||||
#include "macro-edit.hpp"
|
#include "macro-edit.hpp"
|
||||||
#include "macro-segment.hpp"
|
#include "macro-segment.hpp"
|
||||||
#include "plugin-state-helpers.hpp"
|
#include "plugin-state-helpers.hpp"
|
||||||
|
#include "sync-helpers.hpp"
|
||||||
#include "ui-helpers.hpp"
|
#include "ui-helpers.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
#include "variable.hpp"
|
||||||
|
|
||||||
#include <QVariant>
|
|
||||||
#include <QAbstractItemView>
|
#include <QAbstractItemView>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPropertyAnimation>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(advss::TempVariableRef);
|
Q_DECLARE_METATYPE(advss::TempVariableRef);
|
||||||
@@ -731,4 +740,293 @@ void NotifyUIAboutTempVarChange(MacroSegment *segment)
|
|||||||
segment);
|
segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TempVarOutputMappingsWidget::TempVarOutputMappingsWidget(QWidget *parent)
|
||||||
|
: QWidget(parent),
|
||||||
|
_rowsLayout(new QVBoxLayout()),
|
||||||
|
_addButton(new QPushButton(
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.outputMappings.add"),
|
||||||
|
this)),
|
||||||
|
_animation(new QPropertyAnimation(this, "maximumHeight", this))
|
||||||
|
{
|
||||||
|
_rowsLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_rowsLayout->setSpacing(2);
|
||||||
|
auto rowsContainer = new QWidget(this);
|
||||||
|
rowsContainer->setLayout(_rowsLayout);
|
||||||
|
|
||||||
|
auto label = new QLabel(
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.outputMappings"),
|
||||||
|
this);
|
||||||
|
|
||||||
|
auto mainLayout = new QVBoxLayout();
|
||||||
|
mainLayout->addWidget(label);
|
||||||
|
mainLayout->addWidget(rowsContainer);
|
||||||
|
mainLayout->addWidget(_addButton);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
_animation->setDuration(300);
|
||||||
|
_animation->setEasingCurve(QEasingCurve::InOutQuad);
|
||||||
|
connect(_animation, &QPropertyAnimation::finished, this,
|
||||||
|
&TempVarOutputMappingsWidget::AnimationFinished);
|
||||||
|
|
||||||
|
hide();
|
||||||
|
|
||||||
|
connect(_addButton, &QPushButton::clicked, this,
|
||||||
|
&TempVarOutputMappingsWidget::Add);
|
||||||
|
connect(TempVarSignalManager::Instance(),
|
||||||
|
SIGNAL(SegmentTempVarsChanged(MacroSegment *)), this,
|
||||||
|
SLOT(SegmentTempVarsChanged(MacroSegment *)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::SetSegment(MacroSegment *segment)
|
||||||
|
{
|
||||||
|
_segment = segment;
|
||||||
|
_panelExpanded = false;
|
||||||
|
Rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::Add()
|
||||||
|
{
|
||||||
|
if (!_segment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto mappings = _segment->GetVarMappings();
|
||||||
|
mappings.push_back(VarMapping{});
|
||||||
|
{
|
||||||
|
auto lock = LockContext();
|
||||||
|
_segment->SetVarMappings(mappings);
|
||||||
|
}
|
||||||
|
Rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::Remove(int rowIdx)
|
||||||
|
{
|
||||||
|
if (!_segment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto mappings = _segment->GetVarMappings();
|
||||||
|
if (rowIdx < 0 || rowIdx >= (int)mappings.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mappings.erase(mappings.begin() + rowIdx);
|
||||||
|
{
|
||||||
|
auto lock = LockContext();
|
||||||
|
_segment->SetVarMappings(mappings);
|
||||||
|
}
|
||||||
|
Rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::SegmentTempVarsChanged(MacroSegment *segment)
|
||||||
|
{
|
||||||
|
if (segment != _segment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Re-populate each temp var combobox in case temp vars were added/removed
|
||||||
|
_loading = true;
|
||||||
|
const auto &mappings = _segment->GetVarMappings();
|
||||||
|
for (int i = 0; i < (int)_rows.size(); i++) {
|
||||||
|
auto combo = _rows[i].tempVarCombo;
|
||||||
|
const QSignalBlocker blocker(combo);
|
||||||
|
combo->clear();
|
||||||
|
PopulateTempVarCombo(combo);
|
||||||
|
if (i < (int)mappings.size() &&
|
||||||
|
mappings[i].tempVar.HasValidID()) {
|
||||||
|
QVariant v;
|
||||||
|
v.setValue(mappings[i].tempVar);
|
||||||
|
combo->setCurrentIndex(combo->findData(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_loading = false;
|
||||||
|
UpdateVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::WriteBackMappings()
|
||||||
|
{
|
||||||
|
if (_loading || !_segment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::vector<VarMapping> mappings;
|
||||||
|
for (const auto &row : _rows) {
|
||||||
|
VarMapping m;
|
||||||
|
const int idx = row.tempVarCombo->currentIndex();
|
||||||
|
if (idx >= 0) {
|
||||||
|
m.tempVar = row.tempVarCombo->itemData(idx)
|
||||||
|
.value<TempVariableRef>();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto item = row.varSelection->GetCurrentItem();
|
||||||
|
if (!item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m.variable = GetWeakVariableByName(item->Name());
|
||||||
|
mappings.push_back(std::move(m));
|
||||||
|
}
|
||||||
|
auto lock = LockContext();
|
||||||
|
_segment->SetVarMappings(mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::Rebuild()
|
||||||
|
{
|
||||||
|
_loading = true;
|
||||||
|
|
||||||
|
// Remove all existing row widgets from layout and delete them
|
||||||
|
for (auto &row : _rows) {
|
||||||
|
_rowsLayout->removeWidget(row.container);
|
||||||
|
delete row.container;
|
||||||
|
}
|
||||||
|
_rows.clear();
|
||||||
|
|
||||||
|
if (!_segment) {
|
||||||
|
_loading = false;
|
||||||
|
UpdateVisibility();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &mappings = _segment->GetVarMappings();
|
||||||
|
for (int i = 0; i < (int)mappings.size(); i++) {
|
||||||
|
const auto &mapping = mappings[i];
|
||||||
|
|
||||||
|
auto container = new QWidget(this);
|
||||||
|
auto rowLayout = new QHBoxLayout();
|
||||||
|
rowLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
auto tempVarCombo = new FilterComboBox(
|
||||||
|
container,
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.select"));
|
||||||
|
tempVarCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||||
|
tempVarCombo->setMaximumWidth(350);
|
||||||
|
tempVarCombo->setDuplicatesEnabled(true);
|
||||||
|
PopulateTempVarCombo(tempVarCombo);
|
||||||
|
if (mapping.tempVar.HasValidID()) {
|
||||||
|
QVariant v;
|
||||||
|
v.setValue(mapping.tempVar);
|
||||||
|
tempVarCombo->setCurrentIndex(
|
||||||
|
tempVarCombo->findData(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto arrowLabel = new QLabel(container);
|
||||||
|
{
|
||||||
|
QIcon icon;
|
||||||
|
const auto path = (GetThemeTypeName() == "Light")
|
||||||
|
? "theme:Light/right.svg"
|
||||||
|
: "theme:Dark/right.svg";
|
||||||
|
icon.addFile(QString::fromUtf8(path), QSize(),
|
||||||
|
QIcon::Normal, QIcon::Off);
|
||||||
|
arrowLabel->setPixmap(icon.pixmap(16, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto varSel = new VariableSelection(container);
|
||||||
|
varSel->SetVariable(mapping.variable);
|
||||||
|
|
||||||
|
auto removeBtn = new QToolButton(container);
|
||||||
|
removeBtn->setProperty("themeID", QVariant(QString::fromUtf8(
|
||||||
|
"removeIconSmall")));
|
||||||
|
removeBtn->setProperty(
|
||||||
|
"class", QVariant(QString::fromUtf8("icon-trash")));
|
||||||
|
removeBtn->setToolTip(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.outputMappings.remove"));
|
||||||
|
|
||||||
|
rowLayout->addWidget(tempVarCombo, 1);
|
||||||
|
rowLayout->addWidget(arrowLabel);
|
||||||
|
rowLayout->addWidget(varSel, 1);
|
||||||
|
rowLayout->addWidget(removeBtn);
|
||||||
|
container->setLayout(rowLayout);
|
||||||
|
|
||||||
|
_rowsLayout->addWidget(container);
|
||||||
|
_rows.push_back({container, tempVarCombo, varSel});
|
||||||
|
|
||||||
|
const int capturedIdx = i;
|
||||||
|
connect(removeBtn, &QPushButton::clicked, this,
|
||||||
|
[this, capturedIdx]() { Remove(capturedIdx); });
|
||||||
|
connect(tempVarCombo,
|
||||||
|
QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||||
|
this, &TempVarOutputMappingsWidget::WriteBackMappings);
|
||||||
|
connect(varSel, &VariableSelection::SelectionChanged, this,
|
||||||
|
[this](const QString &) { WriteBackMappings(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
_loading = false;
|
||||||
|
UpdateVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TempVarOutputMappingsWidget::IsExpandable() const
|
||||||
|
{
|
||||||
|
return _segment && !_segment->GetOwnTempVars().empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::SetPanelExpanded(bool expanded)
|
||||||
|
{
|
||||||
|
_panelExpanded = expanded;
|
||||||
|
UpdateHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::SetSectionCollapsed(bool collapsed)
|
||||||
|
{
|
||||||
|
_sectionCollapsed = collapsed;
|
||||||
|
UpdateHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::AnimateTo(int targetHeight)
|
||||||
|
{
|
||||||
|
if (_animation->state() == QAbstractAnimation::Running) {
|
||||||
|
_animation->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetHeight > 0 && !isVisible()) {
|
||||||
|
setMinimumHeight(0);
|
||||||
|
setMaximumHeight(0);
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
const int currentMax = maximumHeight();
|
||||||
|
const int currentHeight = (currentMax >= QWIDGETSIZE_MAX) ? height()
|
||||||
|
: currentMax;
|
||||||
|
|
||||||
|
_animationTargetHeight = targetHeight;
|
||||||
|
_animation->setStartValue(currentHeight);
|
||||||
|
_animation->setEndValue(targetHeight);
|
||||||
|
_animation->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::AnimationFinished()
|
||||||
|
{
|
||||||
|
if (_animationTargetHeight > 0) {
|
||||||
|
setMaximumHeight(QWIDGETSIZE_MAX);
|
||||||
|
} else {
|
||||||
|
hide();
|
||||||
|
setMaximumHeight(QWIDGETSIZE_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::UpdateHeight()
|
||||||
|
{
|
||||||
|
const bool shouldShow = _panelExpanded && !_sectionCollapsed &&
|
||||||
|
IsExpandable();
|
||||||
|
if (shouldShow) {
|
||||||
|
AnimateTo(sizeHint().height());
|
||||||
|
} else {
|
||||||
|
AnimateTo(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::UpdateVisibility()
|
||||||
|
{
|
||||||
|
const bool expandable = IsExpandable();
|
||||||
|
emit ExpandableChanged(expandable);
|
||||||
|
UpdateHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TempVarOutputMappingsWidget::PopulateTempVarCombo(
|
||||||
|
FilterComboBox *combo) const
|
||||||
|
{
|
||||||
|
if (!_segment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const auto &var : _segment->GetOwnTempVars()) {
|
||||||
|
QVariant v;
|
||||||
|
v.setValue(var.GetRef());
|
||||||
|
combo->addItem(QString::fromStdString(var.Name()), v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -5,11 +5,12 @@
|
|||||||
#include <obs-data.h>
|
#include <obs-data.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <QEnterEvent>
|
|
||||||
#include <QEvent>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
class QPropertyAnimation;
|
||||||
|
class QPushButton;
|
||||||
|
class QVBoxLayout;
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
class Macro;
|
class Macro;
|
||||||
@@ -17,6 +18,9 @@ class MacroEdit;
|
|||||||
class MacroSegment;
|
class MacroSegment;
|
||||||
class TempVariableRef;
|
class TempVariableRef;
|
||||||
class TempVariableSelection;
|
class TempVariableSelection;
|
||||||
|
class TempVarOutputMappingsWidget;
|
||||||
|
class VariableSelection;
|
||||||
|
struct VarMapping;
|
||||||
|
|
||||||
// TempVariables are variables that are local to a given macro.
|
// TempVariables are variables that are local to a given macro.
|
||||||
// They can be created and used by macro segments.
|
// They can be created and used by macro segments.
|
||||||
@@ -127,4 +131,48 @@ private:
|
|||||||
void NotifyUIAboutTempVarChange(MacroSegment *);
|
void NotifyUIAboutTempVarChange(MacroSegment *);
|
||||||
EXPORT void IncrementTempVarInUseGeneration();
|
EXPORT void IncrementTempVarInUseGeneration();
|
||||||
|
|
||||||
|
class ADVSS_EXPORT TempVarOutputMappingsWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
TempVarOutputMappingsWidget(QWidget *parent);
|
||||||
|
void SetSegment(MacroSegment *segment);
|
||||||
|
void SetPanelExpanded(bool expanded);
|
||||||
|
void SetSectionCollapsed(bool collapsed);
|
||||||
|
bool IsExpandable() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void ExpandableChanged(bool);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void Add();
|
||||||
|
void Remove(int rowIdx);
|
||||||
|
void SegmentTempVarsChanged(MacroSegment *segment);
|
||||||
|
void WriteBackMappings();
|
||||||
|
void AnimationFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Rebuild();
|
||||||
|
void UpdateVisibility();
|
||||||
|
void UpdateHeight();
|
||||||
|
void AnimateTo(int targetHeight);
|
||||||
|
void PopulateTempVarCombo(FilterComboBox *combo) const;
|
||||||
|
|
||||||
|
struct MappingRow {
|
||||||
|
QWidget *container;
|
||||||
|
FilterComboBox *tempVarCombo;
|
||||||
|
VariableSelection *varSelection;
|
||||||
|
};
|
||||||
|
|
||||||
|
MacroSegment *_segment = nullptr;
|
||||||
|
QVBoxLayout *_rowsLayout;
|
||||||
|
QPushButton *_addButton;
|
||||||
|
std::vector<MappingRow> _rows;
|
||||||
|
bool _loading = false;
|
||||||
|
bool _panelExpanded = false;
|
||||||
|
bool _sectionCollapsed = false;
|
||||||
|
int _animationTargetHeight = 0;
|
||||||
|
QPropertyAnimation *_animation;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ static void load(obs_data_t *data)
|
|||||||
{
|
{
|
||||||
tabSettings.Load(data, "tabSettings");
|
tabSettings.Load(data, "tabSettings");
|
||||||
dockSettings.Load(data, "dockSettings");
|
dockSettings.Load(data, "dockSettings");
|
||||||
|
|
||||||
enableDock(obs_data_get_bool(data, "addVariablesDock"));
|
enableDock(obs_data_get_bool(data, "addVariablesDock"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
#include "variable.hpp"
|
#include "variable.hpp"
|
||||||
#include "math-helpers.hpp"
|
#include "math-helpers.hpp"
|
||||||
#include "obs-module-helper.hpp"
|
#include "obs-module-helper.hpp"
|
||||||
|
#include "plugin-state-helpers.hpp"
|
||||||
#include "ui-helpers.hpp"
|
#include "ui-helpers.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
|
#include <obs.hpp>
|
||||||
|
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -15,6 +18,15 @@ static std::deque<std::shared_ptr<Item>> variables;
|
|||||||
static std::mutex lastVariableChangeMutex;
|
static std::mutex lastVariableChangeMutex;
|
||||||
static std::chrono::high_resolution_clock::time_point lastVariableChange{};
|
static std::chrono::high_resolution_clock::time_point lastVariableChange{};
|
||||||
|
|
||||||
|
static bool setup()
|
||||||
|
{
|
||||||
|
AddEarlySaveStep(SaveVariables);
|
||||||
|
AddEarlyLoadStep(LoadVariables);
|
||||||
|
AddPluginCleanupStep([]() { variables.clear(); });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static bool setupDone = setup();
|
||||||
|
|
||||||
static void setLastVariableChangeTime()
|
static void setLastVariableChangeTime()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(lastVariableChangeMutex);
|
std::lock_guard<std::mutex> lock(lastVariableChangeMutex);
|
||||||
@@ -418,34 +430,31 @@ static bool variableWithNameExists(const std::string &name)
|
|||||||
|
|
||||||
void SaveVariables(obs_data_t *obj)
|
void SaveVariables(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
obs_data_array_t *variablesArray = obs_data_array_create();
|
OBSDataArrayAutoRelease variablesArray = obs_data_array_create();
|
||||||
for (const auto &v : variables) {
|
for (const auto &v : variables) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
OBSDataAutoRelease array_obj = obs_data_create();
|
||||||
v->Save(array_obj);
|
v->Save(array_obj);
|
||||||
obs_data_array_push_back(variablesArray, array_obj);
|
obs_data_array_push_back(variablesArray, array_obj);
|
||||||
obs_data_release(array_obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_data_set_array(obj, "variables", variablesArray);
|
obs_data_set_array(obj, "variables", variablesArray);
|
||||||
obs_data_array_release(variablesArray);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadVariables(obs_data_t *obj)
|
void LoadVariables(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
variables.clear();
|
variables.clear();
|
||||||
|
|
||||||
obs_data_array_t *variablesArray = obs_data_get_array(obj, "variables");
|
OBSDataArrayAutoRelease variablesArray =
|
||||||
|
obs_data_get_array(obj, "variables");
|
||||||
size_t count = obs_data_array_count(variablesArray);
|
size_t count = obs_data_array_count(variablesArray);
|
||||||
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
obs_data_t *array_obj = obs_data_array_item(variablesArray, i);
|
OBSDataAutoRelease array_obj =
|
||||||
|
obs_data_array_item(variablesArray, i);
|
||||||
auto var = Variable::Create();
|
auto var = Variable::Create();
|
||||||
variables.emplace_back(var);
|
variables.emplace_back(var);
|
||||||
variables.back()->Load(array_obj);
|
variables.back()->Load(array_obj);
|
||||||
obs_data_release(array_obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_data_array_release(variablesArray);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signalImportedVariables(void *varsPtr)
|
static void signalImportedVariables(void *varsPtr)
|
||||||
@@ -460,16 +469,15 @@ static void signalImportedVariables(void *varsPtr)
|
|||||||
|
|
||||||
void ImportVariables(obs_data_t *data)
|
void ImportVariables(obs_data_t *data)
|
||||||
{
|
{
|
||||||
obs_data_array_t *array = obs_data_get_array(data, "variables");
|
OBSDataArrayAutoRelease array = obs_data_get_array(data, "variables");
|
||||||
size_t count = obs_data_array_count(array);
|
size_t count = obs_data_array_count(array);
|
||||||
|
|
||||||
auto importedVars = new std::vector<std::shared_ptr<Item>>;
|
auto importedVars = new std::vector<std::shared_ptr<Item>>;
|
||||||
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
obs_data_t *arrayElement = obs_data_array_item(array, i);
|
OBSDataAutoRelease arrayElement = obs_data_array_item(array, i);
|
||||||
auto var = Variable::Create();
|
auto var = Variable::Create();
|
||||||
var->Load(arrayElement);
|
var->Load(arrayElement);
|
||||||
obs_data_release(arrayElement);
|
|
||||||
|
|
||||||
if (variableWithNameExists(var->Name())) {
|
if (variableWithNameExists(var->Name())) {
|
||||||
continue;
|
continue;
|
||||||
@@ -479,8 +487,6 @@ void ImportVariables(obs_data_t *data)
|
|||||||
importedVars->emplace_back(var);
|
importedVars->emplace_back(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_data_array_release(array);
|
|
||||||
|
|
||||||
QueueUITask(signalImportedVariables, importedVars);
|
QueueUITask(signalImportedVariables, importedVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
#include "platform-funcs.hpp"
|
#include "platform-funcs.hpp"
|
||||||
|
#include "plugin-state-helpers.hpp"
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <UIAutomation.h>
|
#include <UIAutomation.h>
|
||||||
#include <util/platform.h>
|
#include <util/platform.h>
|
||||||
#include <TlHelp32.h>
|
#include <TlHelp32.h>
|
||||||
#include <Psapi.h>
|
#include <Psapi.h>
|
||||||
|
#include <memory>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -16,6 +18,9 @@
|
|||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#define ADVSS_WIDEN_(x) L##x
|
||||||
|
#define ADVSS_WIDEN(x) ADVSS_WIDEN_(x)
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
#define MAX_SEARCH 1000
|
#define MAX_SEARCH 1000
|
||||||
@@ -133,9 +138,9 @@ const std::vector<std::string> getOBSWindows()
|
|||||||
return lastDoneHelper->windows;
|
return lastDoneHelper->windows;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetWindowList(std::vector<std::string> &windows)
|
std::vector<std::string> GetWindowList()
|
||||||
{
|
{
|
||||||
windows.resize(0);
|
std::vector<std::string> windows;
|
||||||
EnumWindowsWithMetro(GetTitleCB, reinterpret_cast<LPARAM>(&windows));
|
EnumWindowsWithMetro(GetTitleCB, reinterpret_cast<LPARAM>(&windows));
|
||||||
|
|
||||||
// Also add OBS windows
|
// Also add OBS windows
|
||||||
@@ -147,20 +152,10 @@ void GetWindowList(std::vector<std::string> &windows)
|
|||||||
|
|
||||||
// Add entry for OBS Studio itself - see GetCurrentWindowTitle()
|
// Add entry for OBS Studio itself - see GetCurrentWindowTitle()
|
||||||
windows.emplace_back("OBS");
|
windows.emplace_back("OBS");
|
||||||
|
return windows;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetWindowList(QStringList &windows)
|
std::string GetCurrentWindowTitle()
|
||||||
{
|
|
||||||
windows.clear();
|
|
||||||
|
|
||||||
std::vector<std::string> w;
|
|
||||||
GetWindowList(w);
|
|
||||||
for (auto window : w) {
|
|
||||||
windows << QString::fromStdString(window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetCurrentWindowTitle(std::string &title)
|
|
||||||
{
|
{
|
||||||
HWND window = GetForegroundWindow();
|
HWND window = GetForegroundWindow();
|
||||||
DWORD pid;
|
DWORD pid;
|
||||||
@@ -178,15 +173,15 @@ void GetCurrentWindowTitle(std::string &title)
|
|||||||
//
|
//
|
||||||
// So instead rely on Qt to get the title of the active window.
|
// So instead rely on Qt to get the title of the active window.
|
||||||
if (GetCurrentProcessId() == pid) {
|
if (GetCurrentProcessId() == pid) {
|
||||||
auto window = QApplication::activeWindow();
|
auto obsWindow = QApplication::activeWindow();
|
||||||
if (window) {
|
if (obsWindow) {
|
||||||
title = window->windowTitle().toStdString();
|
return obsWindow->windowTitle().toStdString();
|
||||||
} else {
|
|
||||||
title = "OBS";
|
|
||||||
}
|
}
|
||||||
return;
|
return "OBS";
|
||||||
}
|
}
|
||||||
|
std::string title;
|
||||||
GetWindowTitle(window, title);
|
GetWindowTitle(window, title);
|
||||||
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HWND getHWNDfromTitle(const std::string &title)
|
static HWND getHWNDfromTitle(const std::string &title)
|
||||||
@@ -350,22 +345,22 @@ bool IsFullscreen(const std::string &title)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetProcessList(QStringList &processes)
|
QStringList GetProcessList()
|
||||||
{
|
{
|
||||||
|
QStringList processes;
|
||||||
HANDLE procSnapshot;
|
HANDLE procSnapshot;
|
||||||
PROCESSENTRY32 procEntry;
|
PROCESSENTRY32 procEntry;
|
||||||
|
|
||||||
procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||||
if (procSnapshot == INVALID_HANDLE_VALUE) {
|
if (procSnapshot == INVALID_HANDLE_VALUE) {
|
||||||
return;
|
return processes;
|
||||||
}
|
}
|
||||||
|
|
||||||
procEntry.dwSize = sizeof(PROCESSENTRY32);
|
procEntry.dwSize = sizeof(PROCESSENTRY32);
|
||||||
|
|
||||||
if (!Process32First(procSnapshot, &procEntry)) {
|
if (!Process32First(procSnapshot, &procEntry)) {
|
||||||
CloseHandle(procSnapshot);
|
CloseHandle(procSnapshot);
|
||||||
return;
|
return processes;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -383,9 +378,10 @@ void GetProcessList(QStringList &processes)
|
|||||||
} while (Process32Next(procSnapshot, &procEntry));
|
} while (Process32Next(procSnapshot, &procEntry));
|
||||||
|
|
||||||
CloseHandle(procSnapshot);
|
CloseHandle(procSnapshot);
|
||||||
|
return processes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GetForegroundProcessName(QString &proc)
|
static QString getForegroundProcessNameStr()
|
||||||
{
|
{
|
||||||
// only checks if the current foreground window is from the same executable,
|
// only checks if the current foreground window is from the same executable,
|
||||||
// may return true for any window from a program
|
// may return true for any window from a program
|
||||||
@@ -396,31 +392,90 @@ static void GetForegroundProcessName(QString &proc)
|
|||||||
HANDLE process = OpenProcess(
|
HANDLE process = OpenProcess(
|
||||||
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
|
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
|
||||||
if (process == NULL) {
|
if (process == NULL) {
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
WCHAR executablePath[600];
|
WCHAR executablePath[600];
|
||||||
GetModuleFileNameEx(process, 0, executablePath, 600);
|
GetModuleFileNameEx(process, 0, executablePath, 600);
|
||||||
CloseHandle(process);
|
CloseHandle(process);
|
||||||
|
|
||||||
proc = QString::fromWCharArray(executablePath)
|
return QString::fromWCharArray(executablePath)
|
||||||
.split(QRegularExpression("(/|\\\\)"))
|
.split(QRegularExpression("(/|\\\\)"))
|
||||||
.back();
|
.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetForegroundProcessName(std::string &proc)
|
std::string GetForegroundProcessName()
|
||||||
{
|
{
|
||||||
QString temp;
|
return getForegroundProcessNameStr().toStdString();
|
||||||
GetForegroundProcessName(temp);
|
}
|
||||||
proc = temp.toStdString();
|
|
||||||
|
std::string GetForegroundProcessPath()
|
||||||
|
{
|
||||||
|
HWND foregroundWindow = GetForegroundWindow();
|
||||||
|
DWORD processId = 0;
|
||||||
|
GetWindowThreadProcessId(foregroundWindow, &processId);
|
||||||
|
|
||||||
|
HANDLE process = OpenProcess(
|
||||||
|
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
|
||||||
|
if (process == NULL) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
WCHAR executablePath[600];
|
||||||
|
GetModuleFileNameEx(process, 0, executablePath, 600);
|
||||||
|
CloseHandle(process);
|
||||||
|
|
||||||
|
return QString::fromWCharArray(executablePath).toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList GetProcessPathsFromName(const QString &name)
|
||||||
|
{
|
||||||
|
QStringList paths;
|
||||||
|
HANDLE procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||||
|
if (procSnapshot == INVALID_HANDLE_VALUE) {
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
PROCESSENTRY32 procEntry;
|
||||||
|
procEntry.dwSize = sizeof(PROCESSENTRY32);
|
||||||
|
|
||||||
|
if (!Process32First(procSnapshot, &procEntry)) {
|
||||||
|
CloseHandle(procSnapshot);
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
QString exeName = QString::fromWCharArray(procEntry.szExeFile);
|
||||||
|
if (exeName != name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE process =
|
||||||
|
OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
|
||||||
|
FALSE, procEntry.th32ProcessID);
|
||||||
|
if (process == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
WCHAR executablePath[600];
|
||||||
|
if (GetModuleFileNameEx(process, 0, executablePath, 600)) {
|
||||||
|
QString path = QString::fromWCharArray(executablePath);
|
||||||
|
if (!paths.contains(path)) {
|
||||||
|
paths.append(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CloseHandle(process);
|
||||||
|
} while (Process32Next(procSnapshot, &procEntry));
|
||||||
|
|
||||||
|
CloseHandle(procSnapshot);
|
||||||
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInFocus(const QString &executable)
|
bool IsInFocus(const QString &executable)
|
||||||
{
|
{
|
||||||
// only checks if the current foreground window is from the same executable,
|
// only checks if the current foreground window is from the same executable,
|
||||||
// may return true for any window from a program
|
// may return true for any window from a program
|
||||||
QString foregroundProc;
|
const auto foregroundProc = getForegroundProcessNameStr();
|
||||||
GetForegroundProcessName(foregroundProc);
|
|
||||||
|
|
||||||
// True if executable switch equals current window
|
// True if executable switch equals current window
|
||||||
bool equals = (executable == foregroundProc);
|
bool equals = (executable == foregroundProc);
|
||||||
@@ -450,9 +505,86 @@ int SecondsSinceLastInput()
|
|||||||
return (getTime() - getLastInputTime()) / 1000;
|
return (getTime() - getLastInputTime()) / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void addPluginFolderToSymbolPath()
|
||||||
|
{
|
||||||
|
// This runs after OBS_FRONTEND_EVENT_FINISHED_LOADING, which fires after
|
||||||
|
// obs_load_all_modules() completes. By that point OBS has already called
|
||||||
|
// reset_win32_symbol_paths() -> SymInitializeW(), so DbgHelp is
|
||||||
|
// initialized and we can append our plugins subfolder (where the PDB
|
||||||
|
// files live) to the existing search path.
|
||||||
|
HMODULE dbghelp = LoadLibraryW(L"DbgHelp");
|
||||||
|
if (!dbghelp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef BOOL(WINAPI * SymGetSearchPathW_t)(HANDLE, PWSTR, DWORD);
|
||||||
|
typedef BOOL(WINAPI * SymSetSearchPathW_t)(HANDLE, PCWSTR);
|
||||||
|
typedef BOOL(WINAPI * SymRefreshModuleList_t)(HANDLE);
|
||||||
|
|
||||||
|
auto symGetSearchPathW = reinterpret_cast<SymGetSearchPathW_t>(
|
||||||
|
GetProcAddress(dbghelp, "SymGetSearchPathW"));
|
||||||
|
auto symSetSearchPathW = reinterpret_cast<SymSetSearchPathW_t>(
|
||||||
|
GetProcAddress(dbghelp, "SymSetSearchPathW"));
|
||||||
|
auto symRefreshModuleList = reinterpret_cast<SymRefreshModuleList_t>(
|
||||||
|
GetProcAddress(dbghelp, "SymRefreshModuleList"));
|
||||||
|
|
||||||
|
if (!symGetSearchPathW || !symSetSearchPathW || !symRefreshModuleList) {
|
||||||
|
FreeLibrary(dbghelp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HMODULE hModule = NULL;
|
||||||
|
if (!GetModuleHandleExW(
|
||||||
|
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
||||||
|
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||||
|
reinterpret_cast<LPCWSTR>(addPluginFolderToSymbolPath),
|
||||||
|
&hModule)) {
|
||||||
|
FreeLibrary(dbghelp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t dllDir[MAX_PATH];
|
||||||
|
if (!GetModuleFileNameW(hModule, dllDir, MAX_PATH)) {
|
||||||
|
FreeLibrary(dbghelp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *lastSep = wcsrchr(dllDir, L'\\');
|
||||||
|
if (!lastSep) {
|
||||||
|
FreeLibrary(dbghelp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*lastSep = L'\0';
|
||||||
|
|
||||||
|
wchar_t pluginsPath[MAX_PATH];
|
||||||
|
wcsncpy_s(pluginsPath, MAX_PATH, dllDir, _TRUNCATE);
|
||||||
|
wcsncat_s(pluginsPath, MAX_PATH, L"\\" ADVSS_WIDEN(ADVSS_PLUGIN_FOLDER),
|
||||||
|
_TRUNCATE);
|
||||||
|
|
||||||
|
constexpr DWORD currentPathLen = 4096;
|
||||||
|
constexpr DWORD newPathLen = 8192;
|
||||||
|
auto currentPath = std::make_unique<wchar_t[]>(currentPathLen);
|
||||||
|
auto newPath = std::make_unique<wchar_t[]>(newPathLen);
|
||||||
|
|
||||||
|
symGetSearchPathW(GetCurrentProcess(), currentPath.get(),
|
||||||
|
currentPathLen);
|
||||||
|
|
||||||
|
if (currentPath[0] != L'\0') {
|
||||||
|
_snwprintf_s(newPath.get(), newPathLen, _TRUNCATE, L"%s;%s",
|
||||||
|
currentPath.get(), pluginsPath);
|
||||||
|
} else {
|
||||||
|
wcsncpy_s(newPath.get(), newPathLen, pluginsPath, _TRUNCATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
symSetSearchPathW(GetCurrentProcess(), newPath.get());
|
||||||
|
symRefreshModuleList(GetCurrentProcess());
|
||||||
|
FreeLibrary(dbghelp);
|
||||||
|
}
|
||||||
|
|
||||||
void PlatformInit()
|
void PlatformInit()
|
||||||
{
|
{
|
||||||
CoInitialize(NULL);
|
CoInitialize(NULL);
|
||||||
|
AddFinishedLoadingStep(addPluginFolderToSymbolPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformCleanup()
|
void PlatformCleanup()
|
||||||
|
|||||||
@@ -11,10 +11,11 @@ const std::string MacroActionFilter::id = "filter";
|
|||||||
|
|
||||||
std::vector<TempVariableRef> MacroActionFilter::GetTempVarRefs() const
|
std::vector<TempVariableRef> MacroActionFilter::GetTempVarRefs() const
|
||||||
{
|
{
|
||||||
if (!_tempVar.HasValidID()) {
|
auto refs = MacroSegment::GetTempVarRefs();
|
||||||
return {};
|
if (_tempVar.HasValidID()) {
|
||||||
|
refs.push_back(_tempVar);
|
||||||
}
|
}
|
||||||
return {_tempVar};
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroActionFilter::_registered = MacroActionFactory::Register(
|
bool MacroActionFilter::_registered = MacroActionFactory::Register(
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ static void waitHelper(std::unique_lock<std::mutex> *lock, Macro *macro,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionMedia::PerformActionHelper(obs_source_t *source) const
|
void MacroActionMedia::PerformActionHelper(obs_source_t *source)
|
||||||
{
|
{
|
||||||
obs_media_state state = obs_source_media_get_state(source);
|
obs_media_state state = obs_source_media_get_state(source);
|
||||||
|
|
||||||
@@ -130,6 +130,7 @@ void MacroActionMedia::PerformActionHelper(obs_source_t *source) const
|
|||||||
SeekToPercentage(source);
|
SeekToPercentage(source);
|
||||||
break;
|
break;
|
||||||
case Action::WAIT_FOR_PLAYBACK_STOP: {
|
case Action::WAIT_FOR_PLAYBACK_STOP: {
|
||||||
|
SuspendLock suspendLock(*this);
|
||||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
std::unique_lock<std::mutex> lock(*GetMutex());
|
||||||
waitHelper(&lock, GetMacro(), source);
|
waitHelper(&lock, GetMacro(), source);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public:
|
|||||||
SceneSelection _scene;
|
SceneSelection _scene;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PerformActionHelper(obs_source_t *) const;
|
void PerformActionHelper(obs_source_t *);
|
||||||
void SeekToPercentage(obs_source_t *source) const;
|
void SeekToPercentage(obs_source_t *source) const;
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
|
|||||||
@@ -159,7 +159,10 @@ bool MacroActionPlayAudio::PerformAction()
|
|||||||
|
|
||||||
if (_waitForCompletion) {
|
if (_waitForCompletion) {
|
||||||
SetMacroAbortWait(false);
|
SetMacroAbortWait(false);
|
||||||
waitForPlaybackToEnd(GetMacro(), source, maxMs);
|
{
|
||||||
|
SuspendLock suspendLock(*this);
|
||||||
|
waitForPlaybackToEnd(GetMacro(), source, maxMs);
|
||||||
|
}
|
||||||
deactivatePlayback(source, wantsOutput);
|
deactivatePlayback(source, wantsOutput);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,20 @@ bool MacroActionRun::_registered = MacroActionFactory::Register(
|
|||||||
bool MacroActionRun::PerformAction()
|
bool MacroActionRun::PerformAction()
|
||||||
{
|
{
|
||||||
if (_wait) {
|
if (_wait) {
|
||||||
_procConfig.StartProcessAndWait(_timeout.Milliseconds());
|
// Snapshot config before releasing the lock for the blocking wait
|
||||||
SetTempVarValues();
|
auto procConfig = _procConfig;
|
||||||
|
const auto timeout = _timeout.Milliseconds();
|
||||||
|
{
|
||||||
|
SuspendLock suspendLock(*this);
|
||||||
|
procConfig.StartProcessAndWait(timeout);
|
||||||
|
}
|
||||||
|
SetTempVarValue("process.id", procConfig.GetProcessId());
|
||||||
|
SetTempVarValue("process.exitCode",
|
||||||
|
procConfig.GetProcessExitCode());
|
||||||
|
SetTempVarValue("process.stream.output",
|
||||||
|
procConfig.GetProcessOutputStream());
|
||||||
|
SetTempVarValue("process.stream.error",
|
||||||
|
procConfig.GetProcessErrorStream());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -259,6 +259,12 @@ void MacroActionSourceInteractionEdit::AcceptRecorded(
|
|||||||
_stepList->SetSteps(_entryData->_steps);
|
_stepList->SetSteps(_entryData->_steps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionSourceInteractionEdit::showEvent(QShowEvent *event)
|
||||||
|
{
|
||||||
|
const QSignalBlocker b(this);
|
||||||
|
UpdateEntryData();
|
||||||
|
}
|
||||||
|
|
||||||
void MacroActionSourceInteractionEdit::SetCurrentStepEditor(int row)
|
void MacroActionSourceInteractionEdit::SetCurrentStepEditor(int row)
|
||||||
{
|
{
|
||||||
if (_stepEditor) {
|
if (_stepEditor) {
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ private slots:
|
|||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void showEvent(QShowEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetCurrentStepEditor(int row);
|
void SetCurrentStepEditor(int row);
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ const std::string MacroActionSource::id = "source";
|
|||||||
|
|
||||||
std::vector<TempVariableRef> MacroActionSource::GetTempVarRefs() const
|
std::vector<TempVariableRef> MacroActionSource::GetTempVarRefs() const
|
||||||
{
|
{
|
||||||
if (!_tempVar.HasValidID()) {
|
auto refs = MacroSegment::GetTempVarRefs();
|
||||||
return {};
|
if (_tempVar.HasValidID()) {
|
||||||
|
refs.push_back(_tempVar);
|
||||||
}
|
}
|
||||||
return {_tempVar};
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroActionSource::_registered = MacroActionFactory::Register(
|
bool MacroActionSource::_registered = MacroActionFactory::Register(
|
||||||
@@ -793,6 +794,8 @@ void MacroActionSourceEdit::SetWidgetVisibility()
|
|||||||
action == MacroActionSource::Action::CLOSE_FILTER_DIALOG ||
|
action == MacroActionSource::Action::CLOSE_FILTER_DIALOG ||
|
||||||
action == MacroActionSource::Action::CLOSE_PROPERTIES_DIALOG);
|
action == MacroActionSource::Action::CLOSE_PROPERTIES_DIALOG);
|
||||||
|
|
||||||
|
emit ShowVariableMappings(isGetSetting || isGetSettings);
|
||||||
|
|
||||||
adjustSize();
|
adjustSize();
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ private slots:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
void ShowVariableMappings(bool show);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetWidgetVisibility();
|
void SetWidgetVisibility();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "ui-helpers.hpp"
|
#include "ui-helpers.hpp"
|
||||||
|
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
|
#include <obs.hpp>
|
||||||
#include <util/config-file.h>
|
#include <util/config-file.h>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -183,6 +184,8 @@ MacroActionStreamEdit::MacroActionStreamEdit(
|
|||||||
_keyFrameInterval(new VariableSpinBox()),
|
_keyFrameInterval(new VariableSpinBox()),
|
||||||
_stringValue(new VariableLineEdit(this)),
|
_stringValue(new VariableLineEdit(this)),
|
||||||
_showPassword(new QPushButton()),
|
_showPassword(new QPushButton()),
|
||||||
|
_getCurrentValue(new QPushButton(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.streaming.getCurrentValue"))),
|
||||||
_layout(new QHBoxLayout())
|
_layout(new QHBoxLayout())
|
||||||
{
|
{
|
||||||
_keyFrameInterval->setMinimum(0);
|
_keyFrameInterval->setMinimum(0);
|
||||||
@@ -208,13 +211,17 @@ MacroActionStreamEdit::MacroActionStreamEdit(
|
|||||||
SLOT(ShowPassword()));
|
SLOT(ShowPassword()));
|
||||||
QWidget::connect(_showPassword, SIGNAL(released()), this,
|
QWidget::connect(_showPassword, SIGNAL(released()), this,
|
||||||
SLOT(HidePassword()));
|
SLOT(HidePassword()));
|
||||||
|
QWidget::connect(_getCurrentValue, SIGNAL(clicked()), this,
|
||||||
|
SLOT(GetCurrentValueClicked()));
|
||||||
|
|
||||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.streaming.entry"),
|
PlaceWidgets(
|
||||||
_layout,
|
obs_module_text("AdvSceneSwitcher.action.streaming.layout"),
|
||||||
{{"{{actions}}", _actions},
|
_layout,
|
||||||
{"{{keyFrameInterval}}", _keyFrameInterval},
|
{{"{{actions}}", _actions},
|
||||||
{"{{stringValue}}", _stringValue},
|
{"{{keyFrameInterval}}", _keyFrameInterval},
|
||||||
{"{{showPassword}}", _showPassword}});
|
{"{{stringValue}}", _stringValue},
|
||||||
|
{"{{showPassword}}", _showPassword},
|
||||||
|
{"{{getCurrentValue}}", _getCurrentValue}});
|
||||||
setLayout(_layout);
|
setLayout(_layout);
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
@@ -291,6 +298,62 @@ void MacroActionStreamEdit::SetWidgetVisibility()
|
|||||||
_stringValue->setEchoMode(QLineEdit::Normal);
|
_stringValue->setEchoMode(QLineEdit::Normal);
|
||||||
_showPassword->hide();
|
_showPassword->hide();
|
||||||
}
|
}
|
||||||
|
_getCurrentValue->setVisible(
|
||||||
|
action == MacroActionStream::Action::KEYFRAME_INTERVAL ||
|
||||||
|
action == MacroActionStream::Action::SERVER ||
|
||||||
|
action == MacroActionStream::Action::STREAM_KEY ||
|
||||||
|
action == MacroActionStream::Action::USERNAME ||
|
||||||
|
action == MacroActionStream::Action::PASSWORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionStreamEdit::GetCurrentValueClicked()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (_entryData->_action) {
|
||||||
|
case MacroActionStream::Action::KEYFRAME_INTERVAL: {
|
||||||
|
const auto configPath =
|
||||||
|
GetPathInProfileDir("streamEncoder.json");
|
||||||
|
OBSDataAutoRelease settings =
|
||||||
|
obs_data_create_from_json_file_safe(configPath.c_str(),
|
||||||
|
"bak");
|
||||||
|
if (!settings) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_keyFrameInterval->SetFixedValue(
|
||||||
|
(int)obs_data_get_int(settings, "keyint_sec"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MacroActionStream::Action::SERVER:
|
||||||
|
case MacroActionStream::Action::STREAM_KEY:
|
||||||
|
case MacroActionStream::Action::USERNAME:
|
||||||
|
case MacroActionStream::Action::PASSWORD: {
|
||||||
|
static const std::map<MacroActionStream::Action, const char *>
|
||||||
|
settingsKeys = {
|
||||||
|
{MacroActionStream::Action::SERVER, "server"},
|
||||||
|
{MacroActionStream::Action::STREAM_KEY, "key"},
|
||||||
|
{MacroActionStream::Action::USERNAME,
|
||||||
|
"username"},
|
||||||
|
{MacroActionStream::Action::PASSWORD,
|
||||||
|
"password"},
|
||||||
|
};
|
||||||
|
auto service = obs_frontend_get_streaming_service();
|
||||||
|
OBSDataAutoRelease settings = obs_service_get_settings(service);
|
||||||
|
if (!settings) {
|
||||||
|
obs_service_release(service);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const char *val = obs_data_get_string(
|
||||||
|
settings, settingsKeys.at(_entryData->_action));
|
||||||
|
if (val) {
|
||||||
|
_stringValue->setText(QString(val));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionStreamEdit::ActionChanged(int value)
|
void MacroActionStreamEdit::ActionChanged(int value)
|
||||||
|
|||||||
@@ -67,12 +67,14 @@ private slots:
|
|||||||
void StringValueChanged();
|
void StringValueChanged();
|
||||||
void ShowPassword();
|
void ShowPassword();
|
||||||
void HidePassword();
|
void HidePassword();
|
||||||
|
void GetCurrentValueClicked();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QComboBox *_actions;
|
QComboBox *_actions;
|
||||||
VariableSpinBox *_keyFrameInterval;
|
VariableSpinBox *_keyFrameInterval;
|
||||||
VariableLineEdit *_stringValue;
|
VariableLineEdit *_stringValue;
|
||||||
QPushButton *_showPassword;
|
QPushButton *_showPassword;
|
||||||
|
QPushButton *_getCurrentValue;
|
||||||
std::shared_ptr<MacroActionStream> _entryData;
|
std::shared_ptr<MacroActionStream> _entryData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -57,8 +57,11 @@ bool MacroActionWait::PerformAction()
|
|||||||
std::chrono::milliseconds((int)(sleepDuration * 1000));
|
std::chrono::milliseconds((int)(sleepDuration * 1000));
|
||||||
|
|
||||||
SetMacroAbortWait(false);
|
SetMacroAbortWait(false);
|
||||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
{
|
||||||
waitHelper(&lock, GetMacro(), time);
|
SuspendLock suspendLock(*this);
|
||||||
|
std::unique_lock<std::mutex> lock(*GetMutex());
|
||||||
|
waitHelper(&lock, GetMacro(), time);
|
||||||
|
}
|
||||||
|
|
||||||
return !MacroWaitShouldAbort();
|
return !MacroWaitShouldAbort();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,8 +42,7 @@ void CloseWindow(const std::string &) {}
|
|||||||
|
|
||||||
std::optional<std::string> MacroActionWindow::GetMatchingWindow() const
|
std::optional<std::string> MacroActionWindow::GetMatchingWindow() const
|
||||||
{
|
{
|
||||||
std::vector<std::string> windowList;
|
const auto windowList = GetWindowList();
|
||||||
GetWindowList(windowList);
|
|
||||||
|
|
||||||
if (!_regex.Enabled()) {
|
if (!_regex.Enabled()) {
|
||||||
if (std::find(windowList.begin(), windowList.end(),
|
if (std::find(windowList.begin(), windowList.end(),
|
||||||
|
|||||||
@@ -16,54 +16,100 @@ bool MacroConditionProcess::_registered = MacroConditionFactory::Register(
|
|||||||
|
|
||||||
bool MacroConditionProcess::CheckCondition()
|
bool MacroConditionProcess::CheckCondition()
|
||||||
{
|
{
|
||||||
QStringList runningProcesses;
|
const auto foregroundProcessName = GetForegroundProcessName();
|
||||||
QString proc = QString::fromStdString(_process);
|
|
||||||
GetProcessList(runningProcesses);
|
|
||||||
std::string foregroundProcessName;
|
|
||||||
GetForegroundProcessName(foregroundProcessName);
|
|
||||||
|
|
||||||
SetVariableValue(foregroundProcessName);
|
SetVariableValue(foregroundProcessName);
|
||||||
|
|
||||||
if (!_regex.Enabled()) {
|
const QString proc = QString::fromStdString(_process);
|
||||||
if (runningProcesses.contains(proc) &&
|
|
||||||
(!_checkFocus || IsInFocus(proc))) {
|
|
||||||
SetTempVarValue("name", proc.toStdString());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int matchIndex = -1;
|
if (_checkFocus) {
|
||||||
bool foundMatch = false;
|
// Check name and path against the same foreground process
|
||||||
for (const auto &process : runningProcesses) {
|
// instance to avoid false positives when multiple processes
|
||||||
matchIndex++;
|
// share the same name
|
||||||
if (_regex.Matches(process, proc)) {
|
const auto foregroundPath = GetForegroundProcessPath();
|
||||||
foundMatch = true;
|
const QString foregroundName =
|
||||||
break;
|
QString::fromStdString(foregroundProcessName);
|
||||||
|
|
||||||
|
SetTempVarValue("name", foregroundProcessName);
|
||||||
|
SetTempVarValue("path", foregroundPath);
|
||||||
|
|
||||||
|
bool nameMatches =
|
||||||
|
_regex.Enabled() ? _regex.Matches(foregroundName, proc)
|
||||||
|
: (foregroundName == proc);
|
||||||
|
if (!nameMatches) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!foundMatch) {
|
if (_checkPath) {
|
||||||
return false;
|
const QString pathPattern =
|
||||||
}
|
QString::fromStdString(_processPath);
|
||||||
if (!_checkFocus) {
|
const QString qForegroundPath =
|
||||||
SetTempVarValue("name",
|
QString::fromStdString(foregroundPath);
|
||||||
runningProcesses.at(matchIndex).toStdString());
|
bool pathMatches =
|
||||||
|
_pathRegex.Enabled()
|
||||||
|
? _pathRegex.Matches(qForegroundPath,
|
||||||
|
pathPattern)
|
||||||
|
: qForegroundPath == pathPattern;
|
||||||
|
if (!pathMatches) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!IsInFocus(proc)) {
|
|
||||||
return false;
|
const auto runningProcesses = GetProcessList();
|
||||||
|
|
||||||
|
for (const auto &process : runningProcesses) {
|
||||||
|
bool nameMatches = _regex.Enabled()
|
||||||
|
? _regex.Matches(process, proc)
|
||||||
|
: (process == proc);
|
||||||
|
if (!nameMatches) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_checkPath) {
|
||||||
|
SetTempVarValue("name", process.toStdString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto paths = GetProcessPathsFromName(process);
|
||||||
|
|
||||||
|
const QString pathPattern =
|
||||||
|
QString::fromStdString(_processPath);
|
||||||
|
bool foundMatchingPath = false;
|
||||||
|
for (const auto &path : paths) {
|
||||||
|
bool pathMatches =
|
||||||
|
_pathRegex.Enabled()
|
||||||
|
? _pathRegex.Matches(path, pathPattern)
|
||||||
|
: path == pathPattern;
|
||||||
|
if (pathMatches) {
|
||||||
|
SetTempVarValue("path", path.toStdString());
|
||||||
|
foundMatchingPath = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundMatchingPath) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetTempVarValue("name", process.toStdString());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
SetTempVarValue("name", foregroundProcessName);
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionProcess::Save(obs_data_t *obj) const
|
bool MacroConditionProcess::Save(obs_data_t *obj) const
|
||||||
{
|
{
|
||||||
MacroCondition::Save(obj);
|
MacroCondition::Save(obj);
|
||||||
_process.Save(obj, "process");
|
_process.Save(obj, "process");
|
||||||
obs_data_set_bool(obj, "focus", _checkFocus);
|
|
||||||
_regex.Save(obj);
|
_regex.Save(obj);
|
||||||
obs_data_set_int(obj, "version", 1);
|
obs_data_set_bool(obj, "focus", _checkFocus);
|
||||||
|
obs_data_set_bool(obj, "checkPath", _checkPath);
|
||||||
|
_processPath.Save(obj, "processPath");
|
||||||
|
_pathRegex.Save(obj, "pathRegex");
|
||||||
|
obs_data_set_int(obj, "version", 2);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +124,9 @@ bool MacroConditionProcess::Load(obs_data_t *obj)
|
|||||||
} else {
|
} else {
|
||||||
_regex.Load(obj);
|
_regex.Load(obj);
|
||||||
}
|
}
|
||||||
|
_checkPath = obs_data_get_bool(obj, "checkPath");
|
||||||
|
_processPath.Load(obj, "processPath");
|
||||||
|
_pathRegex.Load(obj, "pathRegex");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +140,8 @@ void MacroConditionProcess::SetupTempVars()
|
|||||||
MacroCondition::SetupTempVars();
|
MacroCondition::SetupTempVars();
|
||||||
AddTempvar("name",
|
AddTempvar("name",
|
||||||
obs_module_text("AdvSceneSwitcher.tempVar.process.name"));
|
obs_module_text("AdvSceneSwitcher.tempVar.process.name"));
|
||||||
|
AddTempvar("path",
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.process.path"));
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroConditionProcessEdit::MacroConditionProcessEdit(
|
MacroConditionProcessEdit::MacroConditionProcessEdit(
|
||||||
@@ -100,13 +151,20 @@ MacroConditionProcessEdit::MacroConditionProcessEdit(
|
|||||||
_regex(new RegexConfigWidget(this)),
|
_regex(new RegexConfigWidget(this)),
|
||||||
_focused(new QCheckBox()),
|
_focused(new QCheckBox()),
|
||||||
_focusProcess(new QLabel()),
|
_focusProcess(new QLabel()),
|
||||||
_focusLayout(new QHBoxLayout())
|
_focusLayout(new QHBoxLayout()),
|
||||||
|
_checkPath(new QCheckBox()),
|
||||||
|
_processPath(new VariableLineEdit(this)),
|
||||||
|
_pathRegex(new RegexConfigWidget(this)),
|
||||||
|
_pathLayout(new QHBoxLayout())
|
||||||
{
|
{
|
||||||
_processSelection->setEditable(true);
|
_processSelection->setEditable(true);
|
||||||
_processSelection->setMaxVisibleItems(20);
|
_processSelection->setMaxVisibleItems(20);
|
||||||
_processSelection->setToolTip(
|
_processSelection->setToolTip(
|
||||||
obs_module_text("AdvSceneSwitcher.tooltip.availableVariables"));
|
obs_module_text("AdvSceneSwitcher.tooltip.availableVariables"));
|
||||||
|
|
||||||
|
_processPath->setToolTip(
|
||||||
|
obs_module_text("AdvSceneSwitcher.tooltip.availableVariables"));
|
||||||
|
|
||||||
QWidget::connect(_processSelection,
|
QWidget::connect(_processSelection,
|
||||||
SIGNAL(currentTextChanged(const QString &)), this,
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
SLOT(ProcessChanged(const QString &)));
|
SLOT(ProcessChanged(const QString &)));
|
||||||
@@ -115,6 +173,13 @@ MacroConditionProcessEdit::MacroConditionProcessEdit(
|
|||||||
SLOT(RegexChanged(const RegexConfig &)));
|
SLOT(RegexChanged(const RegexConfig &)));
|
||||||
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
||||||
SLOT(FocusChanged(int)));
|
SLOT(FocusChanged(int)));
|
||||||
|
QWidget::connect(_checkPath, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(CheckPathChanged(int)));
|
||||||
|
QWidget::connect(_processPath, SIGNAL(textChanged(const QString &)),
|
||||||
|
this, SLOT(ProcessPathChanged(const QString &)));
|
||||||
|
QWidget::connect(_pathRegex,
|
||||||
|
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
|
||||||
|
SLOT(PathRegexChanged(const RegexConfig &)));
|
||||||
QWidget::connect(&_timer, SIGNAL(timeout()), this,
|
QWidget::connect(&_timer, SIGNAL(timeout()), this,
|
||||||
SLOT(UpdateFocusProcess()));
|
SLOT(UpdateFocusProcess()));
|
||||||
|
|
||||||
@@ -125,18 +190,25 @@ MacroConditionProcessEdit::MacroConditionProcessEdit(
|
|||||||
{"{{regex}}", _regex},
|
{"{{regex}}", _regex},
|
||||||
{"{{focused}}", _focused},
|
{"{{focused}}", _focused},
|
||||||
{"{{focusProcess}}", _focusProcess},
|
{"{{focusProcess}}", _focusProcess},
|
||||||
|
{"{{checkPath}}", _checkPath},
|
||||||
|
{"{{path}}", _processPath},
|
||||||
|
{"{{pathRegex}}", _pathRegex},
|
||||||
};
|
};
|
||||||
|
|
||||||
auto entryLayout = new QHBoxLayout;
|
auto entryLayout = new QHBoxLayout;
|
||||||
PlaceWidgets(
|
PlaceWidgets(
|
||||||
obs_module_text("AdvSceneSwitcher.condition.process.entry"),
|
obs_module_text("AdvSceneSwitcher.condition.process.layout"),
|
||||||
entryLayout, widgetPlaceholders);
|
entryLayout, widgetPlaceholders);
|
||||||
PlaceWidgets(obs_module_text(
|
PlaceWidgets(obs_module_text(
|
||||||
"AdvSceneSwitcher.condition.process.entry.focus"),
|
"AdvSceneSwitcher.condition.process.layout.focus"),
|
||||||
_focusLayout, widgetPlaceholders);
|
_focusLayout, widgetPlaceholders);
|
||||||
|
PlaceWidgets(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.process.layout.path"),
|
||||||
|
_pathLayout, widgetPlaceholders);
|
||||||
auto mainLayout = new QVBoxLayout;
|
auto mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addLayout(entryLayout);
|
mainLayout->addLayout(entryLayout);
|
||||||
mainLayout->addLayout(_focusLayout);
|
mainLayout->addLayout(_focusLayout);
|
||||||
|
mainLayout->addLayout(_pathLayout);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
@@ -178,11 +250,31 @@ void MacroConditionProcessEdit::FocusChanged(int state)
|
|||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroConditionProcessEdit::CheckPathChanged(int state)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_checkPath = state;
|
||||||
|
SetWidgetVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionProcessEdit::ProcessPathChanged(const QString &text)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_processPath = text.toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionProcessEdit::PathRegexChanged(const RegexConfig &conf)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_pathRegex = conf;
|
||||||
|
adjustSize();
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
void MacroConditionProcessEdit::UpdateFocusProcess()
|
void MacroConditionProcessEdit::UpdateFocusProcess()
|
||||||
{
|
{
|
||||||
std::string name;
|
_focusProcess->setText(
|
||||||
GetForegroundProcessName(name);
|
QString::fromStdString(GetForegroundProcessName()));
|
||||||
_focusProcess->setText(QString::fromStdString(name));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionProcessEdit::SetWidgetVisibility()
|
void MacroConditionProcessEdit::SetWidgetVisibility()
|
||||||
@@ -191,6 +283,13 @@ void MacroConditionProcessEdit::SetWidgetVisibility()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SetLayoutVisible(_focusLayout, _entryData->_checkFocus);
|
SetLayoutVisible(_focusLayout, _entryData->_checkFocus);
|
||||||
|
_processPath->setVisible(_entryData->_checkPath);
|
||||||
|
_pathRegex->setVisible(_entryData->_checkPath);
|
||||||
|
if (_entryData->_checkPath) {
|
||||||
|
RemoveStretchIfPresent(_pathLayout);
|
||||||
|
} else {
|
||||||
|
AddStretchIfNecessary(_pathLayout);
|
||||||
|
}
|
||||||
adjustSize();
|
adjustSize();
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
@@ -205,6 +304,9 @@ void MacroConditionProcessEdit::UpdateEntryData()
|
|||||||
_entryData->_process.UnresolvedValue().c_str());
|
_entryData->_process.UnresolvedValue().c_str());
|
||||||
_regex->SetRegexConfig(_entryData->_regex);
|
_regex->SetRegexConfig(_entryData->_regex);
|
||||||
_focused->setChecked(_entryData->_checkFocus);
|
_focused->setChecked(_entryData->_checkFocus);
|
||||||
|
_checkPath->setChecked(_entryData->_checkPath);
|
||||||
|
_processPath->setText(_entryData->_processPath);
|
||||||
|
_pathRegex->SetRegexConfig(_entryData->_pathRegex);
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "macro-condition-edit.hpp"
|
#include "macro-condition-edit.hpp"
|
||||||
#include "regex-config.hpp"
|
#include "regex-config.hpp"
|
||||||
#include "variable-string.hpp"
|
#include "variable-line-edit.hpp"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
|
||||||
@@ -21,8 +21,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
StringVariable _process;
|
StringVariable _process;
|
||||||
bool _checkFocus = true;
|
|
||||||
RegexConfig _regex = RegexConfig::PartialMatchRegexConfig();
|
RegexConfig _regex = RegexConfig::PartialMatchRegexConfig();
|
||||||
|
bool _checkFocus = true;
|
||||||
|
bool _checkPath = false;
|
||||||
|
StringVariable _processPath;
|
||||||
|
RegexConfig _pathRegex = RegexConfig::PartialMatchRegexConfig();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetupTempVars();
|
void SetupTempVars();
|
||||||
@@ -54,6 +57,9 @@ private slots:
|
|||||||
void ProcessChanged(const QString &text);
|
void ProcessChanged(const QString &text);
|
||||||
void RegexChanged(const RegexConfig &);
|
void RegexChanged(const RegexConfig &);
|
||||||
void FocusChanged(int state);
|
void FocusChanged(int state);
|
||||||
|
void CheckPathChanged(int state);
|
||||||
|
void ProcessPathChanged(const QString &text);
|
||||||
|
void PathRegexChanged(const RegexConfig &);
|
||||||
void UpdateFocusProcess();
|
void UpdateFocusProcess();
|
||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
@@ -66,6 +72,10 @@ private:
|
|||||||
QCheckBox *_focused;
|
QCheckBox *_focused;
|
||||||
QLabel *_focusProcess;
|
QLabel *_focusProcess;
|
||||||
QHBoxLayout *_focusLayout;
|
QHBoxLayout *_focusLayout;
|
||||||
|
QCheckBox *_checkPath;
|
||||||
|
VariableLineEdit *_processPath;
|
||||||
|
RegexConfigWidget *_pathRegex;
|
||||||
|
QHBoxLayout *_pathLayout;
|
||||||
QTimer _timer;
|
QTimer _timer;
|
||||||
std::shared_ptr<MacroConditionProcess> _entryData;
|
std::shared_ptr<MacroConditionProcess> _entryData;
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
|
|||||||
@@ -135,8 +135,7 @@ static bool foregroundWindowChanged()
|
|||||||
|
|
||||||
bool MacroConditionWindow::CheckCondition()
|
bool MacroConditionWindow::CheckCondition()
|
||||||
{
|
{
|
||||||
std::vector<std::string> windowList;
|
const auto windowList = GetWindowList();
|
||||||
GetWindowList(windowList);
|
|
||||||
bool match = false;
|
bool match = false;
|
||||||
if (_windowRegex.Enabled()) {
|
if (_windowRegex.Enabled()) {
|
||||||
match = WindowRegexMatches(windowList);
|
match = WindowRegexMatches(windowList);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ bool setup()
|
|||||||
{
|
{
|
||||||
AddSaveStep(saveConnections);
|
AddSaveStep(saveConnections);
|
||||||
AddLoadStep(loadConnections);
|
AddLoadStep(loadConnections);
|
||||||
|
AddPluginCleanupStep([]() { connections.clear(); });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,48 +112,56 @@ static URLInfo getURLInfo(const std::string &input, bool keepParams)
|
|||||||
|
|
||||||
bool MacroActionHttp::PerformAction()
|
bool MacroActionHttp::PerformAction()
|
||||||
{
|
{
|
||||||
|
// Capture all config while holding the segment lock
|
||||||
const auto [host, path] = getURLInfo(_url, !_setParams);
|
const auto [host, path] = getURLInfo(_url, !_setParams);
|
||||||
|
|
||||||
httplib::Client cli(host);
|
httplib::Client cli(host);
|
||||||
setTimeout(cli, _timeout);
|
setTimeout(cli, _timeout);
|
||||||
const auto params = _setParams ? getParams(_params) : httplib::Params();
|
const auto params = _setParams ? getParams(_params) : httplib::Params();
|
||||||
const auto headers = _setHeaders ? getHeaders(_headers)
|
const auto headers = _setHeaders ? getHeaders(_headers)
|
||||||
: httplib::Headers();
|
: httplib::Headers();
|
||||||
|
const auto method = _method;
|
||||||
|
const std::string body = _body;
|
||||||
|
const std::string contentType = _contentType;
|
||||||
|
|
||||||
|
// Release the segment lock for the blocking network call
|
||||||
httplib::Result response;
|
httplib::Result response;
|
||||||
switch (_method) {
|
{
|
||||||
case MacroActionHttp::Method::GET:
|
SuspendLock suspendLock(*this);
|
||||||
response = cli.Get(path, params, headers);
|
switch (method) {
|
||||||
break;
|
case MacroActionHttp::Method::GET:
|
||||||
case MacroActionHttp::Method::POST: {
|
response = cli.Get(path, params, headers);
|
||||||
const auto pathWithParam =
|
break;
|
||||||
httplib::append_query_params(path, params);
|
case MacroActionHttp::Method::POST: {
|
||||||
response =
|
const auto pathWithParam =
|
||||||
cli.Post(pathWithParam, headers, _body, _contentType);
|
httplib::append_query_params(path, params);
|
||||||
break;
|
response = cli.Post(pathWithParam, headers, body,
|
||||||
}
|
contentType);
|
||||||
case MacroActionHttp::Method::PUT: {
|
break;
|
||||||
const auto pathWithParam =
|
}
|
||||||
httplib::append_query_params(path, params);
|
case MacroActionHttp::Method::PUT: {
|
||||||
response = cli.Put(pathWithParam, headers, _body, _contentType);
|
const auto pathWithParam =
|
||||||
break;
|
httplib::append_query_params(path, params);
|
||||||
}
|
response = cli.Put(pathWithParam, headers, body,
|
||||||
case MacroActionHttp::Method::PATCH: {
|
contentType);
|
||||||
const auto pathWithParam =
|
break;
|
||||||
httplib::append_query_params(path, params);
|
}
|
||||||
response =
|
case MacroActionHttp::Method::PATCH: {
|
||||||
cli.Patch(pathWithParam, headers, _body, _contentType);
|
const auto pathWithParam =
|
||||||
break;
|
httplib::append_query_params(path, params);
|
||||||
}
|
response = cli.Patch(pathWithParam, headers, body,
|
||||||
case MacroActionHttp::Method::DELETE: {
|
contentType);
|
||||||
const auto pathWithParam =
|
break;
|
||||||
httplib::append_query_params(path, params);
|
}
|
||||||
response =
|
case MacroActionHttp::Method::DELETE: {
|
||||||
cli.Delete(pathWithParam, headers, _body, _contentType);
|
const auto pathWithParam =
|
||||||
break;
|
httplib::append_query_params(path, params);
|
||||||
}
|
response = cli.Delete(pathWithParam, headers, body,
|
||||||
default:
|
contentType);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VerboseLoggingEnabled() && !response) {
|
if (VerboseLoggingEnabled() && !response) {
|
||||||
|
|||||||
@@ -718,6 +718,7 @@ static bool setup()
|
|||||||
{
|
{
|
||||||
AddSaveStep(SaveMqttConnections);
|
AddSaveStep(SaveMqttConnections);
|
||||||
AddLoadStep(LoadMqttConnections);
|
AddLoadStep(LoadMqttConnections);
|
||||||
|
AddPluginCleanupStep([]() { GetMqttConnections().clear(); });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ bool MacroActionScript::PerformAction()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SuspendLock suspendLock(static_cast<MacroAction &>(*this));
|
||||||
(void)SendTriggerSignal();
|
(void)SendTriggerSignal();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ bool MacroConditionScript::CheckCondition()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SuspendLock suspendLock(static_cast<MacroCondition &>(*this));
|
||||||
return SendTriggerSignal();
|
return SendTriggerSignal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,13 @@
|
|||||||
#include "log-helper.hpp"
|
#include "log-helper.hpp"
|
||||||
#include "obs-module-helper.hpp"
|
#include "obs-module-helper.hpp"
|
||||||
|
|
||||||
|
#include <obs-frontend-api.h>
|
||||||
#include <obs-module.h>
|
#include <obs-module.h>
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
@@ -28,6 +32,17 @@ const std::string_view InlineScript::_defaultLUAScript =
|
|||||||
"end";
|
"end";
|
||||||
;
|
;
|
||||||
|
|
||||||
|
static std::mutex instancesMutex;
|
||||||
|
static std::unordered_set<InlineScript *> instances;
|
||||||
|
|
||||||
|
static void handleScriptingShutdown(enum obs_frontend_event event, void *)
|
||||||
|
{
|
||||||
|
if (event != OBS_FRONTEND_EVENT_SCRIPTING_SHUTDOWN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InlineScript::DeregisterAll();
|
||||||
|
}
|
||||||
|
|
||||||
static bool setup()
|
static bool setup()
|
||||||
{
|
{
|
||||||
auto sh = obs_get_signal_handler();
|
auto sh = obs_get_signal_handler();
|
||||||
@@ -35,6 +50,8 @@ static bool setup()
|
|||||||
std::string("void ") + signalName.data() + "(string id)";
|
std::string("void ") + signalName.data() + "(string id)";
|
||||||
signal_handler_add(sh, signalDecl.c_str());
|
signal_handler_add(sh, signalDecl.c_str());
|
||||||
|
|
||||||
|
obs_frontend_add_event_callback(handleScriptingShutdown, nullptr);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
static bool setupDone = setup();
|
static bool setupDone = setup();
|
||||||
@@ -98,6 +115,10 @@ static bool createScriptFile(const char *settingsFile, const char *content)
|
|||||||
|
|
||||||
InlineScript::InlineScript() : _instanceId(_instanceIdCounter++)
|
InlineScript::InlineScript() : _instanceId(_instanceIdCounter++)
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(instancesMutex);
|
||||||
|
instances.insert(this);
|
||||||
|
}
|
||||||
Setup();
|
Setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,9 +128,27 @@ InlineScript::InlineScript(const InlineScript &other)
|
|||||||
_textLUA(other._textLUA),
|
_textLUA(other._textLUA),
|
||||||
_instanceId(_instanceIdCounter++)
|
_instanceId(_instanceIdCounter++)
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(instancesMutex);
|
||||||
|
instances.insert(this);
|
||||||
|
}
|
||||||
Setup();
|
Setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InlineScript::~InlineScript()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(instancesMutex);
|
||||||
|
instances.erase(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InlineScript::DeregisterAll()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(instancesMutex);
|
||||||
|
for (auto *instance : instances) {
|
||||||
|
instance->_script.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InlineScript::Save(obs_data_t *data) const
|
void InlineScript::Save(obs_data_t *data) const
|
||||||
{
|
{
|
||||||
OBSDataAutoRelease obj = obs_data_create();
|
OBSDataAutoRelease obj = obs_data_create();
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class InlineScript {
|
|||||||
public:
|
public:
|
||||||
InlineScript();
|
InlineScript();
|
||||||
InlineScript(const InlineScript &);
|
InlineScript(const InlineScript &);
|
||||||
|
~InlineScript();
|
||||||
|
|
||||||
enum Type { INLINE, FILE };
|
enum Type { INLINE, FILE };
|
||||||
|
|
||||||
@@ -34,6 +35,8 @@ public:
|
|||||||
|
|
||||||
void ResolveVariablesToFixedValues();
|
void ResolveVariablesToFixedValues();
|
||||||
|
|
||||||
|
static void DeregisterAll();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Setup();
|
void Setup();
|
||||||
void SetupFile();
|
void SetupFile();
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include "date/tz.h"
|
#include "date/tz.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
using websocketpp::lib::placeholders::_1;
|
using websocketpp::lib::placeholders::_1;
|
||||||
@@ -28,7 +30,7 @@ static constexpr std::string_view registerSubscriptionURL =
|
|||||||
static constexpr std::string_view registerSubscriptionPath =
|
static constexpr std::string_view registerSubscriptionPath =
|
||||||
"/helix/eventsub/subscriptions";
|
"/helix/eventsub/subscriptions";
|
||||||
#endif
|
#endif
|
||||||
static const int reconnectDelay = 15;
|
static const auto reconnectDelay = 15s;
|
||||||
|
|
||||||
#undef DispatchMessage
|
#undef DispatchMessage
|
||||||
|
|
||||||
@@ -81,6 +83,10 @@ void EventSub::ConnectThread()
|
|||||||
} else {
|
} else {
|
||||||
_client->connect(con);
|
_client->connect(con);
|
||||||
_connection = connection_hdl(con);
|
_connection = connection_hdl(con);
|
||||||
|
if (_disconnect) {
|
||||||
|
_client->close(con, websocketpp::close::status::normal,
|
||||||
|
"Twitch EventSub stopping", ec);
|
||||||
|
}
|
||||||
_client->run();
|
_client->run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,9 +104,9 @@ void EventSub::WaitAndReconnect()
|
|||||||
auto thread = std::thread([this]() {
|
auto thread = std::thread([this]() {
|
||||||
std::unique_lock<std::mutex> lock(_waitMtx);
|
std::unique_lock<std::mutex> lock(_waitMtx);
|
||||||
blog(LOG_INFO,
|
blog(LOG_INFO,
|
||||||
"Twitch EventSub trying to reconnect to in %d seconds.",
|
"Twitch EventSub trying to reconnect to in %lld seconds.",
|
||||||
reconnectDelay);
|
(long long)reconnectDelay.count());
|
||||||
_cv.wait_for(lock, std::chrono::seconds(reconnectDelay));
|
_cv.wait_for(lock, reconnectDelay);
|
||||||
_reconnecting = false;
|
_reconnecting = false;
|
||||||
|
|
||||||
if (_disconnect) {
|
if (_disconnect) {
|
||||||
@@ -155,12 +161,6 @@ void EventSub::Disconnect()
|
|||||||
_cv.notify_all();
|
_cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (_connected) {
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
||||||
_client->close(_connection, websocketpp::close::status::normal,
|
|
||||||
"Twitch EventSub stopping", ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_thread.joinable()) {
|
if (_thread.joinable()) {
|
||||||
_thread.join();
|
_thread.join();
|
||||||
}
|
}
|
||||||
@@ -342,8 +342,7 @@ static bool isValidTimestamp(const std::string ×tamp)
|
|||||||
|
|
||||||
auto duration = now - parsedTime;
|
auto duration = now - parsedTime;
|
||||||
// Clocks might be off by a bit, so allow negative values also
|
// Clocks might be off by a bit, so allow negative values also
|
||||||
return duration <= std::chrono::minutes(10) &&
|
return duration <= 10min && duration >= -1min;
|
||||||
duration >= std::chrono::minutes(-1);
|
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
blog(LOG_WARNING, "%s: %s", __func__, e.what());
|
blog(LOG_WARNING, "%s: %s", __func__, e.what());
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1840,7 +1840,10 @@ void MacroActionTwitchEdit::SetWidgetLayout()
|
|||||||
|
|
||||||
const char *layoutText;
|
const char *layoutText;
|
||||||
const char *layout2Text = nullptr;
|
const char *layout2Text = nullptr;
|
||||||
switch (_entryData->GetAction()) {
|
|
||||||
|
const auto action = _entryData->GetAction();
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
case MacroActionTwitch::Action::SEND_CHAT_MESSAGE:
|
case MacroActionTwitch::Action::SEND_CHAT_MESSAGE:
|
||||||
layoutText = obs_module_text(
|
layoutText = obs_module_text(
|
||||||
"AdvSceneSwitcher.action.twitch.layout.chat");
|
"AdvSceneSwitcher.action.twitch.layout.chat");
|
||||||
@@ -1892,6 +1895,12 @@ void MacroActionTwitchEdit::SetWidgetLayout()
|
|||||||
|
|
||||||
_layout->setContentsMargins(0, 0, 0, 0);
|
_layout->setContentsMargins(0, 0, 0, 0);
|
||||||
_layout2->setContentsMargins(0, 0, 0, 0);
|
_layout2->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
const bool showVariableMapping =
|
||||||
|
action == MacroActionTwitch::Action::CHANNEL_GET_INFO ||
|
||||||
|
action == MacroActionTwitch::Action::USER_GET_INFO ||
|
||||||
|
action == MacroActionTwitch::Action::POINTS_REWARD_GET_INFO;
|
||||||
|
emit ShowVariableMappings(showVariableMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionTwitchEdit::UpdateEntryData()
|
void MacroActionTwitchEdit::UpdateEntryData()
|
||||||
|
|||||||
@@ -267,6 +267,7 @@ private slots:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
void ShowVariableMappings(bool show);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<MacroActionTwitch> _entryData;
|
std::shared_ptr<MacroActionTwitch> _entryData;
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ static bool setupTwitchTokenSupport()
|
|||||||
{
|
{
|
||||||
AddSaveStep(saveConnections);
|
AddSaveStep(saveConnections);
|
||||||
AddLoadStep(loadConnections);
|
AddLoadStep(loadConnections);
|
||||||
|
AddPluginCleanupStep([]() { twitchTokens.clear(); });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -187,6 +187,13 @@ target_sources(
|
|||||||
${ADVSS_SOURCE_DIR}/lib/utils/file-selection.cpp
|
${ADVSS_SOURCE_DIR}/lib/utils/file-selection.cpp
|
||||||
${ADVSS_SOURCE_DIR}/lib/variables/variable-text-edit.cpp)
|
${ADVSS_SOURCE_DIR}/lib/variables/variable-text-edit.cpp)
|
||||||
|
|
||||||
|
# --- macro-condition-process --- #
|
||||||
|
|
||||||
|
target_sources(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
PRIVATE test-macro-condition-process.cpp stubs/platform-funcs.cpp
|
||||||
|
${ADVSS_SOURCE_DIR}/plugins/base/macro-condition-process.cpp)
|
||||||
|
|
||||||
# --- Testing --- #
|
# --- Testing --- #
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|||||||
101
tests/stubs/platform-funcs.cpp
Normal file
101
tests/stubs/platform-funcs.cpp
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
#include "platform-funcs.hpp"
|
||||||
|
#include "selection-helpers.hpp"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::string g_foregroundProcessName;
|
||||||
|
std::string g_foregroundProcessPath;
|
||||||
|
QStringList g_processList;
|
||||||
|
QStringList g_processPathsFromName;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void SetStubForegroundProcessName(const std::string &name)
|
||||||
|
{
|
||||||
|
g_foregroundProcessName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetStubForegroundProcessPath(const std::string &path)
|
||||||
|
{
|
||||||
|
g_foregroundProcessPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetStubProcessList(const QStringList &list)
|
||||||
|
{
|
||||||
|
g_processList = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetStubProcessPaths(const QStringList &paths)
|
||||||
|
{
|
||||||
|
g_processPathsFromName = paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- platform-funcs.hpp stubs ---
|
||||||
|
|
||||||
|
std::vector<std::string> GetWindowList()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetCurrentWindowTitle()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsFullscreen(const std::string &)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsMaximized(const std::string &)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> GetTextInWindow(const std::string &)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
int SecondsSinceLastInput()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList GetProcessList()
|
||||||
|
{
|
||||||
|
return g_processList;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetForegroundProcessName()
|
||||||
|
{
|
||||||
|
return g_foregroundProcessName;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetForegroundProcessPath()
|
||||||
|
{
|
||||||
|
return g_foregroundProcessPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList GetProcessPathsFromName(const QString &)
|
||||||
|
{
|
||||||
|
return g_processPathsFromName;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInFocus(const QString &)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- selection-helpers.hpp stubs ---
|
||||||
|
|
||||||
|
void PopulateProcessSelection(QComboBox *, bool) {}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -4,6 +4,8 @@ namespace advss {
|
|||||||
|
|
||||||
void SavePluginSettings(obs_data_t *) {}
|
void SavePluginSettings(obs_data_t *) {}
|
||||||
void LoadPluginSettings(obs_data_t *) {}
|
void LoadPluginSettings(obs_data_t *) {}
|
||||||
|
void AddEarlySaveStep(std::function<void(obs_data_t *)>) {}
|
||||||
|
void AddEarlyLoadStep(std::function<void(obs_data_t *)>) {}
|
||||||
void AddSaveStep(std::function<void(obs_data_t *)>) {}
|
void AddSaveStep(std::function<void(obs_data_t *)>) {}
|
||||||
void AddLoadStep(std::function<void(obs_data_t *)>) {}
|
void AddLoadStep(std::function<void(obs_data_t *)>) {}
|
||||||
void AddPostLoadStep(std::function<void()>) {}
|
void AddPostLoadStep(std::function<void()>) {}
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ using advss::MacroConditionFile;
|
|||||||
static void writeFile(const QString &path, const QString &content)
|
static void writeFile(const QString &path, const QString &content)
|
||||||
{
|
{
|
||||||
QFile f(path);
|
QFile f(path);
|
||||||
f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
|
if (!f.open(QIODevice::WriteOnly | QIODevice::Text |
|
||||||
|
QIODevice::Truncate)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
QTextStream(&f) << content;
|
QTextStream(&f) << content;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +158,9 @@ TEST_CASE("DATE_CHANGE: triggers when modification date changes",
|
|||||||
// Explicitly set the modification time to a known future value so the
|
// Explicitly set the modification time to a known future value so the
|
||||||
// test is not sensitive to filesystem mtime resolution.
|
// test is not sensitive to filesystem mtime resolution.
|
||||||
QFile f(path);
|
QFile f(path);
|
||||||
f.open(QIODevice::ReadWrite);
|
if (!f.open(QIODevice::ReadWrite)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
f.setFileTime(QDateTime::currentDateTime().addSecs(10),
|
f.setFileTime(QDateTime::currentDateTime().addSecs(10),
|
||||||
QFileDevice::FileModificationTime);
|
QFileDevice::FileModificationTime);
|
||||||
f.close();
|
f.close();
|
||||||
|
|||||||
170
tests/test-macro-condition-process.cpp
Normal file
170
tests/test-macro-condition-process.cpp
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
#include "catch.hpp"
|
||||||
|
#include "macro-condition-process.hpp"
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
void SetStubForegroundProcessName(const std::string &);
|
||||||
|
void SetStubForegroundProcessPath(const std::string &);
|
||||||
|
void SetStubProcessList(const QStringList &);
|
||||||
|
void SetStubProcessPaths(const QStringList &);
|
||||||
|
} // namespace advss
|
||||||
|
|
||||||
|
using advss::MacroConditionProcess;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Name matching — no focus, no path
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TEST_CASE("no focus: exact name match returns true",
|
||||||
|
"[macro-condition-process]")
|
||||||
|
{
|
||||||
|
advss::SetStubProcessList({"game.exe", "obs64.exe"});
|
||||||
|
|
||||||
|
MacroConditionProcess cond(nullptr);
|
||||||
|
cond._process = "game.exe";
|
||||||
|
cond._checkFocus = false;
|
||||||
|
|
||||||
|
REQUIRE(cond.CheckCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("no focus: exact name mismatch returns false",
|
||||||
|
"[macro-condition-process]")
|
||||||
|
{
|
||||||
|
advss::SetStubProcessList({"obs64.exe"});
|
||||||
|
|
||||||
|
MacroConditionProcess cond(nullptr);
|
||||||
|
cond._process = "game.exe";
|
||||||
|
cond._checkFocus = false;
|
||||||
|
|
||||||
|
REQUIRE_FALSE(cond.CheckCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("no focus: regex name match returns true",
|
||||||
|
"[macro-condition-process]")
|
||||||
|
{
|
||||||
|
advss::SetStubProcessList({"game.exe", "obs64.exe"});
|
||||||
|
|
||||||
|
MacroConditionProcess cond(nullptr);
|
||||||
|
cond._process = "game.*";
|
||||||
|
cond._checkFocus = false;
|
||||||
|
cond._regex.SetEnabled(true);
|
||||||
|
|
||||||
|
REQUIRE(cond.CheckCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("no focus: regex name mismatch returns false",
|
||||||
|
"[macro-condition-process]")
|
||||||
|
{
|
||||||
|
advss::SetStubProcessList({"obs64.exe"});
|
||||||
|
|
||||||
|
MacroConditionProcess cond(nullptr);
|
||||||
|
cond._process = "game.*";
|
||||||
|
cond._checkFocus = false;
|
||||||
|
cond._regex.SetEnabled(true);
|
||||||
|
|
||||||
|
REQUIRE_FALSE(cond.CheckCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Focus — name only
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TEST_CASE("focus: foreground name matches returns true",
|
||||||
|
"[macro-condition-process]")
|
||||||
|
{
|
||||||
|
advss::SetStubForegroundProcessName("game.exe");
|
||||||
|
advss::SetStubForegroundProcessPath("C:/Games/Game/game.exe");
|
||||||
|
|
||||||
|
MacroConditionProcess cond(nullptr);
|
||||||
|
cond._process = "game.exe";
|
||||||
|
cond._checkFocus = true;
|
||||||
|
|
||||||
|
REQUIRE(cond.CheckCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("focus: foreground name does not match returns false",
|
||||||
|
"[macro-condition-process]")
|
||||||
|
{
|
||||||
|
advss::SetStubForegroundProcessName("obs64.exe");
|
||||||
|
advss::SetStubForegroundProcessPath("C:/OBS/obs64.exe");
|
||||||
|
|
||||||
|
MacroConditionProcess cond(nullptr);
|
||||||
|
cond._process = "game.exe";
|
||||||
|
cond._checkFocus = true;
|
||||||
|
|
||||||
|
REQUIRE_FALSE(cond.CheckCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Path matching — no focus
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TEST_CASE("no focus with path: name and path both match returns true",
|
||||||
|
"[macro-condition-process]")
|
||||||
|
{
|
||||||
|
advss::SetStubProcessList({"game.exe"});
|
||||||
|
advss::SetStubProcessPaths({"C:/Steam/steamapps/common/Game/game.exe"});
|
||||||
|
|
||||||
|
MacroConditionProcess cond(nullptr);
|
||||||
|
cond._process = "game.exe";
|
||||||
|
cond._checkFocus = false;
|
||||||
|
cond._checkPath = true;
|
||||||
|
cond._processPath = "C:/Steam/steamapps/common/Game/game.exe";
|
||||||
|
|
||||||
|
REQUIRE(cond.CheckCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("no focus with path: name matches but path does not returns false",
|
||||||
|
"[macro-condition-process]")
|
||||||
|
{
|
||||||
|
advss::SetStubProcessList({"game.exe"});
|
||||||
|
advss::SetStubProcessPaths({"C:/Epic/Games/Game/game.exe"});
|
||||||
|
|
||||||
|
MacroConditionProcess cond(nullptr);
|
||||||
|
cond._process = "game.exe";
|
||||||
|
cond._checkFocus = false;
|
||||||
|
cond._checkPath = true;
|
||||||
|
cond._processPath = "Steam";
|
||||||
|
|
||||||
|
REQUIRE_FALSE(cond.CheckCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Focus + path
|
||||||
|
//
|
||||||
|
// When both focus and path are checked, both must be satisfied by the *same*
|
||||||
|
// foreground process instance. A background process that matches the path
|
||||||
|
// but is not in focus must not cause a false positive.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TEST_CASE("focus with path: foreground matches both name and path returns true",
|
||||||
|
"[macro-condition-process]")
|
||||||
|
{
|
||||||
|
advss::SetStubForegroundProcessName("game.exe");
|
||||||
|
advss::SetStubForegroundProcessPath(
|
||||||
|
"C:/Steam/steamapps/common/Game/game.exe");
|
||||||
|
|
||||||
|
MacroConditionProcess cond(nullptr);
|
||||||
|
cond._process = "game.exe";
|
||||||
|
cond._checkFocus = true;
|
||||||
|
cond._checkPath = true;
|
||||||
|
cond._processPath = "C:/Steam/steamapps/common/Game/game.exe";
|
||||||
|
|
||||||
|
REQUIRE(cond.CheckCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE(
|
||||||
|
"focus with path: foreground name matches but path does not returns false",
|
||||||
|
"[macro-condition-process]")
|
||||||
|
{
|
||||||
|
advss::SetStubForegroundProcessName("game.exe");
|
||||||
|
advss::SetStubForegroundProcessPath("C:/Epic/Games/Game/game.exe");
|
||||||
|
advss::SetStubProcessPaths({"C:/Steam/steamapps/common/Game/game.exe"});
|
||||||
|
|
||||||
|
MacroConditionProcess cond(nullptr);
|
||||||
|
cond._process = "game.exe";
|
||||||
|
cond._checkFocus = true;
|
||||||
|
cond._checkPath = true;
|
||||||
|
cond._processPath = "C:/Steam/steamapps/common/Game/game.exe";
|
||||||
|
|
||||||
|
REQUIRE_FALSE(cond.CheckCondition());
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user