#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance force
#Persistent ; Keeps a script permanently running, until ExitApp is encountered
#UseHook
#MaxHotkeysPerInterval 200 ; allow more keys
DetectHiddenWindows On ; Used for retriving the application path
SetBatchLines -1 ; Run with maximum speed
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
AutoTrim, Off ; do not auto trim strings
OnExit, ExitProgram ; exit event
OnMessage(0x404, "notifyIcon") ; Left click tray event
OnMessage(0x7E, "DisplayChange") ; fire on display resolution change
Gui +LastFound ; shell message hook
hWnd := WinExist()
AppName = One Audio Tool
RegName = One Key Tool
WinGet, prevWinID, ID, A
settimer, actPrevWin, -100 ; activate previous window
; --------------------------------------
; Volume Configuration
; --------------------------------------
; The percentage by which to raise or lower the volume each time
vol_Step_def = 10
vol_Step := vol_Step_def
; How long to display the volume level bar graphs (in milliseconds)
vol_DisplayTime = 2000
; Transparency of window (0-255)
vol_TransValue = 255
; Bar's background and text colour
vol_CW = EEEEEE
vol_Col_def = 3333AA
vol_Col_rdp = 333333
vol_Col := vol_Col_def
vol_Width = 220 ; width of bar
vol_Thick = 21 ; thickness of bar
vol_PosX :=
vol_PosY :=
vol_XY :=
vol_oldXY := 0
;getResolution()
vol_text :=
; get current volume setting
vol_Master := VA_GetMasterVolume()
; initilize Volume OSD and dim layer
gosub, getResolution
; ---------------------------------------
; Read Settings
; ---------------------------------------
; Registry location to save the settings
reg_root = HKEY_CURRENT_USER
reg_path = Software\%RegName%
reg_path_run = Software\Microsoft\Windows\CurrentVersion\Run
modeBlock0 = Disabled
modeBlock1 = Always On
modeBlock2 = Only via RDP
nameRun = Run on Windows start
RegRead, enableAutorun, %reg_root%, %reg_path_run%, %Regname%
enableAutorun := ErrorLevel ? false : enableAutorun
RegRead, enableVol, %reg_root%, %reg_path%, enableVolume
enableVol := ErrorLevel ? true : enableVol
RegRead, newValue, %reg_root%, %reg_path%, valueVolume
vol_step := ErrorLevel ? vol_step : newValue
applySettings()
; Load Audio App substitude
audioApps =
audioAppFind =
audioAppNum = 0
getAudioApps()
; ---------------------------------------
; Tray Menu
; ---------------------------------------
Menu, TRAY, Tip, %AppName%
if A_IsCompiled
Menu, TRAY, NoStandard
Menu, TRAY, Add, About %AppName%, TrayAbout
Menu, TRAY, Add ; Separator
Menu, TRAY, Add, %nameRun%, menuAutorun
if (enableAutorun)
Menu, TRAY, Check, %nameRun%
else
Menu, TRAY, Uncheck, %nameRun%
Menu, TRAY, Add, Settings..., TraySettings
Menu, TRAY, Add ; Separator
if (A_IsCompiled != 1)
Menu, TRAY, Add, Reload Script, Reload
Menu, TRAY, Add, Disable, Disable
Menu, TRAY, Add, Exit, exitProgram
; ---------------------------------------
; GUI elements, Settings
; ---------------------------------------
Gui, Font, S10 CDefault, Verdana
Gui, Add, GroupBox, x20 y18 w390 h110 , Keyboard Controls
Gui, Add, CheckBox, x40 y38 w150 h30 vboxVolume Checked%enableVol%, Control volume
Gui, Add, Text, x240 y44 w60 h24 , Steps:
Gui, Add, Edit, veditVolume x300 y42 w90 h26
Gui, Add, UpDown, vtextVolume Range1-50, %vol_Step%
Gui, Add, Button, x60 y68 w200 h26 gAudioDialog, Configure Applications...
Gui, Font, S11 CDefault, Verdana
Gui, Add, Button, x60 y145 w110 h28 Default, OK
Gui, Add, Button, x180 y145 w110 h28 , Cancel
Gui, Add, Button, x300 y145 w110 h28 , Apply
; ---------------------------------------
; GUI elements, About
; ---------------------------------------
Gui, 2:Font, S14 W700, Verdana
Gui, 2:Add, Text, x20 y10 w400 h24 , %AppName%
Gui, 2:Font, S10 W400, Verdana
Gui, 2:Add, Text, x20 y40 w470 h15 , Version 1.0.1 (c) 2013 Volker Semken
Gui, 2:Add, Link, x20 y60 w470 h15 , Licensed under the <a href="http://opensource.org/licenses/MIT">MIT license</a>
Gui, 2:Add, Text, x20 y85 w470 h15 , Includes Vista Audio Control Functions, by Lexikos
Gui, 2:Add, Link, x20 y100 w470 h15 , Licensed under Public Domain and available <a href="http://www.autohotkey.com/board/topic/21984-vista-audio-control-functions/">here</a>
Gui, 2:Add, Link, x20 y125 w470 h15 , Audio control OSD thanks to <a href="http://www.autohotkey.com/docs/scripts/VolumeOSD.htm/">Rajat</a>
Gui, 2:Add, Link, x20 y150 w470 h15 , <a href="http://www.autohotkey.com/board/topic/78224-possible-to-monitor-and-pseudo-lock-per-app-volume/">Application Audio control</a> thanks to No_Speak_Eng and Lexikos
Gui, 2:Font, S11 W700, Verdana
Gui, 2:Add, Text, x20 y230 w400 h20 , Available Hotkeys
Gui, 2:Font, S10 W400, Verdana
Gui, 2:Add, Text, x20 y255 w400 h20 , Volume Control
Gui, 2:Add, Text, x220 y255 w400 h20 , Win-WheelUp/Down, Win-PageUp/Down
Gui, 2:Add, Text, x20 y275 w400 h20 , Application Volume Control
Gui, 2:Add, Text, x220 y275 w400 h20 , Win-Shift-WheelUp/Down/PageUp/Down
Gui, 2:Add, Text, x20 y295 w400 h20 , Volume Mute
Gui, 2:Add, Text, x220 y295 w400 h20 , Win-Del, Pause, Media Mute
Gui, Font, S11 CDefault, Verdana
Gui, 2:Add, Button, x175 y335 w130 h30 gAboutClose Default vClose, Close
GuiControl,2: Focus, Close
; Select audio applications
textHelp2 = Enter application name of the active window as it appears in the process list in the Task Manager.
textHelp2 := textHelp2 . " Separate the beginning of process name that instead should be controlled with a space character."
textHelp2 := textHelp2 . " Each line represents one application, up to 20 are supported."
Gui, 4:+Owner1
Gui, 4:Font, S10 W400, Verdana
Gui, 4:Add, Text, x20 y15 w370 h80, %textHelp2%
Gui, 4:Font, S10 W400, Lucida Console
Gui, 4:Add, Edit, x25 y105 w350 h150 r10 vtextAudioApps,
Gui, 4:Font, S11 CDefault, Verdana
Gui, 4:Add, Button, x50 y255 w100 h30 gAudioClose Default, OK
Gui, 4:Add, Button, x200 y255 w100 h30 gAudioCancel, Cancel
GuiControl,4: Focus, OK
; ---------------------------------------
Return ; End of Auto Execute Section
; ---------------------------------------
; ---------------------------------------
; retrive values from GUI and apply new values
; ---------------------------------------
retriveValues() {
global
enableVol = %boxVolume%
vol_Step = %textVolume%
RegWrite, REG_SZ, %reg_root%, %reg_path%, enableVolume, %boxVolume%
RegWrite, REG_SZ, %reg_root%, %reg_path%, valueVolume, %textVolume%
applySettings()
}
applySettings() {
global
if (strlen(trim(vol_step)) = 0)
vol_step := vol_step_def
Guicontrol, , textVolume, %vol_step%
if (enableVol) {
Hotkey, Volume_Up, VolumeUp, ON ; Media Volume
Hotkey, Volume_down, VolumeDown, ON ; Media Volume
Hotkey, #PgUp, VolumeUp, ON ; Win-PageUp
Hotkey, #PgDn, VolumeDown, ON ; Win-PageDown
Hotkey, $#WheelUp, VolumeUp, ON ; Win-MouseWheel
Hotkey, $#WheelDown, VolumeDown, ON ; Win-MouseWheel
Hotkey, #Delete, VolumeMute, ON ; Win-Delete
Hotkey, Volume_Mute, VolumeMute, ON ; Media Mute
Hotkey, Pause, VolumeMute, ON ; Media Mute
Hotkey, #+WheelUp, AppVolUp, ON ; App Volume Up
Hotkey, #+WheelDown, AppVolDown, ON ; App Volume Down
Hotkey, #+PgUp, AppVolUp, ON ; Win-Shift-PageUp
Hotkey, #+PgDn, AppVolDown, ON ; Win-Shift-PageDown
Hotkey, +Volume_Up, AppVolUp, ON ; Shift-Media Volume
Hotkey, +Volume_down, AppVolDown, ON ; Shift-Media Volume
} else {
Hotkey, Volume_Up, VolumeUp, OFF ; Media Volume
Hotkey, Volume_down, VolumeDown, OFF ; Media Volume
Hotkey, #PgUp, VolumeUp, OFF ; Win-PageUp
Hotkey, #PgDn, VolumeDown, OFF ; Win-PageDown
Hotkey, $#WheelUp, VolumeUp, OFF ; Win-MouseWheel
Hotkey, $#WheelDown, VolumeDown, OFF ; Win-MouseWheel
Hotkey, #Delete, VolumeMute, OFF ; Win-Delete
Hotkey, Volume_Mute, VolumeMute, OFF ; Media Mute
Hotkey, Pause, VolumeMute, OFF ; Media Mute
Hotkey, #+WheelUp, AppVolUp, OFF ; App Volume Up
Hotkey, #+WheelDown, AppVolDown, OFF ; App Volume Down
Hotkey, #+PgUp, AppVolUp, OFF ; Win-Shift-PageUp
Hotkey, #+PgDn, AppVolDown, OFF ; Win-Shift-PageDown
Hotkey, +Volume_Up, AppVolUp, OFF ; Shift-Media Volume
Hotkey, +Volume_down, AppVolDown, OFF ; Shift-Media Volume
}
}
getAudioApps() {
global
audioAppNum = 0
loop, 20
{
RegRead, getVal, %reg_root%, %reg_path%, audioApp%A_Index%
if !ErrorLevel && if Trim(getVal) <> ""
{
RegRead, getVal2, %reg_root%, %reg_path%, audioApp%A_Index%Value
if !ErrorLevel && if Trim(getVal2) <> ""
{
audioAppNum += 1
audioApps%audioAppNum% := trim(getVal)
audioAppFind%audioAppNum% := trim(getVal2)
}
} else
break
}
if audioAppNum = 0
{
audioApps1 := "firefox.exe"
audioAppFind1 := "FlashPlayerPlugin"
audioApps1 := "firefox.exe"
audioAppFind1 := "plugin-container.exe"
audioApps2 := "iexplore.exe"
audioAppFind2 := "iexplore.exe"
audioAppNum = 2
}
}
; ---------------------------------------
; Global events and triggers
; ---------------------------------------
ExitProgram:
ExitApp
F24::
^+q::
ExitApp
return
Reload:
Reload
return
Disable:
if disableHotkeys {
Menu, TRAY, Check, Disable
Suspend on
if A_IsCompiled ; would change to default H icon
Menu, Tray, Icon , %A_ScriptFullPath%, 1, 1
} else {
Menu, TRAY, Uncheck, Disable
Suspend off
}
disableHotkeys := !disableHotkeys
return
; activates previous active window
actPrevWin:
WinGet, PName, ProcessName, ahk_pid %curpid%
if PName <> Explorer.exe
WinActivate, ahk_id %prevWinID%
return
; ---------------------------------------
; Tray Menu Functions
; ---------------------------------------
TraySettings:
xpos := A_ScreenWidth / 2 - 430 / 2
ypos := A_ScreenHeight / 2 - 200 / 2
Gui, Show, x%xpos% y%ypos% h200 w430, %AppName% Settings
return
; Left Click Menu
notifyIcon(wParam, lParam) {
if (lParam = 0x202) { ; WM_LBUTTONUP
SetTimer, ShowRbuttonMenu, -1
return 0
}
}
TrayAbout:
xpos := A_ScreenWidth / 2 - 500 / 2
ypos := A_ScreenHeight / 2 - 400 / 2
Gui, 2:Show, x%xpos% y%ypos% h400 w500, About %AppName%
return
ShowRbuttonMenu:
Menu, Tray, Show
return
ButtonOK:
Gui, Submit
Gui, Hide
retriveValues()
return
GuiClose:
Gui, Submit
Gui, Hide
retriveValues()
return
ButtonCancel:
Gui, Hide
return
ButtonApply:
Gui, Submit, NoHide
retriveValues()
return
GuiEscape:
Gui, Hide
return
AboutClose:
Gui, 2:Hide
return
AudioDialog:
textAudioApps =
loop, %audioAppNum%
{
ta := audioApps%A_Index% . A_Space . audioAppFind%A_Index%
textAudioApps = %textAudioApps%%ta%`n
}
GuiControl, 4:, textAudioApps, %textAudioApps%
xpos := A_ScreenWidth / 2 - 400 / 2
ypos := A_ScreenHeight / 2 - 300 / 2
Gui, 4:Show, x%xpos% y%ypos% h300 w400, Configure Audio Control for Applications
Gui, 1:+Disabled
return
AudioClose:
Gui, 1:-Disabled
Gui, 4:Submit
Gui, 4:Hide
lastpos = 1
audioAppNum = 0
loop, parse, textAudioApps, `n
{
line := Trim(A_LoopField) ; trim leading characters
if line =
continue
delimpos := InStr(line, " ") ; position of delimiter, StringSplit did not work here
if (delimpos > 0) { ; must contain at least one white space
aname := Trim(SubStr(line, 1, delimpos - 1))
find := Trim(SubStr(line, delimpos + 1))
} else
continue
if Strlen(aname) = 0 || Strlen(find) = 0
continue
audioAppNum += 1
RegWrite, REG_SZ, %reg_root%, %reg_path%, audioApp%A_Index%, %aname%
RegWrite, REG_SZ, %reg_root%, %reg_path%, audioApp%A_Index%Value, %find%
if ErrorLevel
break
if audioAppNum = 20
break
}
lastpos := audioAppNum + 1
RegWrite, REG_SZ, %reg_root%, %reg_path%, audioApp%lastpos%
getAudioApps()
return
AudioCancel:
4GuiClose:
4GuiEscape:
Gui, 1:-Disabled
Gui, 4:Hide
return
; adds or removes the autorun entry
menuAutorun:
; get path of current AutoHotkey process, is active window, as it shows the tray menu
WinGet, pid, PID, A ; for testing on the active windo
h_process := DllCall("OpenProcess", UInt, 0x418, Int, 0, UInt,pid)
VarSetCapacity(FilePath, 255)
DllCall("psapi.dll\GetModuleFileNameEx" (A_IsUnicode ? "W" : "A"), UInt, h_process, UInt, 0, Str, FilePath, UInt, 255)
DllCall("CloseHandle", UInt, h_process)
enableAutorun := !enableAutorun
Menu, TRAY, ToggleCheck, %nameRun%
if enableAutorun
RegWrite, REG_SZ , %reg_root%, %reg_path_run%, %RegName%, %FilePath%
else
RegDelete, %reg_root%, %reg_path_run%, %RegName%
return
getResolution:
; volume bar OSD
vol_PosX := A_ScreenWidth - vol_Width - 50
vol_PosY := A_ScreenHeight - vol_Thick - 100
vol_XY := vol_PosX . "x" . vol_PosY
vol_oldXY := vol_XY
return
; ---------------------------------------
; Volume Functions for applications
; ---------------------------------------
; http://www.autohotkey.com/board/topic/78224-possible-to-monitor-and-pseudo-lock-per-app-volume/
AppVolUp:
setAppVolume(vol_step)
return
AppVolDown:
setAppVolume(-vol_step)
return
setAppVolume(vol_Step) {
global
Res :=
vol := -1
WinGet, Pid, PID, A
WinGet, ProcessName, ProcessName, ahk_pid %Pid%
if ProcessName = explorer.exe
Pid := 0 , ProcessName := "System sound", Title = "System sound"
appvol_list := Trim(VA_getPID_list(Pid, ProcessName))
loop, parse, appvol_list, %A_Space%
{
if (vol = -1) {
Res := VA_ISimpleAudioUse("Vol", vol_Step, A_LoopField)
if (Res <> "" && Res > 0)
vol := Res
} else
VA_ISimpleAudioUse("SetVol", vol, A_LoopField)
}
if (Res <> "") { ; if an app was found, show bar
StringReplace vol_Text, ProcessName, .exe,
StringLower, vol_Text, vol_Text, T
vol_Text := vol_Text . " " . (Res = 0 ? "muted" : Res)
IfWinNotExist, VolumeOSDxyz
setVolBar()
Progress, 1:%Res%, , %vol_Text%
SetTimer, vol_BarOff, %vol_DisplayTime%
}
VolumeDelay() ; start delay timer to delay futher steps
}
VA_getPID_list(Pid = "!", ProcessName = "") {
global
alist =
appType := 0
appToFind :=
loop, %audioAppNum% {
if audioApps%A_Index% = %ProcessName%
appToFind := appToFind . " " . audioAppFind%A_Index%
}
appToFind := trim(appToFind)
dev := VA_GetDevice()
if !dev
Return
if VA_IMMDevice_Activate(dev, "{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}", 7, 0, mgr) != 0 ; IID_IAudioSessionManager2
Return ObjRelease(dev)
if VA_IAudioSessionManager2_GetSessionEnumerator(mgr, enm) != 0
Return ObjRelease(mgr)
ObjRelease(mgr)
VA_IAudioSessionEnumerator_GetCount(enm, count)
Loop %count% {
VA_IAudioSessionEnumerator_GetSession(enm, A_Index-1, ssn)
VA_IAudioSessionControl2_GetProcessId(ssn, curpid)
if (Pid = curpid) ; process is in mixer list
alist := alist . " " . curpid
}
Loop %count% {
VA_IAudioSessionEnumerator_GetSession(enm, A_Index-1, ssn)
VA_IAudioSessionControl2_GetProcessId(ssn, curpid)
if (curpid > 0 && appType <> "") { ; find image name
WinGet, PName, ProcessName, ahk_pid %curpid%
Loop, parse, appToFind, %A_Space%
if Instr(PName, A_LoopField)
alist := alist . " " . curpid
}
}
return, alist
}
VA_ISimpleAudioUse(Key, Val = "", Pid = "!") {
dev := VA_GetDevice()
if !dev
Return
if VA_IMMDevice_Activate(dev, "{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}", 7, 0, mgr) != 0 ; IID_IAudioSessionManager2
Return ObjRelease(dev)
if VA_IAudioSessionManager2_GetSessionEnumerator(mgr, enm) != 0
Return ObjRelease(mgr)
ObjRelease(mgr)
VA_IAudioSessionEnumerator_GetCount(enm, count)
Loop %count% {
VA_IAudioSessionEnumerator_GetSession(enm, A_Index-1, ssn)
VA_IAudioSessionControl2_GetProcessId(ssn, curpid)
if (Pid = curpid) {
sav := ComObjQuery(ssn, "{87CE5498-68D6-44E5-9215-6DA47EF883D8}") ; IID_ISimpleAudioVolume
ObjRelease(ssn)
if !sav
Return
DllCall(NumGet(NumGet(sav+0)+6*A_PtrSize), "ptr", sav, "int*", mute) ; VA_ISimpleAudioVolume_GetMute
if (Key = "Vol") {
DllCall(NumGet(NumGet(sav+0)+4*A_PtrSize), "ptr", sav, "float*", volume) ; VA_ISimpleAudioVolume_GetMasterVolume
if (Val = "Get")
Return Round(volume*100), ObjRelease(sav), ObjRelease(enm)
if mute = 1
DllCall(NumGet(NumGet(sav+0)+5*A_PtrSize), "ptr", sav, "int", 0, "ptr", 0) ; VA_ISimpleAudioVolume_SetMute
vol := (volume + Val / 100)
vol := (vol > 1) ? 1 : (vol < 0) ? 0 : vol
DllCall(NumGet(NumGet(sav+0)+3*A_PtrSize), "ptr", sav, "float", vol, "ptr", 0) ; VA_ISimpleAudioVolume_SetMasterVolume
Return Round(vol*100), ObjRelease(sav), ObjRelease(enm)
}
if (Key = "Mute") {
if (Val = "Get")
Return mute, ObjRelease(sav), ObjRelease(enm)
DllCall(NumGet(NumGet(sav+0)+5*A_PtrSize), "ptr", sav, "int", mute := (Val = 2) ? !mute : Val, "ptr", 0) ; VA_ISimpleAudioVolume_SetMute
Return mute, ObjRelease(sav), ObjRelease(enm)
}
if (Key = "SetVol") {
if mute = 1
DllCall(NumGet(NumGet(sav+0)+5*A_PtrSize), "ptr", sav, "int", 0, "ptr", 0) ; VA_ISimpleAudioVolume_SetMute
DllCall(NumGet(NumGet(sav+0)+3*A_PtrSize), "ptr", sav, "float", Val / 100, "ptr", 0) ; VA_ISimpleAudioVolume_SetMasterVolume
Return Val, ObjRelease(sav), ObjRelease(enm)
}
}
ObjRelease(ssn), ListPid .= curpid "|"
}
ObjRelease(enm)
if (Key = "ListPid") {
Loop, parse, ListPid, |
List .= (WinExist("ahk_pid " A_LoopField) ? A_LoopField "|" : "")
Return RTrim( List, "|")
}
}
; ---------------------------------------
; Volume Control Functions
; ---------------------------------------
; http://www.autohotkey.com/board/topic/45383-vista-windows-7-simple-volume-control/
VolumeDown:
if (vol_Master > .01) {
VA_SetMasterVolume(vol_Master-=vol_Step)
if vol_Master <= 0
VA_SetMasterMute(True)
}
Gosub, vol_ShowBars
VolumeDelay()
return
VolumeUp:
if (vol_Master <= 99) {
VA_SetMasterVolume(vol_Master+=vol_Step)
if vol_Master > 1
VA_SetMasterMute(False)
}
Gosub, vol_ShowBars
VolumeDelay()
return
VolumeDelay() {
GetKeyState, winkeyL, LWin
GetKeyState, winkeyR, RWin
key = %winkeyL%%winkeyR%
GetKeyState, volkey, Volume_Down ; check key after delay
key = %winkeyL%%winkeyR%%volkey%
; sometimes Autohotkey is buggy, none of the other key comparisons worked here
IfInString, key, UUU ; add short delay on single key presses
Sleep, 150
}
VolumeMute:
VA_SetMasterMute(!VA_GetMasterMute())
Gosub, vol_ShowBars
Sleep, 300
return
vol_ShowBars:
; Get volumes in case the user or an external program changed them:
vol_Master := VA_GetMasterVolume()
vol_Mute := VA_GetMasterMute()
if vol_Mute = 1
{
vol_Master = 0
vol_Text = Master Volume muted
} else {
vol_Level := SubStr(vol_Master, 1, StrLen(vol_Master) -4) ; remove fractions, last 4 chars
vol_Text = Master Volume %vol_Level%
}
; To prevent the "flashing" effect, only create the bar window if it doesn't already exist:
IfWinNotExist, VolumeOSDxyz
setVolBar()
Progress, 1:%vol_Master%, , %vol_Text%
SetTimer, vol_BarOff, %vol_DisplayTime%
return
vol_BarOff:
SetTimer, vol_BarOff, off
Progress, 1:Off
return
setVolBar() {
global
Sysget, isRDP, 4096
vol_Col := isRDP ? vol_Col_rdp : vol_Col_def
vol_BarOptionsMaster = 1:B1 ZH%vol_Thick% ZX8 ZY4 W%vol_Width% X%vol_PosX% Y%vol_PosY% CW%vol_CW%
Progress, %vol_BarOptionsMaster% CB%vol_Col% CT%vol_Col%, , %vol_Text%, VolumeOSDxyz
WinSet, Transparent, %vol_TransValue%, VolumeOSDxyz
}