Based on if a process (command line) is running or not/window existing, Autoswitch can:
- Automatically set default audio playback device
- Automatically set primary monitor
- Automatically black out unused screens
The app is portable. I use black GUIs to black out the monitors. That way the monitor numbering remains the same and windows don't jump everywhere.
This is alpha so there will 'probably' be bugs.
CODE
Autoswitch.ahk
Code: Select all
Version=Autoswitch v0.14 alpha
#SingleInstance, Force
FileInstall, MultiMonitorTool.exe, MultiMonitorTool.exe
g:={}
Global g, HandlerName, Pause, SoftwareName
SoftwareName:="Autoswitch"
MultiMonitorToolList()
While (VA_GetDevice("playback:" A_Index) != 0)
g["Audio out","Device index",A_Index] := VA_GetDevice("playback:" A_Index)
for Number, Device in g["Audio out","Device index"]
g["Audio out","Device name",A_Index] := VA_GetDeviceName(Device)
Menu, Tray, Add, &Show / hide, GuiToggle
; Menu, Tray, Add, Start with &windows, Startup
Menu, Tray, Add, &Donate, Donate
; Menu, Tray, Add, &Pause, Pause
Menu, Tray, Add, &Restart, Restart
Menu, Tray, Add, &Exit, ExitApp
Menu, Tray, Default, &Show / hide
Menu, Tray, NoStandard
GUI()
GUI()
{
Global
GUI +HWNDHandlerName +Delimiter`n
g["GUI","Width"]:=1200
g["GUI","HalfWidth"]:=590
g["GUI","xMargin"]:=10
g["GUI","yMargin"]:=2
;GUI
GUI +HWNDHandlerName +Delimiter`n
GUI, 1: Margin, % g["GUI","xMargin"], % g["GUI","yMargin"]
GUI, 1: Add, Text, % "vVideoOutInactiveText", % "Inactive video out"
GUI, 1: Add, Listbox, % "w" g["GUI","HalfWidth"] " r6 gSave vVideoOutInactive"
for Number, Name in g["Video out","name"]
GUIControl,, VideoOutInactive, % g["Video out","monitor_string",Number] " [" g["Video out","monitor_id",Number] "]"
GUI, 1: Add, Text, % "vBlackOutInactiveText", % "Inactive black out"
GUI, 1: Add, Listbox, % "w" g["GUI","HalfWidth"] " 8 r6 gSave vBlackOutInactive"
for Number, Name in g["Video out","name"]
GUIControl,, BlackOutInactive, % g["Video out","monitor_string",Number] " [" g["Video out","monitor_id",Number] "]"
GUI, 1: Add, Text, % "vAudioOutInactiveText", % "Inactive audio out"
GUI, 1: Add, Listbox, % "w" g["GUI","HalfWidth"] " r6 gSave vAudioOutInactive"
for Number, Name in g["Audio out","Device name"]
GUIControl,, AudioOutInactive, % Name
GUI, 1: Add, Checkbox, % "w" g["GUI","HalfWidth"] " gSave vNightLightInactive", Night light
GUI, 1: Add, Checkbox, % "w" g["GUI","HalfWidth"] " gSave vGraphicsDriverInactive", Reload graphics card driver
GUI, 1: Add, Text, % "vProcessesText", % "If found in running processes command line / window exist = active (separate by individual lines)"
GUI, 1: Add, Edit, % "w" g["GUI","Width"]-g["GUI","xMargin"] " vProcesses gSave r5 Multi"
GUI, 1: Add, Text, % "x" g["GUI","HalfWidth"]+20 " y" g["GUI","yMargin"] " vVideoOutActiveText", % "Active video out"
GUI, 1: Add, Listbox, % "w" g["GUI","HalfWidth"] " r6 gSave vVideoOutActive"
for Number, Name in g["Video out","name"]
GUIControl,, VideoOutActive, % g["Video out","monitor_string",Number] " [" g["Video out","monitor_id",Number] "]"
GUI, 1: Add, Text, % " vBlackOutActiveText", % "Active black out"
GUI, 1: Add, Listbox, % "w" g["GUI","HalfWidth"] " 8 r6 gSave vBlackOutActive"
for Number, Name in g["Video out","name"]
GUIControl,, BlackOutActive, % g["Video out","monitor_string",Number] " [" g["Video out","monitor_id",Number] "]"
GUI, 1: Add, Text, % "vAudioOutActiveText", % "Active audio out"
GUI, 1: Add, Listbox, % "w" g["GUI","HalfWidth"] " r6 gSave vAudioOutActive"
for Number, Name in g["Audio out","Device name"]
GUIControl,, AudioOutActive, % Name
GUI, 1: Add, Checkbox, % "w" g["GUI","HalfWidth"] " Right gSave vNightLightActive", Night light
GUI, 1: Add, Checkbox, % "w" g["GUI","HalfWidth"] " Right gSave vGraphicsDriverActive", Reload graphics card driver
g["Submit"]:="AudioOutActive,AudioOutInactive,VideoOutActive,VideoOutInactive,BlackOutActive,BlackOutInactive,NightLightActive,NightLightInactive,GraphicsDriverActive,GraphicsDriverInactive,Processes"
Load()
GUI, 1: Show, % "w" g["GUI","Width"]+g["GUI","xMargin"], % Version
Scan()
SetTimer, Scan, 1000
}
Load()
{
Global
for Number, Entry in StrSplit(g["Submit"],",")
{
IniRead, Read, settings.ini, Settings, % Entry, % A_Space
GuiControl, Choose, % Entry, % Read
if (Entry = "Processes")
GuiControl, Text, % Entry, % StrReplace(Read,"|","`n")
if (Entry = "BlackOutActive") or (Entry = "BlackOutInactive")
for a, Line in StrSplit(Read,"|")
GuiControl, Choose, % Entry, % Line
if (Entry = "NightLightActive") or (Entry = "NightLightInactive") or (Entry = "GraphicsDriverActive") or (Entry = "GraphicsDriverInactive")
GuiControl,, % Entry, % Read
}
}
Save()
{
Global
SetTimer, Scan, 1000
Gui, 1: Submit, NoHide
Processes:=StrReplace(Processes,"`n","|")
BlackOutActive:=StrReplace(BlackOutActive,"`n","|")
BlackOutInactive:=StrReplace(BlackOutInactive,"`n","|")
for Number, Entry in StrSplit(g["Submit"],",")
IniWrite, % %Entry%, settings.ini, Settings, % Entry
}
Scan()
{
Global
Fill:=""
for Number, Entry in StrSplit(g["Submit"],",")
{
if (Entry != "Processes")
{
GUIControl, +AltSubmit, %Entry%
GUIControlGet, %Entry%
GUIControl, -AltSubmit, %Entry%
}
else
GUIControlGet, %Entry%
}
Active:=0
;Processmatch
for process in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process")
{
if (process.CommandLine != "")
{
CL:=Trim(StrReplace(process.CommandLine,"""","",,2)," ")
CL:=StrReplace(CL,"/","\")
for Number, Entry in StrSplit(Processes,"`n")
if (InStr(CL,Entry)=1)
Active:=1, ActiveProcess:=process.Name
}
}
;Window match
for Number, Entry in StrSplit(Processes,"`n")
if (InStr(Entry,"ahk_")=1)
if WinExist(Entry)
Active:=1, ActiveProcess:=Entry
if (Active = 1)
{
if (g["Audio out","Device index",AudioOutActive] != previousAudioOut) and (g["Audio out","Device name",AudioOutActive] != VA_GetDeviceName(VA_GetDevice("playback"))) and (g["Audio out","Device index",AudioOutActive] != "")
{
VA_SetDefaultEndPoint(g["Audio out","Device index",AudioOutActive],1)
Fill.="Audio out:`n" SubStr(g["Audio out","Device name",AudioOutActive], 1 , 25) "`n"
previousAudioOut := g["Audio out","Device index",AudioOutActive]
}
if (g["Video out","monitor_string",VideoOutActive] " [" g["Video out","monitor_id",VideoOutActive] "]" != previousVideoOut) and (g["Video out","monitor_id",VideoOutActive] != "")
{
RunWait, % "MultiMonitorTool.exe /SetPrimary " """" g["Video out","monitor_id",VideoOutActive] """",, HIDE
Fill.="Video out: " VideoOutActive "`n"
previousVideoOut := g["Video out","monitor_string",VideoOutActive] " [" g["Video out","monitor_id",VideoOutActive] "]"
}
if (BlackOutActive != previousBlackOut)
{
Fill.=Blackout(BlackOutActive) "`n"
previousBlackOut := BlackOutActive
}
if (NightLightActive != previousNightLight)
{
Fill.=NightLight(NightLightActive) "`n"
previousNightLight := NightLightActive
}
if (GraphicsDriverActive != previousGraphicsDriver)
{
Fill.=GraphicsDriver() "`n"
previousGraphicsDriver := GraphicsDriverActive
}
if (Fill != "")
{
TrayTip, % "Autoswitch active (" ActiveProcess ")", % Fill, 3
;GUI, 1: Show, NA, % Version " (Active: " ActiveProcess ")"
WinSetTitle, ahk_id %HandlerName%,, % Version " (Active: " ActiveProcess ")"
}
}
else if (Active = 0)
{
if (g["Audio out","Device index",AudioOutInactive] != previousAudioOut) and (g["Audio out","Device name",AudioOutInactive] != VA_GetDeviceName(VA_GetDevice("playback"))) and (g["Audio out","Device index",AudioOutInactive] != "")
{
VA_SetDefaultEndPoint(g["Audio out","Device index",AudioOutInactive],1)
Fill.="Audio out: " SubStr(g["Audio out","Device name",AudioOutInactive], 1 , 25) "`n"
previousAudioOut := g["Audio out","Device index",AudioOutInactive]
}
if (g["Video out","monitor_string",VideoOutInactive] " [" g["Video out","monitor_id",VideoOutInactive] "]" != previousVideoOut) and (g["Video out","monitor_id",VideoOutInactive] != "")
{
RunWait, % "MultiMonitorTool.exe /SetPrimary " """" g["Video out","monitor_id",VideoOutInactive] """",, HIDE
Fill.="Video out: " VideoOutInactive "`n"
previousVideoOut := g["Video out","monitor_string",VideoOutInactive] " [" g["Video out","monitor_id",VideoOutInactive] "]"
}
if (BlackOutInactive != previousBlackOut)
{
Fill.=Blackout(BlackOutInactive) "`n"
previousBlackOut := BlackOutInactive
}
if (NightLightInactive != previousNightLight)
{
Fill.=NightLight(NightLightInactive) "`n"
previousNightLight := NightLightInactive
}
if (GraphicsDriverInactive != previousGraphicsDriver)
{
Fill.=GraphicsDriver() "`n"
previousGraphicsDriver := GraphicsDriverInactive
}
if (Fill != "")
{
TrayTip, % "Autoswitch inactive", % Fill, 3
;GUI, 1: Show, NA, % Version " (Inactive)"
WinSetTitle, ahk_id %HandlerName%,, % Version " (Inactive)"
}
}
}
GuiToggle()
{
IfWinExist, ahk_id %HandlerName%
Gui, Hide
else
{
Gui, Show
WinSet, ReDraw,, ahk_id %HandlerName%
}
return
}
; Startup()
; {
; RegRead, Startup, HKEY_LOCAL_MACHINE, Software\Microsoft\Windows\CurrentVersion\Run, %SoftwareName%
; if (A_ThisMenuItem = "Start with &windows")
; {
; if (Startup = "")
; {
; RegWrite, REG_SZ, HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run, %SoftwareName%, "%A_ScriptFullPath%"
; msgbox, %SoftwareName% "%A_ScriptFullPath%" %errorlevel%
; Menu, Tray, Check, Start with &windows
; }
; else
; {
; RegDelete, HKEY_LOCAL_MACHINE, Software\Microsoft\Windows\CurrentVersion\Run, %SoftwareName%
; Menu, Tray, Uncheck, Start with &windows
; }
; }
; else if (Startup != "") ;software start
; Menu, Tray, Check, Start with &windows
; }
Restart()
{
Reload
}
ExitApp()
{
ExitApp()
}
Donate()
{
Clipboard=BTC: 37L31tLHRWxmGxYuJnczEUQLD6hvMQTpXo`tETH (+ERC20): 0xAD69Bf1Ba107C542d6172531A7fF4E0c25482D14`tIOTA: 9ETOKOTYEDEHFEGCSXH9CDOCY9QVN9ZGPGDKQASXDYRAGXVBQUBMGTBTBOGANLQVPQWBAWZWZALJMKEQ9UFQGCJJGA
TrayTip, % "Check clipboard", % "Donation addresses copied", 3
}
Blackout(Blackout)
{
MultiMonitorToolList() ;this needs to be refreshed after primary screen has changed
;Destroy all GUI black screens
for Number, Name in g["Video out","name"]
Gui, % (A_Index+1) ": Destroy"
; Sleep, 500
;Create all GUI black screens
for a, Entry in StrSplit(Blackout,"`n")
{
; msgbox % Entry "vs " g["map",Entry]
WH:=StrSplit(g["Video out","resolution",Entry]," X ")
LT:=StrSplit(g["Video out","left-top",Entry],", ")
if (WH[1] = "") or if (WH[2] = "")
continue
GUI, % (A_Index+1) ": +ToolWindow -Border -Caption +AlwaysOnTop"
GUI, % (A_Index+1) ": Color", Black
; msgbox % "x" LT[1] " y" LT[2] " w" WH[1] "h " WH[2] " NoActivate"
GUI, % (A_Index+1) ": Show", % "x" LT[1] " y" LT[2] " w" WH[1] "h " WH[2] " NoActivate"
Fill.=Entry ", "
}
if (Fill != "")
Fill:="Black out: " Trim(Fill,", ")
Return Fill
}
NightLight(Set)
{
SetRegView, 64
if (Set = 1)
{
State:="On"
RegWrite, REG_BINARY, HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\CloudStore\Store\Cache\DefaultAccount\$$windows.data.bluelightreduction.bluelightreductionstate\Current, Data, 0200000049cf237980bdd40100000000434201001000d00a02c614a68a8fc987b0afea0100
; RegWrite, REG_BINARY, HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\CloudStore\Store\DefaultAccount\Current\default$windows.data.bluelightreduction.bluelightreductionstate\windows.data.bluelightreduction.bluelightreductionstate, Data, 434201000a0201002a068bff96eb052a2b0e1043420100c6149499a58a8ea6d7ea0100000000
; RegWrite, REG_BINARY, HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\CloudStore\Store\DefaultAccount\Current\default$windows.data.bluelightreduction.settings\windows.data.bluelightreduction.settings, Data, 434201000a0201002a068bff96eb052a2b0e2143420100ca140e1500ca1e0e0700cf28f029ca320e152e0300ca3c0e062e140000000000
}
else
{
State:="Off"
RegWrite, REG_BINARY, HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\CloudStore\Store\Cache\DefaultAccount\$$windows.data.bluelightreduction.bluelightreductionstate\Current, Data, 02000000f02bf06680bdd4010000000043420100d00a02c6148d99c0b786b0afea0100
; RegWrite, REG_BINARY, HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\CloudStore\Store\DefaultAccount\Current\default$windows.data.bluelightreduction.bluelightreductionstate\windows.data.bluelightreduction.bluelightreductionstate, Data, 434201000a0201002a06eafe96eb052a2b0e12434201001000c6148bbabbed8ca6d7ea0100000000
; RegWrite, REG_BINARY, HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\CloudStore\Store\DefaultAccount\Current\default$windows.data.bluelightreduction.settings\windows.data.bluelightreduction.settings, Data, 434201000a0201002a06ebfe96eb052a2b0e23434201000201ca140e1500ca1e0e0700cf28f029ca320e152e0300ca3c0e062e140000000000
}
Return "Night light: " State
}
GraphicsDriver()
{
Send ^+#{B}
Return "Graphics card driver: Reloaded"
}
MultiMonitorToolList()
{
RunWait, % "MultiMonitorTool.exe /sxml MultiMonitorToolList.xml",, HIDE
for Item in XML("MultiMonitorToolList.xml",,"//item") ; \\.\DISPLAY 1, 2, 3 is used for order
{
Number:=A_Index
; for Node in Item.childNodes
; if (Node.nodeName = "name")
; g["map",Number]:=StrReplace(Node.text,"\\.\DISPLAY","") ;these need a map because numbers can be 1,2, 5 etc
for Node in Item.childNodes
g["Video out",Node.nodeName,Number]:=Node.text
}
}
#Include %A_ScriptDir%\VA.ahk
#Include %A_ScriptDir%\XML.ahk
Code: Select all
XML(XMLcontent,Node="",Nodes="")
{
static XML
static Filename
;Save XML
if(XMLcontent="Save") ; and (XML.xml != "") <-- maybe insert this
{
if (XML.xml = "")
{
Message.Negative("Unable to save XML",Filename)
; msgbox, wait
Return
}
;Transform / indent XML
XML.transformNodeToObject(style(),XML)
;Save to file
XML.save(Filename)
Return
}
;Create object if it does not exist
if (!IsObject(XML))
{
XML := ComObjCreate("MSXML2.DOMDocument.6.0") ; this used to be ComObjCreate("MSXML2.DOMDocument")
XML.setProperty("SelectionLanguage", "XPath") ;// for XP and below
XML.async := false
}
SplitPath, XMLcontent,,, OutExtension
if (OutExtension = "xml") or (OutExtension = "log") or (OutExtension = "config") ;file
{
;Load XML into DocumentObject object
XML.load(XMLcontent)
Filename:=XMLcontent
}
else ;content (not file)
{
;Load XML into DocumentObject object
XML.loadXML(XMLcontent)
}
if (Nodes != "")
{
;Select nodes to read
selectedNodes := XML.selectNodes(Nodes)
;Return entire node object
Return selectedNodes
}
else
{
;Select node to read
selectedNode := XML.selectSingleNode(Node) ;// select the 'child_1' node
;Return entire node object
Return selectedNode
}
}
style(){
static xsl
; I CANT USE INDENT CAUSE MOSART DOESN
if !IsObject(xsl) {
RegExMatch(ComObjType(this.doc, "Name"), "IXMLDOMDocument\K(?:\d|$)", m)
MSXML := "MSXML2.DOMDocument.6.0" ;this used to be "MSXML2.DOMDocument" (m < 3 ? "" : ".6.0")
xsl := ComObjCreate(MSXML)
style =
(LTrim
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="no" encoding="UTF-8"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:for-each select="@*">
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
)
xsl.loadXML(style), style := NULL
}
return xsl
}
Unescape(Content)
{
Content:=StrReplace(Content,"'","'")
Content:=StrReplace(Content,""","""")
Content:=StrReplace(Content,"&","&")
Content:=StrReplace(Content,"<","<")
Content:=StrReplace(Content,">",">")
; msgbox % Content
Return Content
}
Use ahk_class CUIEngineWin32
KNOWN LIMITATIONS
- Currently it does not detect new devices without an app restart
- It does not set default audio communication device (easy to fix, but not sure if anyone needs)
Nir Sofer for MultiMonitorTool: https://www.nirsoft.net/utils/multi_monitor_tool.html
lexikos for Vista Audio Control Functions: https://autohotkey.com/board/topic/21984-vista-audio-control-functions