; ------------------------------------------------------------ ; ; _WindowsHotkeys.ahkv2, by Cavalol - https://raw.githubusercontent.com/mcavallo-git/Coding/main/ahk/_WindowsHotkeys.ahkv2 ; ; ------------------------------------------------------------ ; Required version of AutoHotkey - https://www.autohotkey.com/docs/v2/lib/_Requires.htm #Requires AutoHotkey v2.0.2 ; https://www.autohotkey.com/download/2.0/AutoHotkey_2.0.2.zip ; ------------------------------------------------------------ ; ------------------------------------------------------------ ; --- GLOBALS --- ; ------------------------------------------------------------ ; ------------------------------------------------------------ ; ------------------------------ ; ; Global Settings ; Persistent ; https://www.autohotkey.com/docs/v2/lib/Persistent.htm A_HotkeyInterval := 2000 ; https://www.autohotkey.com/docs/v2/lib/A_MaxHotkeysPerInterval.htm A_MaxHotkeysPerInterval := 2000 ; https://www.autohotkey.com/docs/v2/lib/A_MaxHotkeysPerInterval.htm #SingleInstance Force ; https://www.autohotkey.com/docs/v2/lib/_SingleInstance.htm ; DetectHiddenText 1 ; https://www.autohotkey.com/docs/v2/lib/DetectHiddenText.htm DetectHiddenWindows 1 ; https://www.autohotkey.com/docs/v2/lib/DetectHiddenWindows.htm ; Keyboard hook is required to use variables "A_PriorHotkey" & "A_TimeSincePriorHotkey" InstallKeybdHook ; https://www.autohotkey.com/docs/v2/lib/InstallKeybdHook.htm SetCapsLockState "Off" ; https://www.autohotkey.com/docs/v2/lib/SetNumScrollCapsLockState.htm SetNumLockState "On" ; https://www.autohotkey.com/docs/v2/lib/SetNumScrollCapsLockState.htm SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle - https://www.autohotkey.com/docs/v2/lib/SetTitleMatchMode.htm SetWorkingDir A_ScriptDir ; https://www.autohotkey.com/docs/v2/lib/SetWorkingDir.htm ; ------------------------------ ; ; Global Variables ; DebugMode := 0 ; DebugMode := 1 ; Show the Version of AHK currently being used to compile this code If (DebugMode == 1) { TrayTip "AHK", ("Version: v" A_AhkVersion) ; Toast Notification } ; ------------------------------ ; ; Tray Icon ; TrayIcon_Cached_Default := "_WindowsHotkeys.cached.ico" TrayIcon_Cached_Gray := "_WindowsHotkeys.gray.cached.ico" TrayIcon_Default := "_WindowsHotkeys.ico" TrayIcon_Gray := "_WindowsHotkeys.gray.ico" If (FileExist(TrayIcon_Default)) { TraySetIcon(TrayIcon_Default) } ; ------------------------------ ; ; Tray ToolTip ; A_IconTip := ( A_ScriptName "`n" " Started " FormatTime("","dd-MMM-yyyy @ HH:mm:ss")) ; ------------------------------------------------------------ ; ------------------------------------------------------------ ; --- HOTKEY LISTENERS --- ; ------------------------------------------------------------ ; ------------------------------------------------------------ ; ------------------------------ ; ; HOTKEY: WinKey + Esc ; ACTION: Refresh This Script ::: Closes then re-opens this script (Allows saved changes to THIS script (file) to be tested/applied on the fly) ; ~#Escape:: { BlockInput("Off") ; Stop blocking input (e.g. restore full interaction) Reload ; Replaces the currently running instance of the script with a new one - https://www.autohotkey.com/docs/v2/lib/Reload.htm Sleep 1000 ; If successful, the reload will close this instance during the sleep, so this line and everything below it will never be reached ; global DebugMode ; If (DebugMode == 1) { ; A_MsgBoxResult := MsgBox("The script could not be reloaded. Would you like to open it for editing?", A_ScriptName " - " A_ThisFunc,4) ; If (A_MsgBoxResult = "Yes") { ; Edit ; } ; } Return } ; ------------------------------ ; ; HOTKEY: WinKey + F1 ; ACTION: Edit this Script (the one you're reading right now) ; #F1:: { ; Edit Run("notepad.exe " A_ScriptFullPath) ; Using the "Run" directive instead of the "Edit" directive avoids the error [ Another instance of Code is already running as administrator. Please close the other instance and try again. ] Return } ; ------------------------------ ; ; HOTKEY: Alt + WinKey + F1 ; Ctrl + WinKey + F1 ; ACTION: Edit this repo's README.md file ; !#F1:: ^#F1:: { SplitPath A_ScriptDir,, &OutDir Fullpath_RepoReadmeFile := OutDir "\README.md" ; Edit Run("notepad.exe " Fullpath_RepoReadmeFile) ; Using the "Run" directive instead of the "Edit" directive avoids the error [ Another instance of Code is already running as administrator. Please close the other instance and try again. ] Return } ; ------------------------------ ; ; HOTKEY: Apps Key ; ACTION: Replace functionality with that of the right WinKey by using a "pass-through" (~) hotkey --> https://www.autohotkey.com/docs/HotkeyFeatures.htm#pass-through ; AppsKey::RWin ; ------------------------------ ; ; HOTKEY: AppsKey + Left/Right/Up/Down ; ACTION: Replace AppsKey with RWin and send command ; AppsKey & Left:: { Send "{LWin up}{RWin up}{LWin down}{Left}{LWin up}" Return } AppsKey & Right:: { Send "{LWin up}{RWin up}{LWin down}{Right}{LWin up}" Return } AppsKey & Up:: { Send "{LWin up}{RWin up}{LWin down}{Up}{LWin up}" Return } AppsKey & Down:: { Send "{LWin up}{RWin up}{LWin down}{Down}{LWin up}" Return } ; ------------------------------ ; ; HOTKEY: Left-Shift + Right-Shift (Shift + Shift --> Both Shift-Keys pressed simultaneously) ; ACTION: Toggle between "Maximized" and "Restored" window-sizes for the currently-active window ; ; VKA0 & VKA1:: ;VKA1 = RShift ; VKA1 & VKA0:: ;VKA0 = LShift ; SC02A & SC136:: ;SC136 = RShift ; SC136 & SC02a:: ;SC02A = LShift ; >+LShift:: ;>+ = RShift (Modifier) ; <+RShift:: ;<+ = LShift (Modifier) LShift & RShift:: RShift & LShift:: { Win_ToggleRestoreMaximize() Return } ; ------------------------------ ; ; HOTKEY: Caps Lock ; ACTION: Permanently DISABLE Capslock (unless the user pressed combo keypress [ Shift + CapsLock ] which toggles CapsLock as-normal) ; CapsLock:: ^CapsLock:: !CapsLock:: #CapsLock:: { global DebugMode If (GetKeyState("CapsLock","T") == 0) { If (DebugMode == 1) { TooltipOutput := "Enable CapsLock via Shift+CapsLock" ShowToolTip(TooltipOutput,,,,2500) } } SetCapsLockState "Off" Return } +CapsLock:: { ; Toggles CapsLock to its opposite state SetCapsLockState !GetKeyState("CapsLock","T") Return } ; ---------------------------------------------------- ; ; HOTKEY: Num Lock ; ACTION: Keep NumLock state enabled (unless pressed with shift, which enables it) ; Allow for a specific config-file, if exists, to keep NumLock disabled by-default (for specific hardware/VM use-cases) ; NumLock:: ^NumLock:: !NumLock:: #NumLock:: { global DebugMode ConfigFilepath_KeepNumLockDisabled := ( EnvGet("USERPROFILE") "\.ahk\numlock-keep-disabled.config" ) If (!FileExist(ConfigFilepath_KeepNumLockDisabled)) { ; Default - Keep NumLock enabled If (GetKeyState("NumLock","T") == 0) { SetNumLockState "On" } Else { If (DebugMode == 1) { TooltipOutput := "Disable NumLock via Shift+NumLock" ShowToolTip(TooltipOutput,,,,2500) } } } Else { ; Reversed-Default - Keep NumLock disabled (for laptops with a terrible numpad layout (overlaying keys J, L, etc.)) If (GetKeyState("NumLock","T") == 1) { SetNumLockState "Off" } Else { If (DebugMode == 1) { TooltipOutput := "Enable NumLock via Shift+NumLock" ShowToolTip(TooltipOutput,,,,2500) } } } Return } +NumLock:: { ConfigFilepath_KeepNumLockDisabled := ( EnvGet("USERPROFILE") "\.ahk\numlock-keep-disabled.config" ) If (!FileExist(ConfigFilepath_KeepNumLockDisabled)) { ; Default - Toggle NumLock (when using shift) SetNumLockState !GetKeyState("NumLock","T") } Else { ; Reversed-Default - Only allow Shift+NumLock to enable NumLock (for laptops with a terrible numpad layout (overlaying keys J, L, etc.)) If (GetKeyState("NumLock","T") == 0) { SetNumLockState "On" } } Return } ; ------------------------------ ; ; HOTKEY: Scroll Lock ; ACTION: Replace functionality with combo keypress [ Alt + Shift + F10 ] (set in GeForce Experience to hotkey "Toggle Instant Replay On/Off" (under "In-Game Overlay" > "Settings" (cog) > "Keyboard shortcuts")) ; ScrollLock:: { ; Send "!^+Z" Send "!+{F10}" Return } +ScrollLock:: { ; Toggles ScrollLock to its opposite state SetScrollLockState !GetKeyState("ScrollLock","T") Return } ; ------------------------------ ; ; HOTKEY: Pause/Break ; ACTION: Replace functionality with combo keypress [ Alt + F10 ] (set in GeForce Experience to hotkey "Save the last 1.0 minutes recorded" (under "In-Game Overlay" > "Settings" (cog) > "Keyboard shortcuts")) ; Pause:: { Send "!{F10}" TrayTip "AHK", "Recording Saved`nPress [ Shift+Pause/Break ] to view in output directory explorer" ; Toast Notification Return } ; ------------------------------ ; ; HOTKEY: Shift + Pause/Break ; ACTION: Open the current user's Videos directory ; +Pause:: { Fullpath_OpenInExplorer := ( EnvGet("USERPROFILE") "\Videos" ) TrayTip "AHK", ("Opening Directory [ " Fullpath_OpenInExplorer " ]") ; Toast Notification Run(Fullpath_OpenInExplorer) ; Open the directory Return } ; ------------------------------ ; ; HOTKEY: WinKey + Z ; ACTION: Grabs information about current (active) window's exe-filepath, process-id, on-screen location, & more, and displays it in a popup table Gui ; #z:: { GetWindowSpecs() Return } ; ------------------------------ ; ; HOTKEY: WinKey + F3 ; ACTION: Hover the mouse over a target area to trigger specific browser-based effects (Javascript on-hover, on cursor entry, on cursor exit, etc.) ; #F3:: { BrowserHover() Return } ; ------------------------------ ; ; HOTKEY: WinKey + Minus-Key ( - ) ; WinKey + Numpad-Minus-Key ( - ) ; Alt + WinKey + Minus-Key ( - ) ; Alt + WinKey + Numpad-Minus-Key ( - ) ; Ctrl + WinKey + Minus-Key ( - ) ; Ctrl + WinKey + Numpad-Minus-Key ( - ) ; Ctrl + Alt + WinKey + Minus-Key ( - ) ; Ctrl + Alt + WinKey + Numpad-Minus-Key ( - ) ; ACTION: Type a line of dashes ----- (override default windows-hotkey for the magnifier tool) ; #-:: #NumpadSub:: { SendDashedLine(60) Return } ^#-:: !#-:: !^#-:: ^#NumpadSub:: !#NumpadSub:: !^#NumpadSub:: { SendDashedLine(30) Return } ; ------------------------------ ; ; HOTKEY: Shift + WinKey + Minus-Key ( - ) ; Shift + WinKey + Numpad-Minus-Key ( - ) ; Shift + Alt + WinKey + Minus-Key ( - ) ; Shift + Alt + WinKey + Numpad-Minus-Key ( - ) ; Shift + Ctrl + WinKey + Minus-Key ( - ) ; Shift + Ctrl + WinKey + Numpad-Minus-Key ( - ) ; Shift + Ctrl + Alt + WinKey + Minus-Key ( - ) ; Shift + Ctrl + Alt + WinKey + Numpad-Minus-Key ( - ) ; ACTION: Type a line of underscores _____ ; +#-:: +#NumpadSub:: { SendUnderscoreLine(60) Return } +^#-:: +!#-:: +!^#-:: +^#NumpadSub:: +!#NumpadSub:: +!^#NumpadSub:: { SendUnderscoreLine(30) Return } ; ------------------------------ ; ; HOTKEY: WinKey + Equals-Key ( = ) ; WinKey + Plus-Key ( + ) ; ACTION: Create a citations footer (refer to function description for more info) ; #=:: #+:: #NumpadAdd:: { CreateCitationsFooter() Return } ; ------------------------------ ; ; HOTKEY: WinKey + V ; ACTION: Open VS Code ; #v:: { Open_VisualStudioCode() Return } ; ------------------------------ ; ; HOTKEY: Ctrl + Shift + V ; HOTKEY: Ctrl + Alt + V ; HOTKEY: Ctrl + WinKey + V ; ACTION: Paste the Clipboard ; *+^v:: *!^v:: *^#v:: { PasteClipboardAsBinary() Return } ; ------------------------------ ; ; HOTKEY: WinKey + P ; ACTION: Send a random string ; #p:: { AwaitModifierKeyup() SendPseudoRandomString() ; SendRandomString(18, 1, 1, 0, 0, 1, 0) Return } ; ------------------------------ ; ; HOTKEY: Shift + Ctrl + P ; ACTION: Reserved for VS Code's "Command Palette..." default hotkey ; ; +^p:: ; { ; Return ; } ; ------------------------------ ; ; HOTKEY: Ctrl + WinKey + P ; HOTKEY: Shift + Alt + P ; HOTKEY: Shift + WinKey + P ; ACTION: Ask user if they wish to paste the clipboard as Text or Binary data (workaround for websites which block pasting into forms) ; ^#p:: +#p:: +!p:: { AwaitModifierKeyup() ; Wait until all modifier keys are released PasteClipboard_TextOrBinary() Return } ; ------------------------------ ; ; HOTKEY: WinKey + H ; ACTION: Type the hostname (COMPUTERNAME) ; #h:: { SendHostname() Return } ; ------------------------------ ; ; HOTKEY: Alt + WinKey + H ; Ctrl + WinKey + H ; Shift + WinKey + H ; ACTION: Type the verbose hostname ; ^#h:: !#h:: +#h:: { SendHostname(1) Return } ; ------------------------------ ; ; HOTKEY: WinKey + U ; ACTION: Type the DOMAIN-USERNAME ; #u:: { SetKeyDelay 0, -1 AwaitModifierKeyup() ; Wait until all modifier keys are released Object_WMI_Service := ComObjGet("winmgmts:{impersonationLevel=impersonate}!\\" A_ComputerName "\root\cimv2") For objComputer in Object_WMI_Service.ExecQuery("Select * from Win32_ComputerSystem") { Domain := objComputer.Domain, Workgroup := objComputer.Workgroup } SendKeys := A_UserName "@" Domain "_via_" EnvGet("USERDOMAIN") Send SendKeys Return } ; ------------------------------ ; ; HOTKEY: WinKey + G ; Alt + WinKey + G ; Ctrl + WinKey + G ; Shift + WinKey + G ; Ctrl + Alt + WinKey + G ; Shift + Alt + WinKey + G ; Shift + Ctrl + Alt + WinKey + G ; ACTION: Types the contents of target file - If [ target file + ".exe" ] file exists, only type contents into that exe's window (if it exists) ; #g:: !#g:: ^#g:: +#g:: !^#g:: +!#g:: +^#g:: +!^#g:: { global DebugMode FileToPaste_Legend := EnvGet("USERPROFILE") "\.ahk\" A_ThisHotkey ExeToRequire_Legend := FileToPaste_Legend "-exe" FileToPaste_Contents := "" ExeToRequire_Fullpath := "" DoPaste := 0 If (FileExist(FileToPaste_Legend)) { If (FileExist(ExeToRequire_Legend)) { ; Get required/whitelisted exe fullpath to match active against ExeToRequire_Fullpath := FileRead(ExeToRequire_Legend) Win_ahk_id := WinGetID("A") Win_hwnd := ("ahk_id " Win_ahk_id) Win_ahk_exe := WinGetProcessName(Win_hwnd) Win_fullpath := WinGetProcessPath(Win_hwnd) If ((ExeToRequire_Fullpath != "") && (ExeToRequire_Fullpath == Win_fullpath)) { ; Exe path-matching succeeded DoPaste := 1 If (DebugMode == 1) { TrayTip "AHK", ("Info - Valid exe (allowing paste):" "`n" "'" Win_ahk_exe "'") ; Toast Notification } } Else { ; Exe path-matching failed DoPaste := 0 If (DebugMode == 1) { TrayTip "AHK", ("Error - Invalid exe (blocking paste):" "`n" "'" Win_ahk_exe "'") ; Toast Notification } Else { ; !! Always show at-least the shortened form of this error !! TrayTip "AHK", "Error - Invalid exe (blocking paste):" ; Toast Notification } } } Else { ; Skip matching on the active window's executable fullpath DoPaste := 1 If (DebugMode == 1) { TrayTip "AHK", ("Info - Allowing paste" "`n" "!! Skipped exe path-matching (file not found: [" ExeToRequire_Legend "])") ; Toast Notification } } } Else { ; Paste file not found DoPaste := 0 If (DebugMode == 1) { ; TrayTip "AHK", ("Error (file not found) - Blocking paste" "`n" "ExeToRequire_Legend=[" ExeToRequire_Legend "]") ; Toast Notification Msgbox ("Error (file not found):" "`n" "`n" "ExeToRequire_Legend=[" ExeToRequire_Legend "]") ; Toast Notification } } If (DoPaste == 1) { ; If the start menu pops up, wait a (half) second then reactivate desired exe's window If (ExeToRequire_Fullpath != "") { AwaitModifierKeyup() ; Wait until all modifier keys are released Sleep 10 SplitPath ExeToRequire_Fullpath, &OutFileName WinActivate ("ahk_exe " OutFileName) ; Free variables from memory (to avoid caching of secrets, sensitive paths or large files) VarSetStrCapacity(&OutFileName,0) ; https://www.autohotkey.com/docs/v2/lib/VarSetStrCapacity.htm } ; Paste the contents of target file FileToPaste_Contents := FileRead(FileToPaste_Legend) SendInput FileToPaste_Contents } ; Free variables from memory (to avoid caching of secrets, sensitive paths or large files) VarSetStrCapacity(&FileToPaste_Contents,0) ; https://www.autohotkey.com/docs/v2/lib/VarSetStrCapacity.htm VarSetStrCapacity(&ExeToRequire_Fullpath,0) ; https://www.autohotkey.com/docs/v2/lib/VarSetStrCapacity.htm Return } ; ------------------------------ ; ; HOTKEY: WinKey + D ; ACTION: Types one of a dynamic set of timestamp-strings ; #d:: ; 20221020T045855 (WinKey + D) !#d:: ; 2022-10-20T04:58:40 (Alt + WinKey + D) ^#d:: ; 2022-10-20_04-58-53 (Ctrl + WinKey + D) !^#d:: ; 2022-10-20T04:58:35-04:00 (Ctrl + Alt + WinKey + D) +!#d:: ; 2022-10-20T04:58:25.802768 (Shift + Alt + WinKey + D) +^#d:: ; 2022-10-20_04-58-31.128721 (Shift + Ctrl + WinKey + D) +!^#d:: ; 2022-10-20T04:58:17.412119-04:00 (Shift + Ctrl + Alt + WinKey + D) <-- Note: For some reason, Microsoft made [ Ctrl + Alt + Shift + WinKey ] open their Win10 Office app --> Disable via https://superuser.com/a/1484507 ; +#d:: ; 20221020T203014.000 (Shift + WinKey + D) <-- Note: Keeps bringing up start menu...? { global DebugMode SetKeyDelay 0, -1 AwaitModifierKeyup() ; Wait until all modifier keys are released ; ------------------------------ ; ; RFC3339 compliant datetime/timestamp separators ( Date and Time on the Internet: Timestamps - https://tools.ietf.org/html/rfc3339 ) ; RFC3339_DateAndTimeField_Separator := "T" ; Character-separator between [ date- and time-fields ] RFC3339_DecimalSeconds_Separator := "." ; Character-separator between [ seconds and fractions-of-a-second (microsecond/millisecond) values ] RFC3339_HourMinuteSecond_Separator := ":" ; Character-separator between [ hour, minute, and second time-field ] values RFC3339_UTC_ZeroHourReplacement := "Z" ; Replacement-string to use for timezone when the UTC timezone (UTC+00:00) is output RFC3339_YearMonthDay_Separator := "-" ; Character-separator between [ year, month, and day date-field values ] ; ------------------------------ AltPressed := InStr(A_ThisHotkey,"!") CtrlPressed := InStr(A_ThisHotkey,"^") ShiftPressed := InStr(A_ThisHotkey,"+") ; ------------------------------ Add_Microseconds := 0 Add_Timezone := 0 ; ------------------------------ Add_Microseconds := 0 Add_Timezone := 0 ; ------------------------------ AltPressed := InStr(A_ThisHotkey,"!") CtrlPressed := InStr(A_ThisHotkey,"^") ShiftPressed := InStr(A_ThisHotkey,"+") ; ------------------------------ ; Special timestamp formats (based on hotkey pressed) If ((ShiftPressed != 0)) { ; w/ Shift ; Add microseconds onto timestamp Add_Microseconds := 1 } If ((CtrlPressed != 0) && (AltPressed != 0)) { ; w/ Alt, w/ Ctrl ; RFC3339 timestamp w/ timezone Add_Timezone := 1 DT_Field_Separator := RFC3339_DateAndTimeField_Separator Microseconds_Separator := RFC3339_DecimalSeconds_Separator HMS_Separator := RFC3339_HourMinuteSecond_Separator YMD_Separator := RFC3339_YearMonthDay_Separator } Else If ((AltPressed != 0) && (CtrlPressed = 0)) { ; w/ Alt, w/o Ctrl ; RFC3339 timestamp DT_Field_Separator := RFC3339_DateAndTimeField_Separator HMS_Separator := RFC3339_HourMinuteSecond_Separator Microseconds_Separator := RFC3339_DecimalSeconds_Separator YMD_Separator := RFC3339_YearMonthDay_Separator } Else If ((AltPressed == 0) && (CtrlPressed != 0)) { ; w/o Alt, w/ Ctrl ; Longer filename friendly timestamp (must match regex pattern: [a-zA-Z0-9\+\.\-]+ ) DT_Field_Separator := "_" HMS_Separator := "-" Microseconds_Separator := RFC3339_DecimalSeconds_Separator YMD_Separator := "-" } Else { ; w/o Alt, w/o Ctrl ; Shorter filename friendly timestamp (must match regex pattern: [a-zA-Z0-9\+\.\-]+ ) DT_Field_Separator := RFC3339_DateAndTimeField_Separator HMS_Separator := "" Microseconds_Separator := RFC3339_DecimalSeconds_Separator YMD_Separator := "" } ; ------------------------------ ; Get the formatted version of the current date & time SendKeys := GetTimestamp(YMD_Separator, HMS_Separator, DT_Field_Separator) ; Append microseconds onto timestamp If (Add_Microseconds = 1) { Current_Microseconds := GetMicroseconds() SendKeys := SendKeys Microseconds_Separator Current_Microseconds } ; Append timezone onto timestamp If (Add_Timezone = 1) { Current_TZ := "" GetTimezoneOffset(&Current_TZ, HMS_Separator) SendKeys := SendKeys Current_TZ } ; ------------------------------ If (DebugMode == 1) { TooltipOutput := "" TooltipOutput := ( TooltipOutput "`n" "A_ThisHotkey = [" A_ThisHotkey "]" ) TooltipOutput := ( TooltipOutput "`n" ) TooltipOutput := ( TooltipOutput "`n" "AltPressed = [" AltPressed "]" ) TooltipOutput := ( TooltipOutput "`n" "CtrlPressed = [" CtrlPressed "]" ) TooltipOutput := ( TooltipOutput "`n" ) TooltipOutput := ( TooltipOutput "`n" "Add_Microseconds = [" Add_Microseconds "]" ) TooltipOutput := ( TooltipOutput "`n" "Add_Timezone = [" Add_Timezone "]" ) TooltipOutput := ( TooltipOutput "`n" ) TooltipOutput := ( TooltipOutput "`n" "SendKeys = [" SendKeys "]" ) TooltipOutput := ( TooltipOutput "`n" ) ToolTip TooltipOutput ClearTooltip(7500) } ; ------------------------------ ; Send the timestamp Send SendKeys Return } ; ------------------------------ ; ; HOTKEY: WinKey + F2 ; ACTION: Displays live data/information regarding any key & button presses being caught by AHK ; #F2:: { KeyHistory Return } ; ------------------------------ ; ; HOTKEY: WinKey + F8 ; ACTION: Send duplicate keypresses ; #F8:: { Duplicate_Keypress() Return } ; ------------------------------ ; ; HOTKEY: WinKey + R ; ACTION: Open Windows 10's "Display settings" (to change resolution, monitor settings, etc.) ; #r:: { Run (EnvGet("WINDIR") "\System32\control.exe desk.cpl") Return } ; ------------------------------ ; ; HOTKEY: Alt + WinKey + R ; Ctrl + WinKey + R ; Shift + WinKey + R ; Shift + Alt + R ; Shift + Ctrl + R ; ACTION: Open Windows 10's "Run" Command ; !#r:: ^#r:: +#r:: { CMD_Command := "explorer.exe shell:" ":" ":" "{2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}" RunWaitOne(CMD_Command) Return } ; ------------------------------ ; ; HOTKEY: AppsKey + [ ; AppsKey + ] ; WinKey + [ ; WinKey + ] ; ACTION: Follow-up hotkey to: WinKey P ::: Click "Duplicate" monitors ; #[:: AppsKey & [:: #]:: AppsKey & ]:: { global DebugMode CoordMode "Mouse", "Screen" SetDefaultMouseSpeed 0 SetControlDelay -1 SetTitleMatchMode 1 ; Title must [ START WITH ] the given WinTitle ; Save current monitor config (to compare against once it's been updated) MonitorCountBefore := SysGet(80) ViewportWidthBefore := SysGet(78) ViewportHeightBefore := SysGet(79) ; Save current mouse coordinates MouseGetPos &MouseX, &MouseY ; Send an Escape keypress to close any old Projection menus Send "{Escape}" Sleep 250 If (A_OSVersion="WIN_7") { ; Windows7 If ((A_ThisHotkey=="#[") || (A_ThisHotkey=="AppsKey & [")) { ; Duplicate Monitors xpos := 874 ypos := 520 } Else If ((A_ThisHotkey=="#]") || (A_ThisHotkey=="AppsKey & ]")) { ; Extend Monitors xpos := 1044 ypos := 520 } Send "{LWin up}{RWin up}{LWin down}{p}{LWin up}" Sleep 2000 MouseClick "Left", xpos, ypos Sleep 100 } Else If (SubStr(A_OSVersion, 1, 4)="10.0") { ; Windows10 ; Open the "Projection" window Send "{LWin up}{RWin up}{LWin down}{p}{LWin up}" Sleep 250 Start_TickCount := A_TickCount Loop { LoopingForMilliseconds := (A_TickCount-Start_TickCount) WinTitle := WinGetTitle("A") Win_ahk_class := WinGetClass("A") Win_ahk_exe := WinGetProcessName("A") If ((WinTitle=="Project") && (Win_ahk_class=="Windows.UI.Core.CoreWindow") && (Win_ahk_exe=="ShellExperienceHost.exe")) { ; Projection menu detected --> select related option (duplicate/extend) Sleep 250 RandomSleep := Random(1000,1500) Sleep RandomSleep If ((A_ThisHotkey=="#[") || (A_ThisHotkey=="AppsKey & [")) { ; Duplicate Monitors xpos := (A_ScreenWidth - 20) ypos := 210 } Else If ((A_ThisHotkey=="#]") || (A_ThisHotkey=="AppsKey & ]")) { ; Extend Monitors xpos := (A_ScreenWidth - 20) ypos := 315 } ; Select Projection menu option MouseClick "Left", xpos, ypos ; Wait until the new monitor layout is loaded Loop 30 { Sleep 100 RandomSleep := Random(1000,1500) Sleep RandomSleep MonitorCountAfter := SysGet(80) If (MonitorCountAfter != MonitorCountBefore) { Break } } ; Click outside of the Projection menu to close it MouseClick "Left", MouseX, MouseY Sleep 100 RandomSleep := Random(1000,1500) Sleep RandomSleep ; Send an Escape keypress to ensure the Projection menu closes Send "{Escape}" Sleep 100 RandomSleep := Random(1000,1500) Sleep RandomSleep Break } Else If (LoopingForMilliseconds > 2000) { MsgBox("Error: Unable to locate Projection window", A_ScriptName " - " A_ThisFunc) Break } Else { Sleep 10 RandomSleep := Random(1000,1500) Sleep RandomSleep } } } MouseMove MouseX, MouseY If (DebugMode == 1) { MonitorCountAfter := SysGet(80) ViewportWidthAfter := SysGet(78) ViewportHeightAfter := SysGet(79) ; Check-for Windows' percentage (%) based display scaling Get_CurrentVerticalResolution := "PowerShell.exe -Command '([String]((Get-CimInstance -ClassName CIM_VideoController).CurrentVerticalResolution)).Trim();'" CurrentVerticalResolution := GetCommandOutput(Get_CurrentVerticalResolution) CurrentVerticalResolution := StrReplace(StrReplace(StrReplace(CurrentVerticalResolution, "`n", ""), "`v", ""), "`r", "") ; Read the registry to check for display scaling KeyName := "HKEY_CURRENT_USER\Control Panel\Desktop" PropertyName := "DpiScalingVer" DpiScalingVer := RegRead(KeyName,PropertyName) PropertyName := "Win8DpiScaling" Win8DpiScaling:= RegRead(KeyName,PropertyName) PropertyName := "DpiScalingVer" LogPixels := RegRead(KeyName,PropertyName) ; ------------------------------ ; ; DpiScalingVer ; originally 1000 ; Win8DpiScaling ; originally 0 ; LogPixels ; originally absent ; ; DPI--->Scale Factor ; 96 === x60 <-- 100% ; 120 === x78 <-- 125% ; 144 === x90 <-- 150% ; 192 === xC0 <-- 200% ; 240 === xF0 <-- 250% ; ; From: https://www.tenforums.com/general-support/69742-resolution-mismatch-when-using-change-size-text.html#post869493 ; ; ------------------------------ ; HKEY_CURRENT_CONFIG\System\CurrentControlSet\Control\Video ; ; DefaultSetting.XResolution ; REG_DWORD ; 0x00000400 (1024) ; ; DefaultSetting.YResolution ; REG_DWORD ; 0x00000300 (768) ; ; From: https://superuser.com/a/1050763 ; ; ------------------------------ MsgBox(("`nxpos = " xpos "`nypos = " ypos "`n`nViewportWidthBefore = " ViewportWidthBefore "`nViewportWidthAfter = " ViewportWidthAfter "`nViewportHeightBefore = " ViewportHeightBefore "`nViewportHeightAfter = " ViewportHeightAfter "`n`nDpiScalingVer = " DpiScalingVer "`nWin8DpiScaling = " Win8DpiScaling "`nLogPixels = " LogPixels "`n"), A_ScriptName " - " A_ThisFunc) } Return } ; ------------------------------ ; ; HOTKEY: WinKey + Right-Click ; ACTION: Follows the mouse-cursor and displays its the X,Y coordinates (as a tooltip next to the cursor) ; #RButton:: { FollowDuration_Seconds := 60 ; ShowCursorCoordinates(FollowDuration_Seconds) ShowCursorPixelColor(FollowDuration_Seconds) Return } ; ------------------------------ ; ; HOTKEY: Shift + WinKey + Right-Click ; Ctrl + WinKey + Right-Click ; Alt + WinKey + Right-Click ; ACTION: Follows the mouse-cursor and displays the color of the pixel under it, continuously (as a tooltip next to the cursor) ; +#RButton:: !#RButton:: ^#RButton:: { FollowDuration_Seconds := 60 ; ShowCursorCoordinates(FollowDuration_Seconds) ShowCursorPixelColor(FollowDuration_Seconds) Return } ; ------------------------------ ; ; HOTKEY: WinKey + L ; ACTION: Allow native function (via ~) to lock the workstatiton, wait a sec, then show the screensaver ; #l:: AppsKey & l:: { LockWorkstation() ; Monitor_ShowScreenSaver() Reload Return } ; ------------------------------ ; ; HOTKEY: WinKey + N ; ACTION: Opens "View Network Connections" (control panel window) ; #n:: { Open_ControlPanel_NetworkConnections() Return } ; ------------------------------ ; ; HOTKEY: WinKey + S ; ACTION: Opens "Sound" > "Playback" (control panel window) ; #s:: { Open_ControlPanel_Sound("Playback") ; Open_ControlPanel_Sound("Recording") Return } ; ------------------------------ ; ; HOTKEY: Alt + WinKey + S ; Ctrl + WinKey + S ; Shift + WinKey + S ; ACTION: Opens "Sound" > "Recording" (control panel window) ; !#s:: ^#s:: +#s:: { Open_ControlPanel_Sound("Recording") Return } ; ------------------------------ ; ; HOTKEY: WinKey + O (not zero, the letter O) ; ACTION: Opens "Programs & Features" in the Control Panel ; #o:: { Run "c:\windows\system32\appwiz.cpl" Return } ; ------------------------------ ; ; HOTKEY: WinKey + E ; ACTION: Opens directory pointed to by Windows' USERPROFILE environment variable ; #e:: { Run EnvGet("USERPROFILE") Return } ; ------------------------------ ; ; HOTKEY: WinKey + ` (Tilde) ; ACTION: Keyboard-Command for a Mouse-Left-Click ; #`:: { MouseClick "Left" Return } ; ------------------------------ ; ; HOTKEY: Alt + ` (Tilde) ; ACTION: Keyboard-Command for a Mouse-Right-Click ; !`:: { MouseClick "Right" Return } ; ------------------------------ ; ; HOTKEY: AppsKey + Mouse-Wheel Up ; AppsKey + Mouse-Wheel Down ; ACTION: Simulate a Mouse Left-Click (instead of scrolling up/down) ; ; AppsKey & WheelUp:: ; AppsKey & WheelDown:: ; { ; CoordMode "Mouse", "Screen" ; SetDefaultMouseSpeed 0 ; MouseGetPos &MouseX, &MouseY ; MouseClick "Left", MouseX, MouseY ; Sleep 10 ; Return ; } ; ------------------------------ ; ; HOTKEY: Alt + Mouse-Wheel Up/Down ; ACTION: "SuperScroll" - scrolls 15 wheel-clicks at a time ; !WheelUp:: { MouseClick("WheelUp",,,15,0,"D","R") Return } !WheelDown:: { MouseClick("WheelDown",,,15,0,"D","R") Return } ; ------------------------------ ; ; HOTKEY: WinKey/AppsKey + XButton1 (Mouse Button 4 - Back Side Button) ; ACTION: Goto Previous Track (in currently-active media player) ; #XButton1:: AppsKey & XButton1:: { Send "{Media_Prev}" Return } ; ------------------------------ ; ; HOTKEY: WinKey/AppsKey + XButton2 (Mouse Button 5 - Forward Side Button) ; ACTION: Goto Next Track (in currently-active media player) ; #XButton2:: AppsKey & XButton2:: { Send "{Media_Next}" Return } ; ------------------------------ ; ; ACTION: Volume Up/Down/Mute ; #F10:: #F11:: #F12:: #MButton:: #WheelUp:: #WheelDown:: ^#MButton:: ^#WheelUp:: ^#WheelDown:: AppsKey & WheelUp:: AppsKey & WheelDown:: { VolDelta := 2 Try { If (A_ThisHotkey=="#F10") { SoundSetMute -1 ; Volume Mute (Toggle) } Else If (A_ThisHotkey=="#MButton") { SoundSetMute -1 ; Volume Mute (Toggle) } Else If (A_ThisHotkey=="^#MButton") { SoundSetMute -1 ; Volume Mute (Toggle) } Else { If (A_ThisHotkey=="#F12") { vDelta := "+" ( VolDelta ) ; Volume Up } Else If (A_ThisHotkey=="+#Up") { vDelta := "+" ( VolDelta ) ; Volume Up } Else If (A_ThisHotkey=="!#Up") { vDelta := "+" ( VolDelta ) ; Volume Up } Else If (A_ThisHotkey=="^#Up") { vDelta := "+" ( VolDelta ) ; Volume Up } Else If (A_ThisHotkey=="AppsKey & WheelUp") { vDelta := "+" ( VolDelta ) ; Volume Up } Else If (A_ThisHotkey=="#WheelUp") { vDelta := "+" ( VolDelta ) ; Volume Up } Else If (A_ThisHotkey=="^#WheelUp") { vDelta := "+" ( VolDelta * 2 ) ; Volume Up x2 } Else If (A_ThisHotkey=="+#Down") { vDelta := "-" ( VolDelta ) ; Volume Down } Else If (A_ThisHotkey=="#F11") { vDelta := "-" ( VolDelta ) ; Volume Down } Else If (A_ThisHotkey=="!#Down") { vDelta := "-" ( VolDelta ) ; Volume Down } Else If (A_ThisHotkey=="^#Down") { vDelta := "-" ( VolDelta ) ; Volume Down } Else If (A_ThisHotkey=="AppsKey & WheelDown") { vDelta := "-" ( VolDelta ) ; Volume Down } Else If (A_ThisHotkey=="#WheelDown") { vDelta := "-" ( VolDelta ) ; Volume Down } Else If (A_ThisHotkey=="^#WheelDown") { vDelta := "-" ( VolDelta * 2 ) ; Volume Down x2 } SoundSetVolume(vDelta) } ShowVolumeLevel() } Return } ; ------------------------------ ; ; HOTKEY: WinKey + 0 ; ACTION: Move the currently-active window's top-left corner to the top-left of the screen ; #0:: { AwaitModifierKeyup() ; Wait until all modifier keys are released WinMove(0,0,,,"A") Return } ; ------------------------------ ; ; HOTKEY: WinKey + 1 ; Ctrl + WinKey + 1 ; ACTION: Send a yellow "Warning Sign" emoji ; #1:: ^#1:: { SetKeyDelay 0, -1 Send "⚠️" ; Warning Sign (Colored) Return } ; ------------------------------ ; ; HOTKEY: WinKey + 4 ; Ctrl + WinKey + 4 ; ACTION: Send a green "Heavy Dollar Sign" emoji ; #4:: ^#4:: { SetKeyDelay 0, -1 Send "💲" ; Heavy Dollar Sign (Colored) Return } ; ------------------------------ ; ; HOTKEY: WinKey + 8 ; ACTION: Wait a random duration of time (example) ; #8:: { RandomSleep_15s_to_20s := Random(15000,20000) TrayTip "AHK", ("Sleeping for [" RandomSleep_15s_to_20s "] ms") ; Toast Notification Sleep RandomSleep_15s_to_20s TrayTip "AHK", ("Sleep for [" RandomSleep_15s_to_20s "] ms has finished") ; Toast Notification Return } ; ------------------------------ ; ; HOTKEY: WinKey + 9 ; ACTION: Send a {PrintScreen} keypress (for keyboards without the printscreen key) ; #9:: { AwaitModifierKeyup() ; Wait until all modifier keys are released Send "{PrintScreen}" Return } !#9:: { AwaitModifierKeyup() ; Wait until all modifier keys are released Send "!{PrintScreen}" Return } ^#9:: { AwaitModifierKeyup() ; Wait until all modifier keys are released Send "^{PrintScreen}" Return } +#9:: { AwaitModifierKeyup() ; Wait until all modifier keys are released Send "+{PrintScreen}" Return } ; ------------------------------ ; ; HOTKEY: WinKey + C ; ACTION: Open Google Chrome (to the New Tab page) ; #c:: { Open_Chrome() Return } ; ------------------------------ ; ; HOTKEY: Alt + WinKey + C ; Ctrl + WinKey + C ; Ctrl + Alt + WinKey + C ; ACTION: Debug/quick-test hotkey ; !#c:: ^#c:: !^#c:: { KeypressLoop("e",50,50000,50) ; ClickLoop() ; ClickLoop(1247,1100,25) ; Loop 20 { ; TooltipOutput := "[" A_Index "] GetNanoseconds: " GetNanoseconds() ; ShowToolTip(TooltipOutput,,,A_Index,10000) ; } Return } ; ------------------------------ ; ; HOTKEY: WinKey + F ; ACTION: Do nothing (kills Windows "Feedback Hub", in the very least) ; #f:: { If (1 == 0) { ; ---------- ; OLD RUNTIME - Open "Effective File Search" (software) ; ---------- ; ExeFilepath := "C:`\Program Files (x86)`\efs`\search.exe" efs := "\Effective File Search.efsp" ; iso=C:\ISO ExeFilepath := "C:`\ISO`\Effective File Search.efsp" ExeFilepath2 := EnvGet("USERPROFILE") efs ; MsgBox(ExeFilepath2, A_ScriptName " - " A_ThisFunc) If (FileExist(ExeFilepath)) { Run ExeFilepath } Else { If (FileExist(ExeFilepath2)) { Run ExeFilepath2 } Else { ; If EFS does NOT exist, offer user the URL to download it exe_download_url := "http://www.sowsoft.com/download/efsearch.zip" A_MsgBoxResult := MsgBox("Effective File Search not found`n`nDownload EFS Now?", A_ScriptName " - " A_ThisFunc,4) If (A_MsgBoxResult = "Yes") { Run ("chrome.exe " exe_download_url) } } } } Return } ; ------------------------------ ; ; HOTKEY: WinKey + J ; ACTION: Start Node.JS (Git-Bash) && Postman ; ; #j:: ; { ; ; - - ; GIT_REPO := EnvGet("USERPROFILE") "\Documents\GitHub\repo_name" ; ; - - ; POSTMAN_EXE=LOCALAPPDATA/Postman/Update.exe ; GIT_BASH_EXE=PROGRAMFILES\Git\git-bash.exe ; ; - - ; WinTitle_NodeJS=Supplier Gateway (localhost) ; WinTitle_Postman=Postman ; ; - - ; if ((!FileExist(GIT_REPO)) || (!InStr(FileExist(GIT_REPO), "D"))) { ; MsgBox(("Error: Required directory not-found:`n" GIT_REPO), A_ScriptName " - " A_ThisFunc) ; } Else { ; ; Microsoft Windows has some unusual values for the window-bounds, when maximized/snapped ; Increment_Left := -7 ; Increment_Top := 0 ; Increment_Width := 14 ; Increment_Height := 7 ; ; Prep Monitor Widths/Heights ; SysGet DesktopMonitorCount, 80 , N ; BoundsLeft = -1 ; BoundsRight = -1 ; BoundsTop = -1 ; BoundsBottom = -1 ; BoundsCenterHoriz = 0 ; BoundsCenterVert = 0 ; Loop, DesktopMonitorCount { ; SysGet MonitorWorkArea, MonitorWorkArea, A_Index ; ; If (MonitorWorkArea_LeftCoord > BoundsLeft) { ; If (BoundsLeft < MonitorWorkArea_LeftCoord) ; { ; ; MsgBox((Floor(BoundsLeft) < Floor(MonitorWorkArea_LeftCoord)), A_ScriptName " - " A_ThisFunc) ; ; Widths ; BoundsLeft := MonitorWorkArea_LeftCoord ; BoundsRight := MonitorWorkArea_RightCoord ; ; Heights ; BoundsTop := MonitorWorkArea_TopCoord ; BoundsBottom := MonitorWorkArea_BottomCoord ; } Else { ; ; MsgBox((Floor(BoundsLeft) >= Floor(MonitorWorkArea_LeftCoord)), A_ScriptName " - " A_ThisFunc) ; } ; } ; ; Widths ; BoundsWidthFull := (BoundsRight - BoundsLeft) ; BoundsWidthHalf := Floor(BoundsWidthFull/2) ; BoundsCenterHoriz := (BoundsLeft + BoundsWidthHalf) ; ; Heights ; BoundsHeightFull := (BoundsBottom - BoundsTop) ; BoundsHeightHalf := Floor(BoundsHeightFull/2) ; BoundsCenterVert := (BoundsTop + BoundsHeightHalf) ; SetTitleMatchMode 1 ; A window's title must start with the specified WinTitle to be a match ; ; - - ; WinTitle_Postman=Postman ; WinTitle_NodeJS=Supplier Gateway (localhost) ; ; - - ; ; Start Postman ; IfWinNotExist WinTitle_Postman ; { ; ; Need to run the program, as no window was found for it (yet) ; POSTMAN_ARGS= --processStart Postman.exe ; ; POSTMAN_ARGS=--processStart Postman.exe ; Run(POSTMAN_EXE POSTMAN_ARGS) ; } ; ; - - ; Sleep 100 ; ; - - ; ; Start Node.JS in Git-Bash ; IfWinNotExist,WinTitle_NodeJS ; { ; GIT_BASH_ARGS_API="-c '" EnvGet("USERPROFILE") "/Documents/GitHub/repo_name/build/_start_frontend.sh rest-api start-localhost;'" ; GIT_BASH_ARGS_SG="-c '" EnvGet("USERPROFILE") "/Documents/GitHub/repo_name/build/_start_frontend.sh project-manager start-localhost;'" ; Run GIT_BASH_EXE GIT_BASH_ARGS_API, GIT_REPO) ; ; Run(GIT_BASH_EXE GIT_BASH_ARGS_PM, GIT_REPO) ; ; Run(GIT_BASH_EXE GIT_BASH_ARGS_SG, GIT_REPO) ; } ; ; ; ; Wait until the script(s)/program(s) start before moving them around ; ; WinWait WinTitle_Postman,,5 ; ; WinWait WinTitle_NodeJS,,3 ; ; Move the window to occupy the right half of the Right-Most monitor ; ; WinMove(BoundsCenterHoriz,BoundsTop,BoundsWidthHalf,BoundsHeightFull,WinTitle_Postman) ; ; WinMove(953,0,974,1047,WinTitle_Postman) ; (1st Monitor, Right, Actual) ; ; Move the window to occupy the left half of the Right-Most monitor ; ; WinMove(BoundsLeft,BoundsTop,BoundsWidthHalf,BoundsHeightFull,WinTitle_NodeJS) ; ; WinMove(-7,0,974,1047,WinTitle_NodeJS) ; (1st Monitor, Left, Actual) ; ; ; } ; Return ; } ; ; ; ------------------------------ ; ; HOTKEY: Left-WinKey + K ; Right-WinKey + K ; ACTION: Send a green "Heavy Check Mark" emoji ; <#k:: >#k:: { SetKeyDelay 0, -1 Send "✔️" ; Heavy Check Mark (Colored) Return } ; ------------------------------ ; ; HOTKEY: Ctrl + WinKey + K ; Ctrl + Alt + K ; Ctrl + Shift + K ; ACTION: Send a "Thumbs Up Sign" emoji ; +^k:: !^k:: ^#k:: { SetKeyDelay 0, -1 Send "👍" ; Thumbs Up Sign Return } ; ------------------------------ ; ; HOTKEY: WinKey + T ; ACTION: Open Windows Terminal ; #t:: { Open_WindowsTerminal() Return } ; ------------------------------ ; ; HOTKEY: Alt + WinKey + T ; Ctrl + WinKey + T ; ACTION: Get Windows Environment Vars ; !#t:: ^#t:: { PrintEnv() Return } ; ------------------------------ ; ; HOTKEY: WinKey + W ; ACTION: Snap the currently-active window to left half of monitor #1, or snap to the right of its current position on repeat calls ; #w:: { WinTitle := WinGetTitle("A") If (WinExist(WinTitle)) { WinSnap(WinTitle,,,,"Left","Half",1) } Return } ; ------------------------------ ; ; HOTKEY: Ctrl + Alt + X ; Ctrl + WinKey + X ; ACTION: Send a red "Cross Mark" emoji ; ^!x:: ^#x:: { SetKeyDelay 0, -1 Send "❌️" ; Cross Mark Return } ; ------------------------------ ; ; HOTKEY: WinKey + Y ; ACTION: Open Google Chrome (to Youtube) ; #y:: { Open_Chrome("https://youtube.com", 1) Return } ; ---------------------------------------------------- ; ; HOTKEY: Directional Arrow Combos ; ACTION: Window Snap to Grid (see each hotkey's commend) ; ; #!Up:: WinSnap_ToGrid("A",,2,1,1,1) ; Alt + WinKey + Up --- Snap to top 1/2 (row) of screen ; #!Down:: WinSnap_ToGrid("A",,2,1,2,1) ; Alt + WinKey + Down --- Snap to bottom 1/2 (row) of screen ; ^#!Up:: WinSnap_ToGrid("A",,3,1,1,1) ; Ctrl + Alt + WinKey + Up --- Snap to top 1/3 (row) of screen ; ^#!Down:: WinSnap_ToGrid("A",,3,1,3,1) ; Ctrl + Alt + WinKey + Down --- Snap to bottom 1/3 (row) of screen ; ---------------------------------------------------- ; ; HOTKEY: Numpad Combos ; ACTION: Window Snap to Grid (see each hotkey's commend) ; #!Numpad4:: WinSnap_ToGrid("A",,1,4,1,1) ; Alt + WinKey + Numpad-4 --- Snap to left 1/4 (column) of screen #!Numpad5:: WinSnap_ToGrid("A",,1,4,1,2,1,2) ; Alt + WinKey + Numpad-5 --- Snap to center 1/2 (column) of screen #!Numpad6:: WinSnap_ToGrid("A",,1,4,1,4) ; Alt + WinKey + Numpad-6 --- Snap to right 1/4 (column) of screen ^#Numpad2:: WinSnap_ToGrid("A",,3,1,3,1) ; Ctrl + WinKey + Numpad-2 --- Snap to bottom 1/3 (row) of screen ^#Numpad5:: WinSnap_ToGrid("A",,3,1,2,1) ; Ctrl + WinKey + Numpad-5 --- Snap to center 1/3 (row) of screen ^#Numpad8:: WinSnap_ToGrid("A",,3,1,1,1) ; Ctrl + WinKey + Numpad-8 --- Snap to top 1/3 (row) of screen ^#!Numpad1::WinSnap_ToGrid("A",,3,3,3,1) ; Ctrl + Alt + WinKey + Numpad-1 --- Snap to bottom-left 1/9 (sector) of screen ^#!Numpad2::WinSnap_ToGrid("A",,3,3,3,2) ; Ctrl + Alt + WinKey + Numpad-2 --- Snap to bottom-middle 1/9 (sector) of screen ^#!Numpad3::WinSnap_ToGrid("A",,3,3,3,3) ; Ctrl + Alt + WinKey + Numpad-3 --- Snap to bottom-right 1/9 (sector) of screen ^#!Numpad4::WinSnap_ToGrid("A",,3,3,2,1) ; Ctrl + Alt + WinKey + Numpad-4 --- Snap to middle-left 1/9 (sector) of screen ^#!Numpad5::WinSnap_ToGrid("A",,3,3,2,2) ; Ctrl + Alt + WinKey + Numpad-5 --- Snap to centermost 1/9 (sector) of screen ^#!Numpad6::WinSnap_ToGrid("A",,3,3,2,3) ; Ctrl + Alt + WinKey + Numpad-6 --- Snap to middle-right 1/9 (sector) of screen ^#!Numpad7::WinSnap_ToGrid("A",,3,3,1,1) ; Ctrl + Alt + WinKey + Numpad-7 --- Snap to top-left 1/9 (sector) of screen ^#!Numpad8::WinSnap_ToGrid("A",,3,3,1,2) ; Ctrl + Alt + WinKey + Numpad-8 --- Snap to top-middle 1/9 (sector) of screen ^#!Numpad9::WinSnap_ToGrid("A",,3,3,1,3) ; Ctrl + Alt + WinKey + Numpad-9 --- Snap to top-right 1/9 (sector) of screen ; ------------------------------ ; ; 3-Key Volume Hotkeys (using LCtrl or RCtrl) ; #HotIf GetKeyState("LCtrl", "P") || GetKeyState("RCtrl", "P") ; ; ACTION: Mega Maximize (cover entire viewport) ; LShift & RShift:: RShift & LShift:: { SM_CXVIRTUALSCREEN := SysGet(78) ; SM_CXVIRTUALSCREEN SM_CYVIRTUALSCREEN := SysGet(79) ; SM_CYVIRTUALSCREEN WinGetPos(&xpos, &ypos, &Win_width, &Win_height, "A") If ((Win_width != SM_CXVIRTUALSCREEN) || (Win_height != SM_CYVIRTUALSCREEN)) { ; Mega maximize the window WinMove(0, 0, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, "A") } Else { ; Window is already mega maximized - Restore it WinMove(Floor(0.01*A_ScreenWidth), Floor(0.025*A_ScreenHeight), Floor(0.48*A_ScreenWidth), Floor(0.90*A_ScreenHeight), "A") } Return } #HotIf ; ------------------------------ ; ; 3-Key Volume Hotkeys (using AppsKey, LWin or RWin) ; #HotIf GetKeyState("LWin", "P") || GetKeyState("RWin", "P") || GetKeyState("AppsKey", "P") ; ; ACTION: Volume Up ; Alt & Up:: Ctrl & Up:: Shift & Up:: { VolDelta := 2 SoundSetVolume("+" VolDelta) ShowVolumeLevel() Return } ; ; ACTION: Volume Down ; Alt & Down:: Ctrl & Down:: Shift & Down:: { VolDelta := 2 SoundSetVolume("-" VolDelta) ShowVolumeLevel() Return } ; ; ACTION: Goto previous track (in active media player) ; Ctrl & Left:: Shift & Left:: { Send "{Media_Prev}" Return } ; ; ACTION: Goto next track (in active media player) ; Ctrl & Right:: Shift & Right:: { Send "{Media_Next}" Return } ; ; ACTION: Pause current track (in active media player) ; Alt & Space:: Ctrl & Space:: Shift & Space:: { Send "{Media_Play_Pause}" Return } #HotIf ; ------------------------------ ; ; HOTKEY: Mouse-Wheel Left-/Right-Tilt (e.g. "Rock" the Mouse-Wheel Left/Right) ; ACTION: Change Tabs Left or Right ; ; WheelLeft:: ; { ; Send "^{PgUp}" ; Return ; } ; WheelRight:: ; { ; Send "^{PgDn}" ; Return ; } ; ; ; ------------------------------------------------------------ ; ------------------------------------------------------------ ; --- APP-SPECIFIC HOTKEY LISTENERS --- ; ------------------------------------------------------------ ; ------------------------------------------------------------ ; ------------------------------ ; ; WINDOW: [ VS Code ] ; STATUS: [ NOT active ] ; #HotIf !WinActive("ahk_exe Code.exe") ; ; HOTKEY: Alt + Z (while [ VS Code ] is NOT active) ; ACTION: Open NVIDIA GeForce Experience Overlay - Configure via "GeForce Experience Overlay" > "⚙️" > "Keyboard shortcuts" > "Open/close in-game overlay" (set to [ Shift + Alt + z ]) ; !z:: { SetKeyDelay 0, -1 SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle AwaitModifierKeyup() ; Wait until all modifier keys are released Send "+!z" Return } #HotIf ; ------------------------------ ; ; WINDOW: [ Bitwarden ] ; STATUS: [ ACTIVE ] ; ; #HotIf WinActive("ahk_exe Bitwarden.exe") || (WinActive("ahk_exe chrome.exe") && WinActive("Bitwarden")) #HotIf WinActive("Bitwarden") ; ; HOTKEY: WinKey + B (while [ Bitwarden ] is active) ; ACTION: Type templated Lunr search string - https://bitwarden.com/help/searching-vault/#searching-specific-fields ; #b:: { AwaitModifierKeyup() Send ">{+}name:_____ {+}name:*" Return } #HotIf ; ------------------------------ ; ; WINDOW: [ Foxit PhantomPDF ] ; STATUS: [ ACTIVE ] ; #HotIf WinActive("ahk_exe FoxitPhantomPDF.exe") ; ; HOTKEY: WinKey + A (while [ Foxit PhantomPDF ] is active) ; ACTION: Edit > Add Text ; #a:: { global DebugMode CoordMode "Mouse", "Screen" SetDefaultMouseSpeed 0 SetControlDelay -1 SetTitleMatchMode 3 ; Title must [ EXACTLY MATCH ] the given WinTitle WinTitle := WinGetTitle("A") If (DebugMode == 1) { TrayTip "AHK", "Foxit PhantomPDF:`nClicking 'Edit' > 'Add Text'" ; Toast Notification } ; Click the "Edit" tab xpos := 223 ypos := 40 ControlClick ("x" xpos " y" ypos), WinTitle Sleep 100 ; Click the "Add Text" button xpos := 338 ypos := 87 ControlClick ("x" xpos " y" ypos), WinTitle Return } ; ; HOTKEY: Ctrl + B (while [ Foxit PhantomPDF ] is active) ; ACTION: Edit > Bold ; ^b:: { global DebugMode CoordMode "Mouse", "Screen" SetDefaultMouseSpeed 0 SetControlDelay -1 SetTitleMatchMode 3 ; Title must [ EXACTLY MATCH ] the given WinTitle WinTitle := WinGetTitle("A") If (DebugMode == 1) { TrayTip "AHK", "Foxit PhantomPDF:`nClicking 'Edit' > 'Bold'" ; Toast Notification } ; Click the "Edit" tab xpos := 223 ypos := 40 ControlClick ("x" xpos " y" ypos), WinTitle Sleep 100 ; Click the "B" (Bold) button xpos := 448 ypos := 106 ControlClick ("x" xpos " y" ypos), WinTitle Return } ; ; HOTKEY: Ctrl + Y (while [ Foxit PhantomPDF ] is active) ; ACTION: Redo ; ^y:: { global DebugMode ; CoordMode "Mouse", "Window" SetDefaultMouseSpeed 0 SetControlDelay -1 SetTitleMatchMode 3 ; Title must [ EXACTLY MATCH ] the given WinTitle WinTitle := WinGetTitle("A") If (DebugMode == 1) { TrayTip "AHK", "Foxit PhantomPDF:`nClicking 'Redo'" ; Toast Notification } ; Click the "Redo" button xpos := 187 ypos := 15 Use_ControlClick := 0 If (Use_ControlClick == 1) { ControlClick ("x" xpos " y" ypos), WinTitle } Else { MouseGetPos &MouseX, &MouseY MouseClick "Left", xpos, ypos MouseMove MouseX, MouseY } Return } #HotIf ; ------------------------------ ; ; WINDOW: [ Windows Terminal ] ; STATUS: [ ACTIVE ] ; #HotIf WinActive("ahk_exe WindowsTerminal.exe") ; ; HOTKEY: Alt + WinKey + MINUS (while [ Windows Terminal ] is active) ; Ctrl + Alt + MINUS (while [ Windows Terminal ] is active) ; Ctrl + WinKey + MINUS (while [ Windows Terminal ] is active) ; Shift + Alt + MINUS (while [ Windows Terminal ] is active) ; Shift + Ctrl + MINUS (while [ Windows Terminal ] is active) ; Shift + WinKey + MINUS (while [ Windows Terminal ] is active) ; Ctrl + Alt + WinKey + MINUS (while [ Windows Terminal ] is active) ; Shift + Ctrl + WinKey + MINUS (while [ Windows Terminal ] is active) ; Shift + Alt + WinKey + MINUS (while [ Windows Terminal ] is active) ; ACTION: Send [ Alt + Shift + MINUS ] (e.g. do Windows Terminal action "Split pane, split: down") ; !#-:: ^!-:: ^#-:: +!-:: +^-:: +#-:: ^!#-:: +^#-:: +!#-:: !#NumpadSub:: ^!NumpadSub:: ^#NumpadSub:: +!NumpadSub:: +^NumpadSub:: +#NumpadSub:: ^!#NumpadSub:: +^#NumpadSub:: +!#NumpadSub:: { SetKeyDelay 0, -1 SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle AwaitModifierKeyup() ; Wait until all modifier keys are released Send "!+{-}" Return } ; ; HOTKEY: Alt + WinKey + PLUS (while [ Windows Terminal ] is active) ; Ctrl + Alt + PLUS (while [ Windows Terminal ] is active) ; Ctrl + WinKey + PLUS (while [ Windows Terminal ] is active) ; Shift + Alt + PLUS (while [ Windows Terminal ] is active) ; Shift + Ctrl + PLUS (while [ Windows Terminal ] is active) ; Shift + WinKey + PLUS (while [ Windows Terminal ] is active) ; Ctrl + Alt + WinKey + PLUS (while [ Windows Terminal ] is active) ; Shift + Ctrl + WinKey + PLUS (while [ Windows Terminal ] is active) ; Shift + Alt + WinKey + PLUS (while [ Windows Terminal ] is active) ; ACTION: Send [ Alt + Shift + PLUS ] (e.g. do Windows Terminal action "Split pane, split: right") ; !#=:: ^!=:: ^#=:: +!=:: +^=:: +#=:: ^!#=:: +^#=:: +!#=:: !#NumpadAdd:: ^!NumpadAdd:: ^#NumpadAdd:: +!NumpadAdd:: +^NumpadAdd:: +#NumpadAdd:: ^!#NumpadAdd:: +^#NumpadAdd:: +!#NumpadAdd:: { SetKeyDelay 0, -1 SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle AwaitModifierKeyup() ; Wait until all modifier keys are released Send "!+{=}" Return } #HotIf ; ------------------------------ ; ; WINDOW: [ Xbox Console Companion ] ; STATUS: [ ACTIVE ] ; #HotIf WinActive("Xbox Console Companion") ; ; HOTKEY: WinKey + F5 (while [ Xbox Console Companion ] is active) ; ACTION: Xbox - Download & delete game clips & screenshots ; #F5:: { Xbox_ExportCaptures() Return } #HotIf ; ------------------------------ ; ; WINDOW: [ Youtube Channel Content (in Chrome) ] ; STATUS: [ ACTIVE ] ; #HotIf WinActive("Channel content - YouTube Studio - Google Chrome") ; ; HOTKEY: WinKey + F5 (while [ Youtube Channel Content (in Chrome) ] is active) ; ACTION: Youtube - Walk uploads from "Draft" to live state ; #F5:: { Youtube_EditDraft_Submit() Return } #HotIf ; ------------------------------------------------------------ ; ------------------------------------------------------------ ; --- FUNCTION(S) --- ; ------------------------------------------------------------ ; ------------------------------------------------------------ ; ------------------------------ ; ; ActiveWindow_Maximize ; |--> Maximize active window (if not maximized, already) ; ActiveWindow_Maximize() { Win_MinMaxState := WinGetMinMax("A") If (Win_MinMaxState<=0) { ; Window is not maximized - maximize it WinMaximize "A" } Return } ; ------------------------------ ; ; AwaitModifierKeyup ; |--> Wait until all modifier keys are released ; AwaitModifierKeyup() { KeyWait "LAlt" ; Wait for [ Left-Alt ] to be released KeyWait "LCtrl" ; Wait for [ Left-Control ] to be released KeyWait "LShift" ; Wait for [ Left-Shift ] to be released KeyWait "LWin" ; Wait for [ Left-WinKey ] to be released KeyWait "RAlt" ; Wait for [ Right-Alt ] to be released KeyWait "RCtrl" ; Wait for [ Right-Control ] to be released KeyWait "RShift" ; Wait for [ Right-Shift ] to be released KeyWait "RWin" ; Wait for [ Right-WinKey ] to be released Sleep 10 } ; ------------------------------ ; ; BrowserHover ; |--> Hover the mouse over a target area to trigger specific browser-based effects (Javascript on-hover, on cursor entry, on cursor exit, etc.) ; BrowserHover() { global TrayIcon_Cached_Default global TrayIcon_Cached_Gray global TrayIcon_Default global TrayIcon_Gray CoordMode "Mouse", "Screen" SetDefaultMouseSpeed 0 SetControlDelay -1 AwaitModifierKeyup() TrayIcon := TrayIcon_Cached_Gray MoveDistance := 1 Updated_TrayIcon := 0 HoverAfter_Seconds := 240 If (FileExist(TrayIcon_Cached_Gray)) { BusyIcon := TrayIcon_Cached_Gray } Else { BusyIcon := TrayIcon_Default } If (FileExist(TrayIcon_Gray)) { WaitIcon := TrayIcon_Gray } Else { WaitIcon := TrayIcon_Default } If (FileExist(WaitIcon)) { TraySetIcon(WaitIcon) } Loop { If (A_TimeIdlePhysical >= (HoverAfter_Seconds * 1000)) { If (Updated_TrayIcon==0) { If (FileExist(BusyIcon)) { TraySetIcon(BusyIcon) } Updated_TrayIcon := 1 } MouseMove MoveDistance, 0, 0, "R" Sleep 1000 MouseMove (MoveDistance * -1), 0, 0, "R" } Else { If (Updated_TrayIcon==1) { If (FileExist(WaitIcon)) { TraySetIcon(WaitIcon) } Updated_TrayIcon := 0 } } Sleep 15000 } } ; ------------------------------ ; ; ClearTooltip ; |--> If called with a positive [ Period ], wait [ Period ] milliseconds before clearing the given ToolTip, otherwise clear it immediately ; |--> https://www.autohotkey.com/docs/v2/lib/ToolTip.htm#ExAutoHide ; ClearTooltip(Period:=0, WhichToolTip:=1) { If (Period > 0) { SetTimer () => ToolTip(,,,WhichToolTip), (Period * -1) } Else { ToolTip(,,,WhichToolTip) } Return } ; ------------------------------ ; ; ClickLoop ; |--> Click loop until script is cancelled (or after MaxLoopIterations loop iterations are reached if set to a value other than -1) ; ClickLoop(WhichButton:="Left", MouseX:=-1, MouseY:=-1, Timeout:=1000, MaxLoopIterations:=-1) { CoordMode "Mouse", "Screen" SetDefaultMouseSpeed 0 SetKeyDelay 0, -1 ; Do not click more often than a predefined lower limit If (Timeout < 25) { Timeout := 25 } Loop { ; Wait a given amount of time before each click Sleep Timeout If ((MouseX == -1) && (MouseY == -1)) { ; Use mouse coordinates MouseGetPos &Click_MouseX, &Click_MouseY } Else { ; Use predefined coordinates Click_MouseX := MouseX Click_MouseY := MouseY } If ((Mod((A_Index-1), 10)) == 0) { ; Display a tooltip notifying the user that the script is clicking TooltipOutput := "Clicking every " Timeout " ms..." ShowToolTip(TooltipOutput,,,,(Timeout*10)) } ; Send the click event MouseClick WhichButton, Click_MouseX, Click_MouseY ; Stop looping after MaxLoopIterations iterations (if specified) If (MaxLoopIterations != -1) { If (A_Index > MaxLoopIterations) { Break } } } ClearTooltip(0) Return } ; ------------------------------ ; ; CreateCitationsFooter ; |--> Creates a block of text designed for placement at the bottom (footer) of a document, ; script, etc. which contains Web-Urls to sources which assisted in building said script ; CreateCitationsFooter() { AwaitModifierKeyup() ; Wait until all modifier keys are released Revert_A_KeyDelay := A_KeyDelay SetKeyDelay 0, -1 LF := "`n" SendInput LF SendInput "{Space}{Shift Down}{Home}{Shift Up}{Delete}" SendInput LF SendInput "------------------------------------------------------------" SendInput "{LControl Down}{q}{LControl Up}" SendInput LF SendInput "{LControl Down}{q}{LControl Up}" SendInput "{End}{Shift Down}{Home}{Right}{Shift Up}" SendInput LF SendInput "Citation(s)" SendInput "{LControl Down}{q}{LControl Up}" SendInput LF SendInput "{LControl Down}{q}{LControl Up}" SendInput "{End}{Shift Down}{Home}{Right}{Shift Up}" SendInput LF SendInput "domain | `"title`" | url" SendInput "{LControl Down}{q}{LControl Up}" SendInput LF SendInput "{LControl Down}{q}{LControl Up}" SendInput "{End}{Shift Down}{Home}{Right}{Shift Up}" SendInput LF SendInput "------------------------------------------------------------" SendInput "{LControl Down}{q}{LControl Up}" SendInput "{Up 2}{Left 26}{Space 2}" ; SendInput "{Up 2}{Left 28}{Space 2}" SendInput "{End}{Shift Down}{Left 3}{Shift Up}" SetKeyDelay Revert_A_KeyDelay, -1 Return } ; ------------------------------ ; ; CommentCurrentLine ; |--> Uses Ctrl + Q hotkey to comment the current line (WITH a leading space) in a given IDE (Notepad++/VS-Code) ; CommentCurrentLine() { Send "{LControl Down}{q}{LControl Up}" Sleep 10 Return } ; ------------------------------ ; ; CommentCurrentLine_NoSpace ; |--> Uses Ctrl + Q hotkey to comment the current line (WITHOUT a leading space) in a given IDE (Notepad++/VS-Code) ; CommentCurrentLine_NoSpace() { Send "{Home}{LControl Down}{q}{LControl Up}{Backspace}" Sleep 10 Return } ; ------------------------------ ; ; ControlSendDelayed ; |--> Send a ControlSend but with a delay between the down and up ; ControlSendDelayed(KeysArray:="", Ctrl_hwnd:="", WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="", Delay_DownUp:=50, Delay_Keypress:=10) { Global DebugMode CoordMode "Mouse", "Window" SetDefaultMouseSpeed 0 SetControlDelay -1 SetTitleMatchMode 3 ; Title must [ EXACTLY MATCH ] the given WinTitle If (IsArray(KeysArray) == True) { ; ------------------------------ ; ; Handle array-typed inputs ; For Each_Key in KeysArray { SendKey_Down := "{" Each_Key " Down}" If (DebugMode == 1) { Tooltip(A_ThisFunc "`n" "`n" SendKey_Down) } ControlSend(SendKey_Down, Ctrl_hwnd, WinTitle, WinText, ExcludeTitle, ExcludeText) Sleep Delay_Keypress } Sleep Delay_DownUp For Each_Key in ReverseArray(KeysArray) { SendKey_Up := "{" Each_Key " Up}" If (DebugMode == 1) { Tooltip(A_ThisFunc "`n" "`n" SendKey_Up) } ControlSend(SendKey_Up, Ctrl_hwnd, WinTitle, WinText, ExcludeTitle, ExcludeText) Sleep Delay_Keypress } } Else { ; ------------------------------ ; ; Handle string-typed inputs ; SendKey_Down := "{" KeysArray " Down}" If (DebugMode == 1) { Tooltip(A_ThisFunc "`n" "`n" SendKey_Down) } ControlSend(SendKey_Down, Ctrl_hwnd, WinTitle, WinText, ExcludeTitle, ExcludeText) Sleep Delay_Keypress Sleep Delay_DownUp SendKey_Up := "{" KeysArray " Up}" If (DebugMode == 1) { Tooltip(A_ThisFunc "`n" "`n" SendKey_Up) } ControlSend(SendKey_Up, Ctrl_hwnd, WinTitle, WinText, ExcludeTitle, ExcludeText) Sleep Delay_Keypress } ; ------------------------------ Return } ; ------------------------------ ; ; DoLogging ; |--> Log given text to target file ; DoLogging(LogText) { ; TIMESTAMP := FormatTime("","yyyyMMddTHHmmss") OutputLogfile := "C:\Users\" A_UserName "\Desktop" "\debug-logging.txt" FileAppend LogText, OutputLogfile Return } ; ------------------------------ ; ; Duplicate_Keypress ; |--> Get user-entered keypress & repeatedly send a duplicate (mock) keypress indefinitely afterwards ; Duplicate_Keypress() { global DebugMode KeyPressed := "" Loop { TooltipOutput := ( "Press a key (will be duplicated)" ) ToolTip TooltipOutput ; Get the key to duplicate from the user KeyPressed := KeyWaitAny("L1 T1") If (DebugMode == 1) { TooltipOutput := ( TooltipOutput "`n" "KeyPressed = [" KeyPressed "]" ) ; TooltipOutput := ( TooltipOutput "`n" "KeyPressed = [" KeyPressed "]" "`n" "ErrorLevel = [" ErrorLevel "]" ) } ; If (ErrorLevel == "Max") { ; Exhaustive list of values for [ ErrorLevel ] regarding the [ Input ] AHK command: https://www.autohotkey.com/docs/v1/lib/Input.htm#Error_Handling ; Break ; } } TooltipOutput := ( "Spamming the [ " KeyPressed " ] key" ) Loop { ToolTip TooltipOutput Send KeyPressed Sleep 10 } ClearTooltip(10) Return } ; ------------------------------ ; ; EscapeSpecialCharacters ; |--> Escape Special characters "{}!^#+" in Curly-Braces "{" CHAR_HERE "}" ; |--> Intended to help AHK type curly-brace characters correctly (and not interpret them as open/close block arguments ; |--> Also intended to help AHK type CTRL (^), ALT (!), SHIFT (+), and WINKEY (#) special characters correctly (and not interpret them as modifier keypresses when parsing strings) ; EscapeSpecialCharacters(StringToEscape:="") { ReturnedString := "" StringConsolidated := RegexConsolidateNewlines(StringToEscape) If InStr(StringConsolidated, "`n") { ; Iterate over each line (in the input string) For EachKey, EachLine in StrSplit(StringConsolidated,"`n") { ; Multi-line string - Iterate over each character (in each line) Loop Parse EachLine { If (A_LoopField == "{") { ReturnedString := ReturnedString "{{}" } Else If (A_LoopField == "}") { ReturnedString := ReturnedString "{}}" } Else If ((A_LoopField=="^")||(A_LoopField=="+")||(A_LoopField=="!")||(A_LoopField=="#")) { ReturnedString := ReturnedString "{" A_LoopField "}" } Else { ReturnedString := ReturnedString A_LoopField } } ReturnedString := ReturnedString "`n" } ; After the for-each loop completes, make sure to trim the final trailing newline before sending the string out the door ReturnedString := SubStr(ReturnedString, 1, -1) } Else { ; Single-line string - Iterate over each character in each line Loop Parse StringConsolidated { If (A_LoopField == "{") { ReturnedString := ReturnedString "{{}" } Else If (A_LoopField == "}") { ReturnedString := ReturnedString "{}}" } Else If ((A_LoopField=="^")||(A_LoopField=="+")||(A_LoopField=="!")||(A_LoopField=="#")) { ReturnedString := ReturnedString "{" A_LoopField "}" } Else { ReturnedString := ReturnedString A_LoopField } } } Return ReturnedString } ; ------------------------------ ; ; Get_ahk_id_from_pid ; |--> Input: WinPID to Target ; |--> Returns ahk_id (process-handle) for AHK back-end control-based calls ; Get_ahk_id_from_pid(WinPid, ExcludeTitle:="") { SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle ; ControlGet OutputVar, Hwnd,,, ("ahk_pid " WinPid) WinTitle := "ahk_pid " WinPid OutputVar := WinGetID(WinTitle,,ExcludeTitle) Return ("ahk_id " OutputVar) ; dat_ahk_id := ("ahk_id " output_var) ; Return dat_ahk_id } ; ------------------------------ ; ; Get_ahk_id_from_title ; |--> Input: WinTitle to Target, WinTitle to Exclude from Targeting ; |--> Returns ahk_id (process-handle) for AHK back-end control-based calls ; Get_ahk_id_from_title(WinTitle:="A", ExcludeTitle:="") { SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle ; ControlGet OutputVar, Hwnd,,, WinTitle,, ExcludeTitle OutputVar := WinGetID(WinTitle,,ExcludeTitle) Return ("ahk_id " OutputVar) } ; ------------------------------ ; ; GetCommandOutput ; |--> Returns the standard output returned from a CMD (ComSpec) command ; GetCommandOutput(CMD_Command) { WScript_Shell_StdOut := RunWaitMany(CMD_Command) Return WScript_Shell_StdOut } ; ------------------------------ ; ; GetMicroseconds ; |--> Gets the current timestamp's fractions-of-a-second, down to the 6th digit (microseconds-precision) ; |--> Example call: ; Current_Microseconds := GetMicroseconds() ; GetMicroseconds() { If (0 = 1 ) { ; NOT WORKING CURRENTLY - NEED TO RESOLVE METHOD OF GETTING 10^-6 SECONDS IN AHK v2 BETA.12 vIntervals := 0 DllCall("kernel32\GetSystemTimeAsFileTime", "Int64*",vIntervals) ; 1 interval = 0.1 microseconds ReturnedVal := SubStr(Format("{:00}00", Mod(vIntervals, 10000000)), 1, 6) } Else { ReturnedVal := (A_MSec * 1000) } Return ReturnedVal } ; ------------------------------ ; ; GetMilliseconds ; |--> Gets the current timestamp's fractions-of-a-second, down to the 3rd digit (millisecond-precision) ; |--> Example call: ; Current_Milliseconds := GetMilliseconds() ; GetMilliseconds() { Return A_MSec } ; ------------------------------ ; ; GetNanoseconds ; |--> Gets the current timestamp's fractions-of-a-second, down to the 9th digit (pseudo-nanosecond-precision - max-precision is actually only 7 digits past decimal, e.g. per-100-nanoseconds) ; |--> Example call: ; Current_Nanosecondss := GetNanoseconds() ; GetNanoseconds() { If (0 = 1 ) { ; NOT WORKING CURRENTLY - NEED TO RESOLVE METHOD OF GETTING TIME DOWN TO THE 10^-9 GRANULATIRY IN AHK v2 BETA.12 (EVEN THOUGH 10^-7 IS THE MOST PRECISE A PC CAN BE ASSUMED TO BE ACCURATE DOWN-TO) vIntervals := 0 DllCall("kernel32\GetSystemTimeAsFileTime", "Int64*",vIntervals) ; 1 interval = 100 nanoseconds ; vDate := 1601 ; EnvAdd, vDate, vIntervals//10000000, S ; autohotkey.com | "EnvAdd" | https://www.autohotkey.com/docs/v2/lib/EnvAdd.htm ReturnedVal := Format("{:07}00", Mod(vIntervals, 10000000)) } Else { ReturnedVal := (A_MSec * 1000 * 1000) } Return ReturnedVal } ; ------------------------------ ; ; GetPID ; |--> Returns PID if process IS found ; |--> Returns 0 if process is NOT found ; GetPID(ProcName) { PID := ProcessExist(ProcName) Return PID } ; ------------------------------ ; ; GetRandomString ; |--> Generate a random string of desired length ; GetRandomString(DesiredStringLength:=20, EnableNumbers:=1, EnableLowercaseLetters:=1, EnableUppercaseLetters:=0, EnableSpecialCharacters:=0) { ReturnedString := "" AllowedCharacters := "" AllNumbers := "0123456789" If (EnableNumbers == 1) { AllowedCharacters := ( AllowedCharacters . AllNumbers ) } Else { EnableNumbers := 0 } AllLowercase := "abcdefghijklmnopqrstuvwxyz" If (EnableLowercaseLetters == 1) { AllowedCharacters := ( AllowedCharacters . AllLowercase ) } Else { EnableLowercaseLetters := 0 } AllUppercase := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" If (EnableUppercaseLetters == 1) { AllowedCharacters := ( AllowedCharacters . AllUppercase ) } Else { EnableUppercaseLetters := 0 } AllSpecial := "!@#$`%^&*" If (EnableSpecialCharacters == 1) { AllowedCharacters := ( AllowedCharacters . AllSpecial ) } Else { EnableSpecialCharacters := 0 } MinimumCharacters_NeededForCharTypes := ( EnableNumbers + EnableLowercaseLetters + EnableUppercaseLetters + EnableSpecialCharacters ) If ( DesiredStringLength < MinimumCharacters_NeededForCharTypes ) { MsgBox(( "Error - String must be at least " MinimumCharacters_NeededForCharTypes " characters long (to meet character type requirements)" ), A_ScriptName " - " A_ThisFunc,0) } Else If (StrLen(AllowedCharacters) <= 0) { MsgBox(( "Error - No character types were selected (unable to generate a random string from nothing)" ), A_ScriptName " - " A_ThisFunc,0) } Else { ; Enforce that at least 1 of each allowed character type appears in the string Pos_ForceNum := -1 Pos_ForceLower := -1 Pos_ForceUpper := -1 Pos_ForceSpecial := -1 If (EnableUppercaseLetters == 1) { ; Set the first character to an Uppercase letter (most preferred) Pos_ForceUpper := 0 } Else If (EnableLowercaseLetters == 1) { ; Set the first character to an Lowercase letter Pos_ForceLower := 0 } Else If (EnableNumbers == 1) { ; Set the first character to an Number Pos_ForceNum := 0 } Else If (EnableSpecialCharacters == 1) { ; Set the first character to an Special character Pos_ForceSpecial := 0 } ; Force at least one number (if allowed in call) If (EnableNumbers == 1) { While ((Pos_ForceNum == -1) || (Pos_ForceNum==Pos_ForceLower) || (Pos_ForceNum==Pos_ForceUpper) || (Pos_ForceNum==Pos_ForceSpecial)) { Pos_ForceNum := Random(0,(DesiredStringLength-1)) } } ; Force at least one lowercase letter (if allowed in call) If (EnableLowercaseLetters == 1) { While ((Pos_ForceLower == -1) || (Pos_ForceLower==Pos_ForceNum) || (Pos_ForceLower==Pos_ForceUpper) || (Pos_ForceLower==Pos_ForceSpecial)) { Pos_ForceLower := Random(0,(DesiredStringLength-1)) } } ; Force at least one uppercase letter (if allowed in call) Pos_ForceUpper := -1 If (EnableUppercaseLetters == 1) { While ((Pos_ForceUpper == -1) || (Pos_ForceUpper==Pos_ForceNum) || (Pos_ForceUpper==Pos_ForceLower) || (Pos_ForceUpper==Pos_ForceSpecial)) { Pos_ForceUpper := Random(0,(DesiredStringLength-1)) } } ; Force at least one special character (if allowed in call) Pos_ForceSpecial := -1 If (EnableSpecialCharacters == 1) { While ((Pos_ForceSpecial == -1) || (Pos_ForceSpecial==Pos_ForceNum) || (Pos_ForceSpecial==Pos_ForceLower) || (Pos_ForceSpecial==Pos_ForceUpper)) { Pos_ForceSpecial := Random(0,(DesiredStringLength-1)) } } ; Build a random string MaxLoopIterations := ( DesiredStringLength * 1000 ) PreviousChar := "" Loop MaxLoopIterations { If (StrLen(ReturnedString) >= DesiredStringLength) { Break } Else { EachLoop_AllowedChars := AllowedCharacters If (StrLen(ReturnedString) == Pos_ForceNum) { EachLoop_AllowedChars := AllNumbers ; Force next char to be a number } Else If (StrLen(ReturnedString) == Pos_ForceLower) { EachLoop_AllowedChars := AllLowercase ; Force next char to be a lowercase letter } Else If (StrLen(ReturnedString) == Pos_ForceUpper) { EachLoop_AllowedChars := AllUppercase ; Force next char to be an uppercase letter } Else If (StrLen(ReturnedString) == Pos_ForceSpecial) { EachLoop_AllowedChars := AllSpecial ; Force next char to be a special character } ; Generate a random index based off of the allowed characters' string as a character array, and use that for the 'random' component RandomCharacterIndex := Random(1,StrLen(EachLoop_AllowedChars)) NextChar := SubStr(EachLoop_AllowedChars, RandomCharacterIndex, 1) If (NextChar != PreviousChar) { ; Only append the next character if its not a repeat of the last character ReturnedString .= NextChar PreviousChar := NextChar } } } } Return ReturnedString } ; ------------------------------ ; ; GetTimestamp ; | ; |--> Description: ; | Returns the current datetime formatted as-needed ; | ; |--> Ex) ; Timestamp := GetTimestamp("yyyyMMddTHHmmss") ; Timestamp := GetTimestamp("yyyy.MM.dd-HH.mm.ss") ; Timestamp := GetTimestamp("yyyy.MM.dd HH:mm:ss") ; Timestamp := GetTimestamp("yyyy-MM-ddTHH-mm-ss") ; GetTimestamp(YMD_Separator:="-", HMS_Separator:=":", DT_Field_Separator:="T") { Timestamp_Format := "yyyy" YMD_Separator "MM" YMD_Separator "dd" DT_Field_Separator "HH" HMS_Separator "mm" HMS_Separator "ss" Return FormatTime("",Timestamp_Format) } ; ------------------------------ ; ; GetTimezoneOffset ; |--> Returns the timezone with [ DateTime +/- Zulu-Offset ] ; GetTimezoneOffset(&Output_TZ, HMS_Separator:=":", UTC_ReplacementStr:="Z", StripCharacter:=".") { Time_CurrentTZ := A_Now Time_UTC := A_NowUTC TZ_UTC_LocalOffset := DateDiff(Time_CurrentTZ, Time_UTC, "Minutes") TZ_UTC_HourOffset := Floor(TZ_UTC_LocalOffset/60) TZ_UTC_MinuteOffset := TZ_UTC_LocalOffset - TZ_UTC_HourOffset*60 ; +/- Timezone ahead/behind UTC determination TZ_UTC_PositiveNegative_Sign := "" If (TZ_UTC_HourOffset<0.0) { TZ_UTC_PositiveNegative_Sign := "-" TZ_UTC_HourOffset *= -1 } Else { TZ_UTC_PositiveNegative_Sign := "+" } ; Hours - Left-Pad with zeroes as-needed TZ_UTC_HourOffset_Padded := Format("{:02}", TZ_UTC_HourOffset) ; Minutes - Left-Pad with zeroes as-needed TZ_UTC_MinuteOffset_Padded := Format("{:02}", TZ_UTC_MinuteOffset) Output_TZ := "" If ((TZ_UTC_HourOffset = 0.0) && (StrLen(UTC_ReplacementStr) > 0)) { ; Replacement-string to use for timezone when the UTC timezone (UTC+00:00) is output Output_TZ := UTC_ReplacementStr } Else { Output_TZ := Output_TZ TZ_UTC_PositiveNegative_Sign Output_TZ := Output_TZ TZ_UTC_HourOffset_Padded Output_TZ := Output_TZ HMS_Separator Output_TZ := Output_TZ TZ_UTC_MinuteOffset_Padded } If (StrLen(StripCharacter) > 0) { Output_TZ := StrReplace(Output_TZ, StripCharacter, "") } Return } ; ------------------------------ ; ; GetTimezoneOffset_P ; |--> Returns the timezone with "P" instead of "+", for fields which only allow alphanumeric with hyphens ; GetTimezoneOffset_P(&Output_TZ_P) { Output_TZ_P := "" GetTimezoneOffset(&Output_TZ_P) Output_TZ_P := StrReplace(Output_TZ_P, "+", "P") Return } ; ------------------------------ ; ; GetWindowSpecs ; |--> Gets Specs for currently-active window ; GetWindowSpecs(WinTitle:="A") { global DebugMode If (WinTitle = "") { ; Error - WinTitle passed as an empty string TooltipOutput := "" TooltipOutput := TooltipOutput " " "`n" TooltipOutput := TooltipOutput " Error - Invalid Argument(s) passed to function [ " A_ThisFunc " ]" " " "`n" TooltipOutput := TooltipOutput " |" "`n" TooltipOutput := TooltipOutput " |--> Call: " A_ThisFunc " (`"" WinTitle "`")" " " "`n" TooltipOutput := TooltipOutput " |" "`n" TooltipOutput := TooltipOutput " |--> Script: " A_ScriptFullPath " " "`n" TooltipOutput := TooltipOutput " " ShowToolTip(TooltipOutput,,,,60000) } Else { ; Set the Gui-identifier (e.g. which gui-popup is affected by gui-based commands, such as [ Gui ... ] and [ LV.Add(...) ]) ; Gui WindowSpecs:Default MyGui := Gui() MyGui.Name := "WindowSpecs" ; MyGui.Destroy() Win_ahk_id := WinGetID(WinTitle) Win_hwnd := ("ahk_id " Win_ahk_id) WinTitle := WinGetTitle(Win_hwnd) Win_text := WinGetText(Win_hwnd) Win_ahk_class := WinGetClass(Win_hwnd) Win_ahk_pid := WinGetPID(Win_hwnd) Win_ahk_exe := WinGetProcessName(Win_hwnd) Win_fullpath := WinGetProcessPath(Win_hwnd) Win_size_state := WinGet_SizeState(Win_hwnd) WinGetPos(&xpos, &ypos, &Win_width, &Win_height, Win_hwnd) Ctrl_names := ImplodeArray(WinGetControls(Win_hwnd),", ",True) ; Get all control names in this window Ctrl_ids := ImplodeArray(WinGetControlsHwnd(Win_hwnd),", ",True) ; Get all control ids in this window Ctrl_focus_hwnd := ControlGetFocus(Win_hwnd) If (Ctrl_focus_hwnd != 0) { Ctrl_focus_classnn := ControlGetClassNN(Ctrl_focus_hwnd, Win_hwnd) Ctrl_focus_isvisible := ControlGetVisible(Ctrl_focus_hwnd, Win_hwnd) Try { ControlGetPos(&Ctrl_xpos, &Ctrl_ypos, &Ctrl_width, &Ctrl_height, Ctrl_focus_hwnd, Win_hwnd) Ctrl_focus_pos := ("x" Ctrl_xpos " y" Ctrl_ypos ", w" Ctrl_width ", h" Ctrl_height ) } ; Ctrl_focus_text := ControlGetText(Ctrl_focus_hwnd, Win_hwnd) } Else { Ctrl_focus_classnn := "" Ctrl_focus_isvisible := "" Ctrl_focus_pos := "" ; Ctrl_focus_text := "" } ; Get the value of the longest text field (to scale the width of the GUI off) Win_longest_field := "" Win_longest_field := StrLen_Max(Win_longest_field,[WinTitle,Win_fullpath,Ctrl_names,Ctrl_ids,Win_ahk_class]) Win_is_win10_app := WinGet_IsWin10App(Win_hwnd) If (Win_is_win10_app == 1) { ; Get the Win10-App's stats Win10_ahk_id := WinGet_ahk_id(Win_hwnd) Win10_title := WinGetTitle("ahk_id " Win10_ahk_id) Win10_text := WinGetText("ahk_id " Win10_ahk_id) Win10_ahk_class := WinGetClass("ahk_id " Win10_ahk_id) Win10_ahk_pid := WinGetPID("ahk_id " Win10_ahk_id) Win10_ahk_exe := WinGetProcessName("ahk_id " Win10_ahk_id) Win10_fullpath := WinGetProcessPath("ahk_id " Win10_ahk_id) Win10_control_names := ImplodeArray(WinGetControls("ahk_id " Win10_ahk_id),", ",True) ; Get all control names in this window Win10_control_ids := ImplodeArray(WinGetControlsHwnd("ahk_id " Win10_ahk_id),", ",True) ; Get all control ids in this window Win10_size_state := WinGet_SizeState("ahk_id " Win10_ahk_id) WinGetPos(&Win10_xpos, &Win10_ypos, &Win10_Width, &Win10_Height, ("ahk_id " Win10_ahk_id)) ; Get the value of the longest text field (to scale the width of the GUI off) Win_longest_field := StrLen_Max(Win_longest_field,[Win10_title,Win10_fullpath,Win10_control_names,Win10_control_ids,Win10_ahk_class]) } ; --- TABLE - TOTAL WIDTH --- Gui_BaseWidth := 200 Gui_MaxWidth := Floor(0.4 * A_ScreenWidth) Gui_LongestField := StrLen(Win_longest_field) If (Win_is_win10_app == 1) { Gui_BaseWidth := Gui_BaseWidth + 64 } Gui_Width := Gui_BaseWidth + Ceil( Gui_LongestField * 8 ) ; <-- Average character width for the 'Tahoma' Gui font is ~8-8.5 pixels If (Gui_Width > Gui_MaxWidth) { Gui_Width := Gui_MaxWidth } ; --- TABLE - TOTAL ROWS --- Gui_RowCount := 2 ; Header Rows Gui_RowCount := Gui_RowCount + 12 ; Win Rows Gui_RowCount := Gui_RowCount + 7 ; Ctrl Rows If (Win_is_win10_app == 1) { Gui_RowCount := Gui_RowCount + 12 ; Win10 Rows } If (DebugMode == 1) { Gui_RowCount := Gui_RowCount + 3 ; Debug-Rows } ; --- TABLE - COLORS --- Gui_BackgroundColor := "1E1E1E" Gui_TextColor := "FFFFFF" ; --- TABLE - FINAL CONFIG --- ( Gui Listview has many options under its "G-Label" callback - See more @ https://www.autohotkey.com/docs/v1/lib/ListView.htm#G-Label_Notifications_Secondary ) Gui_Options := "r" Gui_RowCount Gui_Options := Gui_Options " w" Gui_Width ; Gui_Options := Gui_Options " gGetWindowSpecs_OnDoubleClick" Gui_Options := Gui_Options " Background" Gui_BackgroundColor Gui_Options := Gui_Options " C" Gui_TextColor Gui_Options := Gui_Options " Grid" Gui_Options := Gui_Options " NoSortHdr" ; Gui_Options = Gui_Options " AltSubmit" ; Draw the 'ListView' (grid/table) with two columns ; |--> Note that [ Gui {configs...} ] declarations must be on the PREVIOUS LINE before [ Gui Add, ... ] MyGui.SetFont("s10", "Tahoma") MyGui.SetFont("s10", "Consolas") MyGui.SetFont("s10", "Courier New") MyGui.SetFont("s10", "Open Sans") MyGui.SetFont("s10", "Fira Code") MyGui.BackColor := "1E1E1E" LV := MyGui.Add("ListView",Gui_Options,["Key","Value"]) LV.OnEvent("DoubleClick", GetWindowSpecs_OnDoubleClick) LV.OnEvent("ContextMenu", GetWindowSpecs_OnRightClick) ; The user right-clicks the control or presses Menu or Shift+F10 while the control has the keyboard focus LV.Add("", "", "") LV.Add("", "WinTitle", WinTitle) LV.Add("", "Win_text", Win_text) LV.Add("", "Win_ahk_class", Win_ahk_class) LV.Add("", "Win_ahk_exe", Win_ahk_exe) LV.Add("", "Win_ahk_id", Win_ahk_id) LV.Add("", "Win_ahk_pid", Win_ahk_pid) LV.Add("", "Win_fullpath", Win_fullpath) LV.Add("", "Win_size_state", Win_size_state) ; LV.Add("", "xpos", xpos) ; LV.Add("", "ypos", ypos) ; LV.Add("", "Width", Win_width) ; LV.Add("", "height", Win_height) LV.Add("", "xpos, ypos", ( xpos ", " ypos ) ) LV.Add("", "width, height", ( Win_width ", " Win_height ) ) ; LV.Add("", "Mimic in AHK", "WinMove,,,xpos,ypos,Win_width,Win_height") LV.Add("", "", "") LV.Add("", "Ctrl_ids", Ctrl_ids) LV.Add("", "Ctrl_names", Ctrl_names) LV.Add("", "Ctrl_focus_hwnd", Ctrl_focus_hwnd) LV.Add("", "Ctrl_focus_classnn", Ctrl_focus_classnn) LV.Add("", "Ctrl_focus_isvisible", Ctrl_focus_isvisible) LV.Add("", "Ctrl_focus_pos", Ctrl_focus_pos) ; LV.Add("", "Ctrl_focus_text", Ctrl_focus_text) ; Handle Windows 10 'apps' (applications) alongside 'normal' Windows executables/process-windows LV.Add("", "", "") LV.Add("", "Is Win10 App?", ((Win_is_win10_app==1) ? ("Yes"):("No"))) If (Win_is_win10_app == 1) { ; Show the Win10-App's stats LV.Add("", "Win10_title", Win10_title) LV.Add("", "Win10_text", Win10_text) LV.Add("", "Win10_ahk_class", Win10_ahk_class) LV.Add("", "Win10_ahk_exe", Win10_ahk_exe) LV.Add("", "Win10_ahk_id", Win10_ahk_id) LV.Add("", "Win10_ahk_pid", Win10_ahk_pid) LV.Add("", "Win10_fullpath", Win10_fullpath) LV.Add("", "Win10_size_state", Win10_size_state) ; LV.Add("", "Win10_xpos", Win10_xpos) ; LV.Add("", "Win10_ypos", Win10_ypos) ; LV.Add("", "Win10_Width", Win10_Width) ; LV.Add("", "Win10_Height", Win10_Height) LV.Add("", "Win10_xpos, Win10_ypos", ( Win10_xpos ", " Win10_ypos ) ) LV.Add("", "Win10_Width, Win10_Height", ( Win10_Width ", " Win10_Height ) ) LV.Add("", "Win10_control_names", Win10_control_names) LV.Add("", "Win10_control_ids", Win10_control_ids) } If (DebugMode == 1) { LV.Add("", "", "") LV.Add("", "Gui_LongestField", Gui_LongestField) LV.Add("", "Gui_Width", Gui_Width) ; LV.Add("", "Gui_Options", Gui_Options) } LV.Add("", "", "") LV.ModifyCol(1, "AutoHdr Text Left") LV.ModifyCol(2, "AutoHdr Text Left") ; LV.ModifyCol() ; Auto-size each column to fit its contents. ; Display the window and return. The script will be notified whenever the user double clicks a row. ; Gui Show MyGui.Show() } Return } ; ; GetWindowSpecs_OnDoubleClick - Sub-Function of "GetWindowSpecs" ; GetWindowSpecs_OnDoubleClick(LV, RowNumber) { global DebugMode KeySelected := LV.GetText(RowNumber,1) ; Grab the key (col. 1) from the selected row ValSelected := LV.GetText(RowNumber,2) ; Grab the val (col. 2) from the selected row A_MsgBoxResult := MsgBox(("Value selected:`n " ValSelected "`n`nCopy this value to the clipboard?"), A_ScriptName " - " A_ThisFunc,4) If (A_MsgBoxResult = "Yes") { A_Clipboard := ValSelected } Return } ; ; GetWindowSpecs_OnRightClick - Sub-Function of "GetWindowSpecs" ; GetWindowSpecs_OnRightClick(LV, Item, IsRightClick, X, Y) { global DebugMode KeySelected := LV.GetText(Item,1) ; Grab the key (col. 1) from the selected row ValSelected := LV.GetText(Item,2) ; Grab the val (col. 2) from the selected row A_MsgBoxResult := MsgBox(("Value selected:`n " ValSelected "`n`nCopy this value to the clipboard?"), A_ScriptName " - " A_ThisFunc,4) If (A_MsgBoxResult = "Yes") { A_Clipboard := ValSelected } Return } ; ------------------------------ ; ; IfProcessExist (proxy-function for GetPID(...)) ; |--> Returns True if process IS found ; |--> Returns False if process is NOT found ; IfProcessExist(ProcName) { Return (GetPID(ProcName)>0) ? True : False } ; ------------------------------ ; ; ImplodeArray ; |--> Convert an array to a string, delimited by a given delimiter string, and with each index optionally displayed ; ImplodeArray(Array:="",Delimiter:=",",ShowIndexes:=False) { ReturnedVal := "" If (IsArray(Array) == True) { For EachValue in Array { If (A_Index != 1) { ReturnedVal .= Delimiter } If (ShowIndexes == True) { ReturnedVal .= A_Index "='" EachValue "'" } Else { ReturnedVal .= EachValue } } } Return ReturnedVal } ; ------------------------------ ; ; IsArray ; |--> Returns True if input parameter #1 IS an array ; |--> Returns False if input parameter #1 is NOT an array ; IsArray(TestVar:="") { Return (IsObject(TestVar)) ; https://www.autohotkey.com/board/topic/70596-isarray/?p=447071 ; Return (!ObjCount(TestArray) || ObjMinIndex(TestArray) == 1 && ObjMaxIndex(TestArray) == ObjCount(TestArray) && TestArray.Clone().Delete(1, TestArray.MaxIndex()) == ObjCount(TestArray)) ; https://www.autohotkey.com/boards/viewtopic.php?t=64332 } ; ------------------------------ ; ; KeypressLoop ; |--> Keypress loop until script is cancelled (or after MaxLoopIterations loop iterations are reached if set to a value other than -1) ; KeypressLoop(WhichKey:="e", Timeout:=1000, MaxLoopIterations:=-1, DownUpDelay:=-1) { global DebugMode SetKeyDelay 0, -1 ; Do not click more often than a predefined lower limit If (Timeout < 25) { Timeout := 25 } Loop { ; Wait a given amount of time before each click Sleep Timeout If (DebugMode == 1) { ; Display a tooltip notifying the user that the script is sending keypresses If ((Mod((A_Index-1), 10)) == 0) { TooltipOutput := "Sending keypress every " Timeout " ms..." ShowToolTip(TooltipOutput,,,,(Timeout*10)) } } ; Send the keypress event If (DownUpDelay != -1) { Send ("{" WhichKey " down}") Sleep DownUpDelay Send ("{" WhichKey " up}") } Else { Send WhichKey } ; Stop looping after MaxLoopIterations iterations (if specified) If (MaxLoopIterations != -1) { If (A_Index > MaxLoopIterations) { Break } } } ClearTooltip(0) Return } ; ------------------------------ ; ; KeyWaitAny ; |--> Waits for the user to press any single key (and returns it) ; |--> Source: https://www.autohotkey.com/docs/v2/lib/InputHook.htm#ExKeyWaitAny ; KeyWaitAny(Options:="") { ih := InputHook(Options) if !InStr(Options, "V") ih.VisibleNonText := false ih.KeyOpt("{All}", "E") ; End ih.Start() ih.Wait() Return ih.EndKey ; Return the key name } ; ------------------------------ ; ; LockWorkstation ; |--> Lock the Workstation and turn-off/activate-lower-power-mode on monitors ; LockWorkstation() { DllCall("LockWorkStation") Sleep 10 Monitor_ActivateLowPowerMode() ; Monitor_PowerOff() Return } ; ------------------------------ ; ; Monitor_ActivateLowPowerMode ; |--> [ 0x112 ] targets [ WM_SYSCOMMAND ] - https://docs.microsoft.com/en-us/windows/win32/menurc/wm-syscommand ; |--> [ 0xF170 ] targets [ SCMONITORPOWER ] ; |--> Sending a value of [ 1 ] sends [ activate low-power mode ] to attached monitor(s) ; Monitor_ActivateLowPowerMode() { DllCall("LockWorkStation") Sleep 10 SendMessage(0x112, 0xF170, 1,, "Program Manager") Return } ; ------------------------------ ; ; Monitor_PowerOff ; |--> [ 0x112 ] targets [ WM_SYSCOMMAND ] - https://docs.microsoft.com/en-us/windows/win32/menurc/wm-syscommand ; |--> [ 0xF170 ] targets [ SCMONITORPOWER ] ; |--> Sending a value of [ 2 ] sends [ power off ] to attached monitor(s) ; Monitor_PowerOff() { DllCall("LockWorkStation") Sleep 10 SendMessage(0x112, 0xF170, 2,, "Program Manager") Return } ; ------------------------------ ; ; Monitor_PowerOn ; |--> [ 0x112 ] targets [ WM_SYSCOMMAND ] ; |--> [ 0xF170 ] targets [ SCMONITORPOWER ] ; |--> Sending a value of [ -1 ] sends [ power on ] to attached monitor(s) ; Monitor_PowerOn() { DllCall("LockWorkStation") Sleep 10 SendMessage(0x112, 0xF170, -1,, "Program Manager") Return } ; ------------------------------ ; ; Monitor_ShowScreenSaver ; |--> [ 0x112 ] targets [ WM_SYSCOMMAND ] - https://docs.microsoft.com/en-us/windows/win32/menurc/wm-syscommand ; |--> [ 0xF140 ] targets [ SC_SCREENSAVE ] ; |--> Sending a value of [ 2 ] sends [ power off ] to attached monitor(s) ; Monitor_ShowScreenSaver() { SendMessage(0x112, 0xF140, 0,, "Program Manager") ; | ; |--> [ 0x112 ] targets [ WM_SYSCOMMAND ] - https://docs.microsoft.com/en-us/windows/win32/menurc/wm-syscommand ; | ; |--> [ 0xF140 ] targets [ SC_SCREENSAVE ] ; Return } ; ------------------------------ ; ; MouseGet_MonitorIndex ; | ; |--> Description: ; | Returns the Monitor Index (integer) of the monitor containing the mouse cursor ; | ; |--> Ex) Mouse_MonitorIndex := MouseGet_MonitorIndex() ; MouseGet_MonitorIndex() { CoordMode "Mouse", "Screen" MouseGetPos &MouseX, &MouseY ; Default to monitor #1 Mouse_MonitorIndex := 1 ; Walk through each connected display Loop MonitorGetCount() { Each_MonitorIndex := A_Index MonitorGetWorkArea(Each_MonitorIndex, &EachMonitor_LeftCoord, &EachMonitor_TopCoord, &EachMonitor_RightCoord, &EachMonitor_BottomCoord) ; Determine if the center of target window is currently located within the bounds of this monitor's work area If ((MouseX >= EachMonitor_LeftCoord) && (MouseX <= EachMonitor_RightCoord)) { If ((MouseY >= EachMonitor_TopCoord) && (MouseY <= EachMonitor_BottomCoord)) { ; Mouse cursor is on this monitor Mouse_MonitorIndex := Each_MonitorIndex Break } } } ; Return the monitor index which the mouse is currently on Return Mouse_MonitorIndex } ; ------------------------------ ; ; Open_Chrome ; |--> Opens the "Google Chrome" Application ; Open_Chrome(Url_Open:="", Force_RunExe:=0) { global DebugMode SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle FullPath_RunExe := "" FullPath_RunExe_x64 := "C:\Program Files\Google\Chrome\Application\chrome.exe" FullPath_RunExe_x86 := "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" If (FileExist(FullPath_RunExe_x64)) { FullPath_RunExe := FullPath_RunExe_x64 } Else If (FileExist(FullPath_RunExe_x86)) { FullPath_RunExe := FullPath_RunExe_x86 } ; WinTitle := ("ahk_exe chrome.exe") WinTitle := " - Google Chrome" WinText := "Chrome Legacy Window" WinWait_TimeoutSeconds := 20 PreExisting_Win_hwnd := WinExist(WinTitle) If (FullPath_RunExe = "") { ; Error - Unable to resolve the location of "chrome.exe" TooltipOutput := "Chrome executable not found (neither x64 or x86 version)" ShowToolTip(TooltipOutput,,,3,15000) } Else { If ((!WinExist(WinTitle)) || (Force_RunExe != 0)) { ; Run a NON-admin version of target exe RunExe_NON_Admin(FullPath_RunExe, Url_Open) WinWait WinTitle,,WinWait_TimeoutSeconds ; Wait until the specified window exists | https://www.autohotkey.com/docs/v2/lib/WinWait.htm } If (WinExist(WinTitle)) { ; Skip snapping the window if it was already open yet we forced rerunning its executable (use case for New Tab(s) in chrome) If ( ! ((PreExisting_Win_hwnd != 0) && (Force_RunExe != 0)) ) { If (MonitorGetCount()==1) { WinSnap(WinTitle,,,,"Right","Half",1) ; Resize window to right half of monitor #1 } Else { WinSnap(WinTitle,,,,"Left","Half",2) ; Resize window to left half of monitor #2 } } If (WinExist(WinTitle,WinText)) { ; WinActivate using Title & Text WinActivate(WinTitle,WinText) ; Activate the specified window | https://www.autohotkey.com/docs/v2/lib/WinActivate.htm } Else If (WinExist(WinTitle)) { ; WinActivate using Title, only WinActivate(WinTitle) ; Activate the specified window | https://www.autohotkey.com/docs/v2/lib/WinActivate.htm } } Else { TooltipOutput := A_ScriptName " - " A_ThisFunc "`n`n" "Error - No window found matching [ " WinTitle " ] " ShowToolTip(TooltipOutput,,,5,15000) } } Return } ; ------------------------------ ; ; Open_ControlPanel_NetworkConnections ; |--> Opens "View Network Connections" ; |--> Open manually via [ Start Menu search for "View Network Connections" ] or [ "Settings (Win10 App)" > "Network & Internet" > "Ethernet" (left menu) > "Change adapter options" (top right) ] ; Open_ControlPanel_NetworkConnections() { global DebugMode WinTitle := "Network Connections" SetTitleMatchMode 3 ; Title must [ EXACTLY MATCH ] the given WinTitle AwaitModifierKeyup() ; Wait until all modifier keys are released If (!WinExist(WinTitle)) { If (DebugMode == 1) { TrayTip "AHK", ("Opening '" WinTitle "'...") ; Toast Notification } ; Run (":" ":" "{7007acc7-3202-11d1-aad2-00805fc1270e}") ; CLSID (Windows Class Identifier) for 'View Network Connections' ; Run (EnvGet("WINDIR") "\System32\ncpa.cpl") Run (EnvGet("WINDIR") "\System32\control.exe ncpa.cpl") WinWait WinTitle,,10 ; Wait until the specified window exists | https://www.autohotkey.com/docs/v2/lib/WinWait.htm } If (WinExist(WinTitle)) { WinActivate(WinTitle) ; Activate the specified window | https://www.autohotkey.com/docs/v2/lib/WinActivate.htm } Return } ; ------------------------------ ; ; Open_ControlPanel_Sound ; |--> Opens "Sound Control Panel" ; |--> Open manually via [ Start Menu search for "Change system sounds" ] or [ "Settings (Win10 App)" > "System" > "Sound" (left menu) > "Sound Control Panel" (top right) ] ; Open_ControlPanel_Sound(TabToOpen:="Playback") { global DebugMode WinTitle := "Sound" SetTitleMatchMode 3 ; Title must [ EXACTLY MATCH ] the given WinTitle AwaitModifierKeyup() ; Wait until all modifier keys are released Tab_Desc := "Playback" Tab_Int := 0 If (TabToOpen=="Playback") { Tab_Desc := "Playback" Tab_Int := 0 } Else If (TabToOpen=="Recording") { Tab_Desc := "Recording" Tab_Int := 1 } Else If (TabToOpen=="Sounds") { Tab_Desc := "Sounds" Tab_Int := 2 } Else If (TabToOpen=="Communications") { Tab_Desc := "Communications" Tab_Int := 3 } Else { Tab_Desc := "Playback" Tab_Int := 0 } If (!WinExist(WinTitle)) { If (DebugMode == 1) { TrayTip "AHK", ("Opening '" WinTitle "' > '" Tab_Desc "'") ; Toast Notification } Run (EnvGet("WINDIR") "\System32\control.exe" " " "mmsys.cpl,," Tab_Int) ; Run explorer shell:::{F2DDFC82-8F12-4CDD-B7DC-D4FE1425AA4D} ; CLSID (Windows Class Identifier) for 'Sound Control Panel' ; Run control.exe /name Microsoft.Sound WinWait WinTitle,,10 ; Wait until the specified window exists | https://www.autohotkey.com/docs/v2/lib/WinWait.htm } If (WinExist(WinTitle)) { WinActivate(WinTitle) ; Activate the specified window | https://www.autohotkey.com/docs/v2/lib/WinActivate.htm } Return } ; ------------------------------ ; ; Open_Exe ; |--> Opens target exeutable & sets its window to be active ; Open_Exe(ExeFullpath) { global DebugMode Timeout := 10 SplitPath ExeFullpath, &OutFileName If (ProcessExist(OutFileName) == True) { ; Executable IS running If (DebugMode == 1) { TooltipOutput := "Activating `"" OutFileName "`"" ShowToolTip(TooltipOutput,,,,2000) } ExePID := GetPID(OutFileName) WinActivate ("ahk_pid " ExePID) } Else If (FileExist(ExeFullpath)) { ; Executable NOT running but IS found locally If (DebugMode == 1) { TooltipOutput := "Opening `"" OutFileName "`"" ShowToolTip(TooltipOutput,,,,2000) } ; Run ExeFullpath ExitCode := RunWait(ExeFullpath,,, ExePID) ; WinWait "ahk_pid " ExePID ; ExePID := GetPID(OutFileName) WinActivate ("ahk_pid " ExePID) } Else { ; Executable NOT running & NOT found locally If (DebugMode == 1) { TooltipOutput := ("File not found: [ " ExeFullpath " ]") ShowToolTip(TooltipOutput,,,,2000) } } Return } ; ------------------------------ ; ; Open_VisualStudioCode ; |--> Opens Microsoft's "Visual Studio Code" application (e.g. "VS Code" or "VSCode") - VS Code is a Free Source Code Editor & IDE ; Open_VisualStudioCode(FilePath_Open:="") { global DebugMode SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle ; ------------------------------ FullPath_RunExe := "C:\Windows\System32\notepad.exe" ; Run notepad.exe which is redirected to VS Code through NotepadReplacer (which opens default Workspace in VS Code) ; ------------------------------ ; WinTitle := WinGetTitle("ahk_exe Code.exe") ; WinExist doesn't grab minimized windows by their 'ahk_exe' as-intended WinTitle := " - Visual Studio Code" WinText := "Chrome Legacy Window" WinWait_TimeoutSeconds := 20 If (!WinExist(WinTitle) || (FilePath_Open != "")) { ; Run a NON-admin version of target exe RunExe_NON_Admin(FullPath_RunExe, FilePath_Open) WinWait WinTitle,,WinWait_TimeoutSeconds ; Wait until the specified window exists | https://www.autohotkey.com/docs/v2/lib/WinWait.htm } WinSnap(WinTitle,,,,"Left","Half",1) ; Resize window to left half of monitor #1 If (WinExist(WinTitle)) { WinActivate(WinTitle) ; Activate the specified window | https://www.autohotkey.com/docs/v2/lib/WinActivate.htm } Return } ; ------------------------------ ; ; Open_WindowsTerminal ; |--> Opens Microsoft's "Windows Terminal" application - Windows Terminal is a tabbed terminal utility for Windows ; Open_WindowsTerminal() { global DebugMode SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle ; ------------------------------ FullPath_RunExe := "C:\Windows\explorer.exe" Win10_AppName := "Microsoft.WindowsTerminal_8wekyb3d8bbwe" ; App name acquired via powershell call [ (Get-AppxPackage Microsoft.WindowsTerminal).PackageFamilyName; ] Win10_AppUnionPath := ( "shell:AppsFolder\" Win10_AppName "!App") ; "C:\Windows\explorer.exe" "shell:AppsFolder\Microsoft.WindowsTerminal_8wekyb3d8bbwe!App" ; ------------------------------ ; ;;; Deprecated approach (doesn't work if not acting as an admin while opening it..?) ; FullPath_RunExe := "C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.11.2921.0_x64__8wekyb3d8bbwe\wt.exe" ; Acquired via powershell call [ Get-ChildItem ((Get-AppxPackage "*WindowsTerminal*").InstallLocation); ] ; Win10_AppUnionPath := "" ; ------------------------------ Win_ahk_exe := "WindowsTerminal.exe" WinTitle := ("ahk_exe " Win_ahk_exe) WinText := "DesktopWindowXamlSource" WinWait_TimeoutSeconds := 20 If (!WinExist(WinTitle)) { ; Run a NON-admin version of target exe RunExe_NON_Admin(FullPath_RunExe, Win10_AppUnionPath) WinWait WinTitle,,WinWait_TimeoutSeconds ; Wait until the specified window exists | https://www.autohotkey.com/docs/v2/lib/WinWait.htm } WinSnap(WinTitle,WinText,,,"Right","Half",1) ; Resize window to right half of monitor #1 If (WinExist(WinTitle,WinText)) { WinActivate(WinTitle,WinText) ; Activate the specified window | https://www.autohotkey.com/docs/v2/lib/WinActivate.htm } Else If (WinExist(WinTitle)) { WinActivate(WinTitle) ; Activate the specified window | https://www.autohotkey.com/docs/v2/lib/WinActivate.htm } Return } ; ------------------------------ ; ; PasteClipboardAsBinary ; |--> Pastes the current clipboard data as binary-data (as if the user typed it instead of pasting it) ; PasteClipboardAsBinary() { global DebugMode SetKeyDelay 0, -1 AwaitModifierKeyup() ; Wait until all modifier keys are released Sleep 250 A_Clipboard := ClipboardAll() Sleep 25 A_Clipboard := A_Clipboard ; Convert any copied files, HTML or other formatted text to plain text Sleep 25 If (StrLen(A_Clipboard)>=5000) { MsgBox("Warning! You are about to paste [ " StrLen(A_Clipboard) " ] characters. This may take some type to type. Press WinKey + ESC to cancel", A_ScriptName " - " A_ThisFunc) } SendInput(EscapeSpecialCharacters(A_Clipboard)) Sleep 25 Return } ; ------------------------------ ; ; PasteClipboardAsText ; |--> Types the current clipboard's contained data, character-by-character (as if the user typed it instead of pasting it) ; PasteClipboardAsText(StringToPaste:="") { global DebugMode SetKeyDelay 1, -1 ; A tiny delay between every keypress is often required by anti-paste mechanisms on websites - Set the shortest delay to work around this AwaitModifierKeyup() ; Wait until all modifier keys are released Sleep 250 StringToPaste := ((StrLen(StringToPaste)<=0)?(A_Clipboard):(StringToPaste)) If (StrLen(StringToPaste)>=5000) { MsgBox("Warning! You are about to paste [ " StrLen(StringToPaste) " ] characters. This may take some type to type. Press WinKey + ESC to cancel", A_ScriptName " - " A_ThisFunc) } Loop Parse RegexConsolidateNewlines(StringToPaste) { ; DoSleep := 0 SendChar := "" If (A_LoopField == "{") { SendChar := "{" "{" "}" } Else If (A_LoopField == "}") { SendChar := "{" "}" "}" } Else If ((A_LoopField=="^")||(A_LoopField=="+")||(A_LoopField=="!")||(A_LoopField=="#")) { SendChar := "{" A_LoopField "}" ; SendRaw A_LoopField } Else If ((A_LoopField=="`n")||(A_LoopField=="`r")) { SendChar := "{" "`n" "}" ; DoSleep := 1 } Else { SendChar := A_LoopField } ; If (DoSleep == 1) { ; Sleep 50 ; } SendInput SendChar ; If (DoSleep == 1) { ; Sleep 50 ; } } Return } ; ------------------------------ ; ; PasteClipboard_TextOrBinary ; |--> Displays a menu asking user if they wish to paste the clipboard as Text or Binary data (workaround for websites which block pasting into forms) ; PasteClipboard_TextOrBinary() { Start_TickCount := A_TickCount MsgBox_WinTitle := ( A_ScriptName " - " A_ThisFunc ) SetTimer () => Custom_MsgBox_Buttons(MsgBox_WinTitle, Start_TickCount), 10 A_MsgBoxResult := MsgBox("Paste the Clipboard as Text or Binary?", A_ScriptName " - " A_ThisFunc,3) If (A_MsgBoxResult = "Yes") { ; Paste the Text version of the Clipboard PasteClipboardAsText() } If (A_MsgBoxResult = "No") { ; Paste the Binary version of the Clipboard PasteClipboardAsBinary() } Return } Custom_MsgBox_Buttons(MsgBox_WinTitle:="", Start_TickCount:=0, Period:=5000) { SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle Remaining_TickCount := (Period-(A_TickCount-Start_TickCount)) If (Remaining_TickCount <= 0) { SetTimer , 0 ; Mark the timer for deletion } Else { ; Check for the MsgBox window and update the buttons on it If WinExist(MsgBox_WinTitle) { WinActivate(MsgBox_WinTitle) ControlSetText "Text", "Button1", MsgBox_WinTitle ControlSetText "Binary", "Button2", MsgBox_WinTitle SetTimer , 0 } } Return } ; ------------------------------ ; ; PrintEnv ; |--> Gets Windows Environment Vars (output to file) ; PrintEnv() { ; --- Custom Globals global COMPUTERNAME global USERNAME ; --- Windows Default-Globals ALLUSERSPROFILE := EnvGet("ALLUSERSPROFILE") APPDATA := EnvGet("APPDATA") COMMONPROGRAMFILES := EnvGet("COMMONPROGRAMFILES") COMPUTERNAME := EnvGet("COMPUTERNAME") HOMEDRIVE := EnvGet("HOMEDRIVE") HOMEPATH := EnvGet("HOMEPATH") LOCALAPPDATA := EnvGet("LOCALAPPDATA") LOGONSERVER := EnvGet("LOGONSERVER") PROGRAMDATA := EnvGet("PROGRAMDATA") ; PROGRAMFILES := EnvGet("PROGRAMFILES") PUBLIC := EnvGet("PUBLIC") SYSTEMDRIVE := EnvGet("SYSTEMDRIVE") SYSTEMROOT := EnvGet("SYSTEMROOT") TEMP := EnvGet("TEMP") TMP := EnvGet("TMP") USERDOMAIN := EnvGet("USERDOMAIN") USERNAME := EnvGet("USERNAME") USERPROFILE := EnvGet("USERPROFILE") WINDIR := EnvGet("WINDIR") MsgBoxOutput := "" ; ------------------------------ ; ; *** Windows Env-Vars *** ; ; MsgBoxOutput := MsgBoxOutput "*** Windows Env-Vars ***" "`n" ; MsgBoxOutput := MsgBoxOutput "`n" ; MsgBoxOutput := MsgBoxOutput "ALLUSERSPROFILE: " EnvGet("ALLUSERSPROFILE") "`n" ; MsgBoxOutput := MsgBoxOutput "APPDATA: " EnvGet("APPDATA") "`n" ; MsgBoxOutput := MsgBoxOutput "COMMONPROGRAMFILES: " EnvGet("COMMONPROGRAMFILES") "`n" ; MsgBoxOutput := MsgBoxOutput "COMPUTERNAME: " EnvGet("COMPUTERNAME") "`n" ; MsgBoxOutput := MsgBoxOutput "HOMEDRIVE: " EnvGet("HOMEDRIVE") "`n" ; MsgBoxOutput := MsgBoxOutput "HOMEPATH: " EnvGet("HOMEPATH") "`n" ; MsgBoxOutput := MsgBoxOutput "LOCALAPPDATA: " EnvGet("LOCALAPPDATA") "`n" ; MsgBoxOutput := MsgBoxOutput "LOGONSERVER: " EnvGet("LOGONSERVER") "`n" ; MsgBoxOutput := MsgBoxOutput "PROGRAMDATA: " EnvGet("PROGRAMDATA") "`n" ; MsgBoxOutput := MsgBoxOutput "PROGRAMFILES: " EnvGet("PROGRAMFILES") "`n" ; MsgBoxOutput := MsgBoxOutput "PUBLIC: " EnvGet("PUBLIC") "`n" ; MsgBoxOutput := MsgBoxOutput "SYSTEMDRIVE: " EnvGet("SYSTEMDRIVE") "`n" ; MsgBoxOutput := MsgBoxOutput "SYSTEMROOT: " EnvGet("SYSTEMROOT") "`n" ; MsgBoxOutput := MsgBoxOutput "TEMP: " EnvGet("TEMP") "`n" ; MsgBoxOutput := MsgBoxOutput "TMP: " EnvGet("TMP") "`n" ; MsgBoxOutput := MsgBoxOutput "USERDOMAIN: " EnvGet("USERDOMAIN") "`n" ; MsgBoxOutput := MsgBoxOutput "USERNAME: " EnvGet("USERNAME") "`n" ; MsgBoxOutput := MsgBoxOutput "USERPROFILE: " EnvGet("USERPROFILE") "`n" ; MsgBoxOutput := MsgBoxOutput "WINDIR: " EnvGet("WINDIR") "`n" ; ; ------------------------------ ; ; https://www.autohotkey.com/docs/v2/Variables.htm#CoordMode MsgBoxOutput := MsgBoxOutput "`n" MsgBoxOutput := MsgBoxOutput "----------------------------- AHK Env-Vars -----------------------------" "`n" MsgBoxOutput := MsgBoxOutput "`n" MsgBoxOutput := MsgBoxOutput "A_AhkPath: " A_AhkPath "`n" MsgBoxOutput := MsgBoxOutput "A_AhkVersion: " A_AhkVersion "`n" MsgBoxOutput := MsgBoxOutput "A_ControlDelay: " A_ControlDelay "`n" MsgBoxOutput := MsgBoxOutput "A_CoordModeCaret: " A_CoordModeCaret "`n" MsgBoxOutput := MsgBoxOutput "A_CoordModeMenu: " A_CoordModeMenu "`n" MsgBoxOutput := MsgBoxOutput "A_CoordModeMouse: " A_CoordModeMouse "`n" MsgBoxOutput := MsgBoxOutput "A_CoordModePixel: " A_CoordModePixel "`n" MsgBoxOutput := MsgBoxOutput "A_CoordModeToolTip: " A_CoordModeToolTip "`n" MsgBoxOutput := MsgBoxOutput "A_Cursor: " A_Cursor "`n" MsgBoxOutput := MsgBoxOutput "A_DefaultMouseSpeed: " A_DefaultMouseSpeed "`n" MsgBoxOutput := MsgBoxOutput "A_IconNumber: " A_IconNumber "`n" MsgBoxOutput := MsgBoxOutput "A_IconTip: " A_IconTip "`n" MsgBoxOutput := MsgBoxOutput "A_IsCompiled: " A_IsCompiled "`n" MsgBoxOutput := MsgBoxOutput "A_KeyDelay: " A_KeyDelay "`n" MsgBoxOutput := MsgBoxOutput "A_KeyDuration: " A_KeyDuration "`n" MsgBoxOutput := MsgBoxOutput "A_LineNumber: " A_LineNumber "`n" MsgBoxOutput := MsgBoxOutput "A_MouseDelay: " A_MouseDelay "`n" MsgBoxOutput := MsgBoxOutput "A_MSec: " A_MSec "`n" MsgBoxOutput := MsgBoxOutput "A_Now: " A_Now "`n" MsgBoxOutput := MsgBoxOutput "A_NowUTC: " A_NowUTC "`n" MsgBoxOutput := MsgBoxOutput "A_PriorHotkey: " A_PriorHotkey "`n" MsgBoxOutput := MsgBoxOutput "A_ScriptDir: " A_ScriptDir "`n" MsgBoxOutput := MsgBoxOutput "A_ScriptFullPath: " A_ScriptFullPath "`n" MsgBoxOutput := MsgBoxOutput "A_ScriptName: " A_ScriptName "`n" MsgBoxOutput := MsgBoxOutput "A_SendLevel: " A_SendLevel "`n" MsgBoxOutput := MsgBoxOutput "A_SendMode: " A_SendMode "`n" MsgBoxOutput := MsgBoxOutput "A_ThisFunc: " A_ThisFunc "`n" MsgBoxOutput := MsgBoxOutput "A_ThisHotkey: " A_ThisHotkey "`n" MsgBoxOutput := MsgBoxOutput "A_TickCount: " A_TickCount "`n" MsgBoxOutput := MsgBoxOutput "A_TimeSincePriorHotkey: " A_TimeSincePriorHotkey "`n" MsgBoxOutput := MsgBoxOutput "A_TimeSinceThisHotkey: " A_TimeSinceThisHotkey "`n" MsgBoxOutput := MsgBoxOutput "A_WinDelay: " A_WinDelay "`n" MsgBoxOutput := MsgBoxOutput "A_WorkingDir: " A_WorkingDir "`n" MsgBoxOutput := MsgBoxOutput "`n" MsgBoxOutput := MsgBoxOutput "----------------------------- Windows Env-Vars -----------------------------" "`n" MsgBoxOutput := MsgBoxOutput "`n" MsgBoxOutput := MsgBoxOutput "A_AppData: " A_AppData "`n" MsgBoxOutput := MsgBoxOutput "A_AppDataCommon: " A_AppDataCommon "`n" MsgBoxOutput := MsgBoxOutput "A_ComputerName: " A_ComputerName "`n" MsgBoxOutput := MsgBoxOutput "A_ComSpec: " A_ComSpec "`n" MsgBoxOutput := MsgBoxOutput "A_Desktop: " A_Desktop "`n" MsgBoxOutput := MsgBoxOutput "A_DesktopCommon: " A_DesktopCommon "`n" MsgBoxOutput := MsgBoxOutput "A_Is64bitOS: " A_Is64bitOS "`n" MsgBoxOutput := MsgBoxOutput "A_IsAdmin: " A_IsAdmin "`n" MsgBoxOutput := MsgBoxOutput "A_Language: " A_Language "`n" MsgBoxOutput := MsgBoxOutput "A_MyDocuments: " A_MyDocuments "`n" MsgBoxOutput := MsgBoxOutput "A_OSVersion: " A_OSVersion "`n" MsgBoxOutput := MsgBoxOutput "A_ProgramFiles: " A_ProgramFiles "`n" MsgBoxOutput := MsgBoxOutput "A_Programs: " A_Programs "`n" MsgBoxOutput := MsgBoxOutput "A_ProgramsCommon: " A_ProgramsCommon "`n" MsgBoxOutput := MsgBoxOutput "A_PtrSize: " A_PtrSize "`n" MsgBoxOutput := MsgBoxOutput "A_ScreenDPI: " A_ScreenDPI "`n" MsgBoxOutput := MsgBoxOutput "A_ScreenHeight: " A_ScreenHeight "`n" MsgBoxOutput := MsgBoxOutput "A_ScreenWidth: " A_ScreenWidth "`n" MsgBoxOutput := MsgBoxOutput "A_StartMenu: " A_StartMenu "`n" MsgBoxOutput := MsgBoxOutput "A_StartMenuCommon: " A_StartMenuCommon "`n" MsgBoxOutput := MsgBoxOutput "A_Startup: " A_Startup "`n" MsgBoxOutput := MsgBoxOutput "A_Temp: " A_Temp "`n" MsgBoxOutput := MsgBoxOutput "A_UserName: " A_UserName "`n" MsgBoxOutput := MsgBoxOutput "A_WinDir: " A_WinDir "`n" MsgBoxOutput := MsgBoxOutput "`n" MsgBoxOutput := MsgBoxOutput "----------------------------- SysGet Values -----------------------------" "`n" MsgBoxOutput := MsgBoxOutput "`n" MsgBoxOutput := MsgBoxOutput " 0 - SM_CXSCREEN: " SysGet(0) " (A_ScreenWidth)`n" MsgBoxOutput := MsgBoxOutput " 1 - SM_CYSCREEN: " SysGet(1) " (A_ScreenHeight)`n" MsgBoxOutput := MsgBoxOutput "76 - SM_XVIRTUALSCREEN: " SysGet(76) " (Viewport Top-Left, X)`n" MsgBoxOutput := MsgBoxOutput "77 - SM_YVIRTUALSCREEN: " SysGet(77) " (Viewport Top-Left, Y)`n" MsgBoxOutput := MsgBoxOutput "78 - SM_CXVIRTUALSCREEN: " SysGet(78) " (Viewport Width)`n" MsgBoxOutput := MsgBoxOutput "79 - SM_CYVIRTUALSCREEN: " SysGet(79) " (Viewport Height)`n" MsgBoxOutput := MsgBoxOutput "80 - SM_CMONITORS: " SysGet(80) " (Monitor Count)`n" MsgBoxOutput := MsgBoxOutput "`n" MsgBoxOutput := MsgBoxOutput "--------------------------------------------------------------------------------------------" "`n" Msgbox(MsgBoxOutput, A_ScriptName " - " A_ThisFunc) ; Note: For some reason, adding newlines to MsgBox makes it not wrap text ; ; TIMESTAMP := FormatTime("","yyyyMMddTHHmmss") ; Logfile_EnvVars := A_Desktop "\WindowsEnvVars-" COMPUTERNAME "-" USERNAME ".log" ; Logfile_EnvVars_Timestamp := A_Desktop "\WindowsEnvVars-" COMPUTERNAME "-" USERNAME "-" TIMESTAMP ".log" ; ; FileAppend KnownWinEnvVars, Logfile_EnvVars_Timestamp ; Run ("notepad.exe " Logfile_EnvVars_Timestamp) ; Return } ; ------------------------------ ; ; ProcessExist (proxy-function for GetPID(...)) ; |--> Returns True if process IS found ; |--> Returns False if process is NOT found ; ProcessExist(ProcName) { Return (GetPID(ProcName)>0) ? True : False } ; ------------------------------ ; ; RegexConsolidateNewlines ; |--> The characters '`n' & '`r' are interpreted the same (by Windows) when AHK 'types' them in (sends them). ; RegexConsolidateNewlines(InputString:="") { Return RegExReplace(InputString,"\r\n?|\n\r?","`n") } ; ------------------------------ ; ; RegexRemoveNewlines ; |--> Remove newline characters '`n' & '`r' from a string ; RegexRemoveNewlines(InputString:="") { Return RegExReplace(InputString,"\r|\n","") } ; ------------------------------ ; ; StringToUniqueInt ; |--> Returns the sum of ordinal values for every character in the input string - Relies on the "Ord" command - https://www.autohotkey.com/docs/v2/lib/Ord.htm ; StringToUniqueInt(InputString:="") { ReturnedVal := 0 If (InputString != "") { Loop Parse InputString { ReturnedVal += Ord(A_LoopField) } } Return ReturnedVal } ; ------------------------------ ; ; ReverseArray ; |--> Reverse an array - https://www.autohotkey.com/boards/viewtopic.php?p=297353#p297353 ; ReverseArray(InputArray:="") { Local i:=0, Each_ArrayItem, OutputArray := Array() For Each_ArrayItem in InputArray.Clone() { OutputArray.InsertAt(i,Each_ArrayItem) i := i - 1 } Return OutputArray } ; ------------------------------ ; ; RunExe_NON_Admin ; |--> Opens target program without administrative rights (by using a Scheduled Task de-escalation workaround) ; RunExe_NON_Admin(FullPath_RunExe, Exe_Args:="") { global DebugMode Semicolon := ";" Add_Args := "" If (Exe_Args != "") { Add_Args := (" -Argument (Write-Output " Exe_Args ")") } ; Prep the output powershell script's contents (which will get nested into a vbs script so that it can run silently via wscript.exe) PWSH_CLI := "" PWSH_CLI := PWSH_CLI "If ([Boolean](1)) { " PWSH_CLI := PWSH_CLI "SV TEMP_Execute '" FullPath_RunExe "'" Semicolon " " PWSH_CLI := PWSH_CLI "SV TEMP_Name (Get-Date -UFormat `%s)" Semicolon " " PWSH_CLI := PWSH_CLI "SV TEMP_Action (New-ScheduledTaskAction -Execute ((GV TEMP_Execute).Value)" Add_Args ")" Semicolon " " PWSH_CLI := PWSH_CLI "SV TEMP_Trigger (New-ScheduledTaskTrigger -Once -At (Get-Date))" Semicolon " " PWSH_CLI := PWSH_CLI "Register-ScheduledTask -Action ((GV TEMP_Action).Value) -Trigger ((GV TEMP_Trigger).Value) -TaskName ((GV TEMP_Name).Value)" Semicolon " " PWSH_CLI := PWSH_CLI "Start-ScheduledTask -TaskName ((GV TEMP_Name).Value)" Semicolon " " PWSH_CLI := PWSH_CLI "Start-Sleep -Seconds 1" Semicolon " " PWSH_CLI := PWSH_CLI "Unregister-ScheduledTask -TaskName ((GV TEMP_Name).Value) -Confirm:([Boolean](0))" Semicolon " " PWSH_CLI := PWSH_CLI "}" Semicolon " " PWSH_CLI := StrReplace(StrReplace(PWSH_CLI,"`t",""),"`n"," ") ; Prep the output VBS script's contents VbsScript_Contents := ("CreateObject( `"WScript.Shell`" ).Run `"PowerShell -Command `"`"" PWSH_CLI "`"`" `", 0, True") ; Build the output directory Temp_Dirname := (A_Temp "\" A_ScriptName "\" A_ThisFunc) ; Build a basename whose uniqueness is matched to the uniqueness of [ the input exe's basename prepended onto the sum of the ordinal value of all characters in the input args ] SplitPath FullPath_RunExe, &OutFileName Temp_VbsScript_Basename := (OutFileName "_" StringToUniqueInt(Exe_Args) ".vbs") Temp_VbsScript_FullPath := (Temp_Dirname "\" Temp_VbsScript_Basename) ; Create the VBS script file (if it doesn't already exist) If (!FileExist(Temp_VbsScript_FullPath)) { ; Create the VBS script's directory (if it doesn't already exist) If (!FileExist(Temp_Dirname)) { DirCreate Temp_Dirname } FileAppend VbsScript_Contents, Temp_VbsScript_FullPath } If (DebugMode == 1) { ; Debug - Show the command before running it ToolTipOutput := (A_ScriptName " - " A_ThisFunc "`n`n" StrReplace(StrReplace(PWSH_CLI,"{","{`n"),";",";`n")) ShowToolTip(TooltipOutput,,,5,60000) } ; Run_PowerShellScript_NonAdmin := ("powershell.exe -WindowStyle Hidden -Command `"" PWSH_CLI "`"") ; Run Run_PowerShellScript_NonAdmin Run_VbsScript_NonAdmin := ("C:\Windows\System32\wscript.exe `"" Temp_VbsScript_FullPath "`"") Run Run_VbsScript_NonAdmin Return } ; ------------------------------ ; ; RunWaitOne ; |--> Executes a single command through the current ComSpec (usually "cmd.exe") | https://www.autohotkey.com/docs/v1/lib/Run.htm#StdOut ; |--> Example-call: ; MsgBox(RunWaitOne("dir " A_ScriptDir)) ; RunWaitOne(CMD_Command) { global DebugMode ; WScript_Shell := ComObjCreate("WScript.Shell") WScript_Shell := ComObject("WScript.Shell") Run_Command := A_ComSpec " /C `"" CMD_Command "`" " If (DebugMode == 1) { TooltipOutput := "Run_Command=[" Run_Command "]" ToolTip(TooltipOutput,7500) } WScript_Shell_Exec := WScript_Shell.Run(Run_Command, 0, true) Return WScript_Shell_Exec } ; ------------------------------ ; ; RunWaitMany ; |--> Executes multiple commands through the current ComSpec (usually "cmd.exe") | https://www.autohotkey.com/docs/v1/lib/Run.htm#StdOut ; |--> Example-call: ; MsgBox(RunWaitMany(" ; ( ; echo Put your commands here, ; echo each one will be run, ; echo and you'll get the output. ; )")) ; RunWaitMany(CMD_Commands) { ; WScript_Shell := ComObjCreate("WScript.Shell") WScript_Shell := ComObject("WScript.Shell") ; Open cmd.exe with echoing of commands disabled WScript_Shell_Exec := WScript_Shell.Exec(A_ComSpec " /Q /K echo off") ; Send the commands to execute, separated by newline WScript_Shell_Exec.StdIn.WriteLine(CMD_Commands "`nexit") ; Always exit at the end! ; Read and return the output of all commands Return WScript_Shell_Exec.StdOut.ReadAll() } ; ------------------------------ ; ; SendDashedLine ; |--> Output a line of dashes ; SendDashedLine(LineLength:=60) { AwaitModifierKeyup() ; Wait until all modifier keys are released SetKeyDelay 0, -1 ; StringToType := StringRepeat("-",60) SendInput ("{- " LineLength "}") Return } ; ------------------------------ ; ; SendUnderscoreLine ; |--> Output a line of underscores ; SendUnderscoreLine(LineLength:=60) { AwaitModifierKeyup() ; Wait until all modifier keys are released SetKeyDelay 0, -1 ; StringToType := StringRepeat("-",60) SendInput ("{_ " LineLength "}") Return } ; ------------------------------ ; ; SendHostname ; |--> Send (type) the current device's Hostname - intended to be used for quick form filling ; SendHostname(VerbosityLevel:=0) { SetKeyDelay 0, -1 AwaitModifierKeyup() ; Wait until all modifier keys are released SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle Win_ahk_exe := WinGetProcessName("A") WinTitle := WinGetTitle("A") ; If (Win_ahk_exe == "chrome.exe") { ; WinGetPos(&xpos, &ypos, &Win_width, &Win_height, "A") ; If ((Win_width <= 450) && (Win_height <= 650)) { ; ; Chrome plugin ; VerbosityLevel := 1 ; } ; } If (VerbosityLevel >= 1) { NowTimestamp := FormatTime("","yyyy-MM-dd_HH-mm-ss") EchoStr := A_ComputerName " " NowTimestamp " " Win_ahk_exe Send ("{Blind}{Text}" EchoStr) } Else { Send ("{Blind}{Text}" A_ComputerName) } Return } ; ------------------------------ ; ; SendPseudoRandomString ; |--> Sends/Copies a psuedo-random string of characters ; SendPseudoRandomString(CopyStringToClipboard:=1) { global DebugMode SpecialChar := "@" PseudoRandomString := "" PseudoRandomString := PseudoRandomString . GetRandomString(1, 0, 0, 1, 0) ; 1 Uppercase PseudoRandomString := PseudoRandomString . GetRandomString(9, 1, 1, 0, 0) ; 9 Lowercase & Numbers PseudoRandomString := PseudoRandomString . SpecialChar ; 1 Special PseudoRandomString := PseudoRandomString . GetRandomString(9, 1, 1, 0, 0) ; 9 Lowercase & Numbers PasteClipboardAsText(PseudoRandomString) If (CopyStringToClipboard == 1) { A_Clipboard := PseudoRandomString If (DebugMode == 1) { Text_TrayTip := "Copied string to the Clipboard`nPaste with CTRL + V" TrayTip "AHK", Text_TrayTip ; Toast Notification } } } ; ------------------------------ ; ; SendRandomString ; |--> Sends/Copies a random string of characters ; SendRandomString(DesiredStringLength:=20, EnableNumbers:=1, EnableLowercaseLetters:=1, EnableUppercaseLetters:=0, EnableSpecialCharacters:=0, CopyStringToClipboard:=1, DoConfirmationPopup:=1) { global DebugMode BlockAction := 1 If (DoConfirmationPopup==0) { BlockAction := 0 } Else { A_MsgBoxResult := MsgBox("Generate Random String (overwrites clipboard contents)?", A_ScriptName " - " A_ThisFunc,4) If (A_MsgBoxResult = "Yes") { BlockAction := 0 } } If ( BlockAction == 0 ) { RandomString := GetRandomString(DesiredStringLength, EnableNumbers, EnableLowercaseLetters, EnableUppercaseLetters, EnableSpecialCharacters) PasteClipboardAsText(RandomString) If (CopyStringToClipboard == 1) { A_Clipboard := RandomString If (DebugMode == 1) { Text_TrayTip := "Copied string to the Clipboard`nPaste with CTRL + V" TrayTip "AHK", Text_TrayTip ; Toast Notification } } } } ; ------------------------------ ; ; SendSpace ; |--> For some reason, Windows 10 doesn't like Send {Space} (as-in it 'ignores' the keypress), but happily accepts Send {SC039} as equivalent to a spacebar-press ; SendSpace() { Send "{SC039}" Return } ; ------------------------------ ; ; ShowCursorCoordinates ; |--> Follows the mouse-cursor and displays its the X,Y coordinates (as a tooltip next to the cursor) ; ShowCursorCoordinates(FollowDuration_Seconds:=10) { PollDuration_ms := 10 Loop_Iterations := Floor((1000 * FollowDuration_Seconds) / PollDuration_ms) Loop Loop_Iterations { ; Win_ahk_exe := WinGetProcessName("A") ; ; Screen: "Coordinates are relative to the desktop (entire screen)." ; CoordMode "Mouse", "Screen" MouseGetPos &MouseX_Screen, &MouseY_Screen Tooltip_Coords_Screen := "x" MouseX_Screen " y" MouseY_Screen " (Screen)" ; ; Window: "Coordinates are relative to the active window." ; CoordMode "Mouse", "Window" MouseGetPos &MouseX_Window, &MouseY_Window Tooltip_Coords_Window := "x" MouseX_Window " y" MouseY_Window " (Window)" ; ; Client: "Coordinates are relative to the active window's client area, which excludes the window's title bar, menu (if it has a standard one) and borders. Client coordinates are less dependent on OS version and theme." ; CoordMode "Mouse", "Client" MouseGetPos &MouseX_Client, &MouseY_Client Tooltip_Coords_Client := "x" MouseX_Client " y" MouseY_Client " (Client)" Tooltip( Tooltip_Coords_Screen "`n" Tooltip_Coords_Window "`n" Tooltip_Coords_Client ) Sleep PollDuration_ms } ClearTooltip(0) Return } ; ------------------------------ ; ; ShowCursorPixelColor ; |--> Follows the mouse-cursor and displays the color of the pixel under it, continuously (as a tooltip next to the cursor) ; ShowCursorPixelColor(FollowDuration_Seconds:=10) { global DebugMode CoordMode "Pixel", "Screen" FollowDuration_ms := (1000 * FollowDuration_Seconds) If (DebugMode == 1) { OutputFile := A_Desktop "\rgblogging.txt" Logfile := FileOpen(OutputFile, "w") If (FileExist(OutputFile)) { FileDelete OutputFile } Logfile.write("`n") } PollDuration_ms := 10 Show_ResolvedColorName := 0 Last_MouseX := 0 Last_MouseY := 0 Last_Blue := 0 Last_Green := 0 Last_Red := 0 TickCount_BeforeLoop := A_TickCount Loop { Runtime_Net_ms := (A_TickCount-TickCount_BeforeLoop) RemainingHover_ms := (FollowDuration_ms - Runtime_Net_ms) RemainingHover_Seconds := Round((RemainingHover_ms/1000), 1) If ( RemainingHover_Seconds <= 0 ) { Break } Else { Sleep PollDuration_ms } ; ; Screen: "Coordinates are relative to the desktop (entire screen)." ; CoordMode "Mouse", "Screen" MouseGetPos &MouseX_Screen, &MouseY_Screen ; Screen: Get active monitor coords/dimensions Mouse_MonitorIndex := MouseGet_MonitorIndex() MonitorGetWorkArea(Mouse_MonitorIndex, &MonitorWorkArea_LeftCoord, &MonitorWorkArea_TopCoord, &MonitorWorkArea_RightCoord, &MonitorWorkArea_BottomCoord) Monitor_Width := (MonitorWorkArea_RightCoord - MonitorWorkArea_LeftCoord) Monitor_Height := (MonitorWorkArea_BottomCoord - MonitorWorkArea_TopCoord) ; ; Window: "Coordinates are relative to the active window." ; CoordMode "Mouse", "Window" MouseGetPos &MouseX_Window, &MouseY_Window ; ; Client: "Coordinates are relative to the active window's client area, which excludes the window's title bar, menu (if it has a standard one) and borders. Client coordinates are less dependent on OS version and theme." ; CoordMode "Mouse", "Client" MouseGetPos &MouseX_Client, &MouseY_Client Color := PixelGetColor(MouseX_Screen, MouseY_Screen) ColorComponent_Blue := (Color & 0xFF) ColorComponent_Green := ((Color & 0xFF00) >> 8) ColorComponent_Red := ((Color & 0xFF0000) >> 16) If (Show_ResolvedColorName == 1) { ColorDelta_BlueGreen := Abs(ColorComponent_Blue - ColorComponent_Green) ColorDelta_GreenRed := Abs(ColorComponent_Green - ColorComponent_Red) ColorDelta_BlueRed := Abs(ColorComponent_Blue - ColorComponent_Red) Color_ResolvedName := "???" If ((ColorComponent_Blue<=70) && (ColorComponent_Green<=70) && (ColorComponent_Red<=70)) { Color_ResolvedName := "Too-Dark" } Else If ((ColorDelta_GreenRed <= 10) && ((ColorComponent_Red-ColorComponent_Blue)>=20) && ((ColorComponent_Green-ColorComponent_Blue)>=15)) { Color_ResolvedName := "Yellow" } Else If (((ColorComponent_Red/ColorComponent_Green) >= 1.1) && ((ColorComponent_Red - ColorComponent_Green) >= 10) && ((ColorComponent_Red/ColorComponent_Blue) >= 1.1) && ((ColorComponent_Red - ColorComponent_Blue) >= 10) && ((ColorComponent_Blue-ColorComponent_Green) >= -5)) { Color_ResolvedName := "Magenta" } Else If ((ColorComponent_Green >= 40) && ((ColorComponent_Green - ColorComponent_Blue) >= 15) && ((ColorComponent_Green - ColorComponent_Red) >= 15) && (ColorDelta_BlueRed <= 15)) { Color_ResolvedName := "Green" } Else If (((ColorComponent_Blue/ColorComponent_Green) <= 1.35) && ((ColorComponent_Green/ColorComponent_Red) <= 1.35) && ((ColorComponent_Blue/ColorComponent_Red) <= 1.35)) { Color_ResolvedName := "White" } Else If ( (((ColorComponent_Blue-ColorComponent_Green)>=10)||((ColorComponent_Blue>=245)&&(ColorComponent_Green>=235))) && ((ColorComponent_Blue - ColorComponent_Red) >= 20) && ((ColorComponent_Green - ColorComponent_Red) >= 5)) { Color_ResolvedName := "Blue" } } TooltipOutput := "" TooltipOutput := TooltipOutput "Mouse Coords:" "`n" TooltipOutput := TooltipOutput " x" MouseX_Screen " y" MouseY_Screen " (Screen)" "`n" TooltipOutput := TooltipOutput " x" MouseX_Window " y" MouseY_Window " (Window)" "`n" TooltipOutput := TooltipOutput " x" MouseX_Client " y" MouseY_Client " (Client)" "`n" TooltipOutput := TooltipOutput "`n" TooltipOutput := TooltipOutput "Pixel Color:" "`n" TooltipOutput := TooltipOutput " " Color " (Hex)" "`n" TooltipOutput := TooltipOutput " rgb(" ColorComponent_Red "," ColorComponent_Green "," ColorComponent_Blue ")" "`n" TooltipOutput := TooltipOutput "`n" TooltipOutput := TooltipOutput "Monitor (Current):" "`n" TooltipOutput := TooltipOutput " Index: " Mouse_MonitorIndex "`n" TooltipOutput := TooltipOutput " Width: " Monitor_Width " / Height: " Monitor_Height "`n" TooltipOutput := TooltipOutput " x" MonitorWorkArea_LeftCoord " y" MonitorWorkArea_TopCoord " (Top-Left)" "`n" TooltipOutput := TooltipOutput " x" MonitorWorkArea_RightCoord " y" MonitorWorkArea_BottomCoord " (Bottom-Right)" "`n" TooltipOutput := TooltipOutput "`n" If (Show_ResolvedColorName == 1) { TooltipOutput := TooltipOutput "Color_ResolvedName=[" Color_ResolvedName "] " "`n" } If (DebugMode == 1) { TooltipOutput := TooltipOutput "OutputFile=[" OutputFile "] " "`n" } If ((Last_MouseX != MouseX_Screen) || (Last_MouseY != MouseY_Screen) || (Last_Blue != ColorComponent_Blue) || (Last_Green != ColorComponent_Green) || (Last_Red != ColorComponent_Red)) { ToolTip TooltipOutput ; Only perform updates if any discernible change is detected (amongst colors & mouse position values) If (DebugMode == 1) { LogfileOutput := StrReplace(TooltipOutput,"`n"," ") Logfile.write(LogfileOutput "`n") } Last_MouseX := MouseX_Screen Last_MouseY := MouseY_Screen Last_Blue := ColorComponent_Blue Last_Green := ColorComponent_Green Last_Red := ColorComponent_Red } } If (DebugMode == 1) { Logfile.close() Sleep 250 Run("Notepad " OutputFile) } ClearTooltip(0) Return } ; ------------------------------ ; ; ShowToolTip ; |--> Show a tooltip at a given X/Y location on the screen until a set number of milliseconds has elapsed, then clear the tooltip ; |--> https://www.autohotkey.com/docs/v2/lib/ToolTip.htm ; ShowToolTip(Text:="", X:="", Y:="", WhichToolTip:=1, Period:=5000) { global ShowToolTip_Map_TickCounts Start_TickCount := A_TickCount ShowToolTip_Map_TickCounts[WhichToolTip] := Start_TickCount ; Store the latest value of [ Start_TickCount ] into its associated map index SetTimer () => ShowToolTip_Auto(Text, X, Y, WhichToolTip, Period, Start_TickCount), 50 ; SetTimer () => ClearTooltip(0,WhichToolTip), (Period * -1) ; ClearTooltip(0,WhichToolTip) Return } ShowToolTip_Auto(Text:="", X:="", Y:="", WhichToolTip:=1, Period:=5000, Start_TickCount:=0) { global DebugMode global ShowToolTip_Map_Text global ShowToolTip_Map_TickCounts CoordMode "Mouse", "Screen" CoordMode "ToolTip", "Screen" Remaining_TickCount := (Period-(A_TickCount-Start_TickCount)) ; Handle multiple calls to the same function & only use the latest call (to allow tooltips to have their content updated but their display time also updated and not hidden shortly after their updated data is displayed due to the deprecated tooltip call clearing it early) If ((ShowToolTip_Map_TickCounts[WhichToolTip] != Start_TickCount) || (Remaining_TickCount <= 0)) { ShowToolTip_Map_Text[WhichToolTip] := "" ; Reset this tooltip's value in the text map ClearTooltip(0,WhichToolTip) ; Remove the tooltip SetTimer , 0 ; Mark the timer for deletion } Else { ; ------------------------------ If (0 = 1 ) { ; ; TO DO: ; Get the data/text currently displayed/contained in the associated tooltip (to determine if it needs to be updated or not) ; Tooltip_CurrentText := ControlGetText("ahk_class tooltips_class32") ; ; Also refer to [ https://www.autohotkey.com/board/topic/53672-get-the-text-content-of-a-tool-tip-window ] ; ; ------------------------------ } ; ------------------------------ TooltipOutput := Text If (DebugMode == 1) { TooltipOutput := TooltipOutput "`n" Round((Remaining_TickCount/1000),3) } ; Only update the tooltip text if it doesn't already contain said the value of said text If (ShowToolTip_Map_Text[WhichToolTip] == RegexConsolidateNewlines(TooltipOutput)) { ; (Skipped) Tooltip already contains desired contents } Else { ; Update the tooltip contents If (IsInteger(X) && IsInteger(Y)) { ShowToolTip_Map_Text[WhichToolTip] := RegexConsolidateNewlines(TooltipOutput) ; Store the latest value of [ TooltipOutput ] into its associated map index ToolTip TooltipOutput, Format("{:d}",X), Format("{:d}",Y), WhichToolTip ; Show the tooltip } Else { ; If X & Y are both non-integer values, then display the tooltip next to the mouse's current location MonitorGetWorkArea(, &MonitorLeft, &MonitorTop, &MonitorRight, &MonitorBottom) MonitorWidth := (MonitorRight-MonitorLeft) MonitorHeight := (MonitorBottom-MonitorTop) MouseGetPos &MouseX, &MouseY xpos := Floor( MouseX + ((WhichToolTip-0.5)/20)*(MonitorWidth) ) ypos := Floor( MouseY + ((WhichToolTip-1)/20)*(MonitorHeight) ) ShowToolTip_Map_Text[WhichToolTip] := RegexConsolidateNewlines(TooltipOutput) ; Store the latest value of [ TooltipOutput ] into its associated map index ToolTip TooltipOutput, xpos, ypos, WhichToolTip ; Show the tooltip } } ; ------------------------------ } Return } ; Maps (associative arrays) containing the latest data for every tooltip index (1-20) ShowToolTip_Map_Text := Map(1,"",2,"",3,"",4,"",5,"",6,"",7,"",8,"",9,"",10,"",11,"",12,"",13,"",14,"",15,"",16,"",17,"",18,"",19,"",20,"") ShowToolTip_Map_TickCounts := Map(1,"",2,"",3,"",4,"",5,"",6,"",7,"",8,"",9,"",10,"",11,"",12,"",13,"",14,"",15,"",16,"",17,"",18,"",19,"",20,"") ; ------------------------------ ; ; ShowVolumeLevel ; |--> Show a the current volume level as a tooltip. Displays the volume % shown as both [ an integer ] as well as [ a set of bars filled from left (0%) to right (100%) ]. Also displays a mute icon (when muted) ; ShowVolumeLevel() { CoordMode "Mouse", "Screen" CoordMode "ToolTip", "Screen" Icon_MutedSpeaker := "🔇" Icon_SpeakerLowVolume := "🔈" Icon_SpeakerMediumVolume := "🔉" Icon_SpeakerHighVolume := "🔊" Icon_VolumeFilled := "⬛️" Icon_VolumeBlanks := "⬜️" ; Get the volume & mute current-settings NewVolumeLevel := SoundGetVolume() MasterMute := SoundGetMute() ; Final volume level NewVolumeLevel := Round( NewVolumeLevel ) NewVolumeLevelPercentage := NewVolumeLevel "`%" ; Build the volume-bars (out-of dingbats/utf8+ icons) Total_IconCount_MaxVolume := 20 IconCount_TopBot_Filled := Round( ( NewVolumeLevel / 100 ) * Total_IconCount_MaxVolume) IconCount_TopBot_Blanks := Total_IconCount_MaxVolume - IconCount_TopBot_Filled DisplayedIcons_TopBot_Filled := StringRepeat( Icon_VolumeFilled, IconCount_TopBot_Filled ) DisplayedIcons_TopBot_Blanks := StringRepeat( Icon_VolumeBlanks, IconCount_TopBot_Blanks ) VolumeBars_TopBot := DisplayedIcons_TopBot_Filled DisplayedIcons_TopBot_Blanks IconCount_Middle_Filled := Round( ( NewVolumeLevel / 100 ) * Total_IconCount_MaxVolume) - 4 IconCount_Middle_Blanks := Total_IconCount_MaxVolume - IconCount_Middle_Filled DisplayedIcons_Middle_Filled := StringRepeat( Icon_VolumeFilled, IconCount_Middle_Filled ) DisplayedIcons_Middle_Blanks := StringRepeat( Icon_VolumeBlanks, IconCount_Middle_Blanks ) VolumeBars_Middle := DisplayedIcons_Middle_Filled DisplayedIcons_Middle_Blanks TrimCount_TopBot := Round( StrLen( VolumeBars_TopBot ) / 2 ) TrimCount_Middle := Round( StrLen( VolumeBars_Middle ) / 2 ) Echo_TopBot_LeftHalf := RTrim(SubStr(VolumeBars_TopBot, 1, (StrLen(VolumeBars_TopBot)-TrimCount_TopBot) )) Echo_TopBot_RightHalf := RTrim(SubStr(VolumeBars_TopBot, TrimCount_TopBot, StrLen(VolumeBars_TopBot))) Echo_TopBot_LeftHalf := Icon_SpeakerMediumVolume A_Space A_Space A_Space Echo_TopBot_LeftHalf Echo_TopBot_RightHalf := Echo_TopBot_RightHalf A_Space A_Space Icon_SpeakerHighVolume Echo_Middle_LeftHalf := Echo_TopBot_LeftHalf Echo_Middle_RightHalf := Echo_TopBot_RightHalf IconSlice_Middle_EitherSide := 3 Mute_AddSpaces := 2 Echo_Middle_LeftHalf := SubStr( Echo_TopBot_LeftHalf, 1, ( -1 * IconSlice_Middle_EitherSide * StrLen( Icon_VolumeFilled )) ) Echo_Middle_RightHalf := SubStr( Echo_TopBot_RightHalf, ( IconSlice_Middle_EitherSide * StrLen( Icon_VolumeFilled )) ) ; Show mute status next to the integer volume level ; |--> Replace mute-icon w/ whitespace if un-muted Mute_StatusIcon := ( ( MasterMute ) ? ( Icon_MutedSpeaker ) : ( StringRepeat( A_Space , 4 ) ) ) Mute_LSpaces := ( Round( Mute_AddSpaces / 2 ) ) Mute_RSpaces := ( Mute_AddSpaces - Mute_LSpaces ) Mute_Padding := StringRepeat( A_Space , Mute_LSpaces ) Mute_StatusIcon StringRepeat( A_Space , Mute_RSpaces ) If ( NewVolumeLevel == 100 ) { ; Mute_AddSpaces := Mute_AddSpaces + 0 Echo_Middle_Center := Mute_Padding NewVolumeLevel Mute_Padding } Else If ( NewVolumeLevel >= 10 ) { ; Mute_AddSpaces := Mute_AddSpaces + 1 Echo_Middle_Center := Mute_Padding A_Space A_Space NewVolumeLevel Mute_Padding } Else { ; Mute_AddSpaces := Mute_AddSpaces + 2 Echo_Middle_Center := Mute_Padding A_Space A_Space NewVolumeLevel A_Space A_Space Mute_Padding } Echo_TopBot_Center := StringRepeat( A_Space , 0 ) Echo_Tooltip := "" Echo_Tooltip := Echo_Tooltip Echo_TopBot_LeftHalf Echo_TopBot_Center Echo_TopBot_RightHalf "`n" Echo_Tooltip := Echo_Tooltip Echo_Middle_LeftHalf Echo_Middle_Center Echo_Middle_RightHalf "`n" Echo_Tooltip := Echo_Tooltip Echo_TopBot_LeftHalf Echo_TopBot_Center Echo_TopBot_RightHalf ; ------------------------------ ; End of calculations for [ text formatting ] ; Start of calculations for [ tooltip placement ] ; ------------------------------ ToolTip_Width := 254 ToolTip_Height := 50 StartMenu_Height := 40 ToolTip_XPos := 50 ; Fallback/default values ToolTip_YPos := 50 ; Fallback/default values ; ------------------------------ MonitorGetWorkArea(MouseGet_MonitorIndex(), &MonitorWorkArea_LeftCoord, &MonitorWorkArea_TopCoord, &MonitorWorkArea_RightCoord, &MonitorWorkArea_BottomCoord) Monitor_Width := (MonitorWorkArea_RightCoord - MonitorWorkArea_LeftCoord) Monitor_Height := (MonitorWorkArea_BottomCoord - MonitorWorkArea_TopCoord) ToolTip_XPos := Round(MonitorWorkArea_LeftCoord+((Monitor_Width - ToolTip_Width) / 2)) ToolTip_YPos := Round(Monitor_Height - StartMenu_Height - (ToolTip_Height*2)) ; ------------------------------ ; Note: Windows default volume display shows for a total of 3.5 seconds (with the last 1.0 seconds being a fade out) ShowToolTip(Echo_Tooltip, ToolTip_XPos, ToolTip_YPos, ,1500) ; ToolTip Echo_Tooltip, ToolTip_XPos, ToolTip_YPos ; ClearTooltip(1500) ; Note: Windows default volume display shows for a total of 3.5 seconds (with the last 1.0 seconds being a fade out) ; ------------------------------ Return } ; ------------------------------ ; ; SpaceUp_Loop ; |--> Designed for Windows Task Scheduler to quickly show open all tasks on the main page, which can then be sorted (but only for the ones that've been opened) ; SpaceUp_Loop(LoopIterations) { Loop LoopIterations { Sleep 500 Send "{SC039}" SendSpace() Sleep 500 Send "{Up}" } Return } ; ------------------------------ ; ; StringRepeat ; |--> Repeat a string a given number of times ; StringRepeat(StrToRepeat, Multiplier) { ReturnedVal := "" If (Multiplier > 0) { Loop { If (A_Index > Multiplier) { Break } ReturnedVal .= StrToRepeat } } Return ReturnedVal } ; ------------------------------ ; ; StrLen_Max ; | ; |--> Description: ; | Compare strings/arrays of strings - return the longest string amongst them ; | ; |--> Parameters: ; @param {string/array} StrOrObj_1 Either a string or array of strings to find the longest string out of ; @param {string/array} StrOrObj_2 Either a string or array of strings to find the longest string out of ; StrLen_Max(StrOrObj_1:="", StrOrObj_2:="") { LongestString := "" ; Parameter 1 - Handle array- or string-typed inputs If (IsArray(StrOrObj_1) == True) { ; Handle array-typed inputs For EachStr1 in StrOrObj_1 { If (StrLen(EachStr1) > StrLen(LongestString)) { ; Return the longest string the given array LongestString := EachStr1 } } } Else { ; Handle string-typed inputs If (StrLen(StrOrObj_1) > StrLen(LongestString)) { LongestString := StrOrObj_1 } } ; Parameter 2 - Handle array- or string-typed inputs If (IsArray(StrOrObj_2) == True) { ; Handle array-typed inputs For EachStr2 in StrOrObj_2 { If (StrLen(EachStr2) > StrLen(LongestString)) { ; Return the longest string the given array LongestString := EachStr2 } } } Else { ; Handle string-typed inputs If (StrLen(StrOrObj_2) > StrLen(LongestString)) { LongestString := StrOrObj_2 } } Return LongestString } ; ------------------------------ ; ; StrLenUnicode ; |--> Get String-Length for unicode string(s)? (Need better description) ; StrLenUnicode(data) { RegExReplace(data, "s).", "", &i) Return i } ; ------------------------------ ; ; TabSpace_Loop ; |--> Designed for Samsung SmartThings' Web-IDE where (sometimes) multiple hundreds of checkboxes need to be selected individually to update from a Git repo ; TabSpace_Loop(LoopIterations) { Loop LoopIterations { Send "{Tab}" Sleep 10 Send "{Space}" Sleep 10 } Return } ; ------------------------------ ; ; TempFile ; |--> Creates a temporary file with a timestamp (down to the millisecond) based filename ; |--> Returns a string-value containing the fullpath of the temporary file (which was just created) ; TempFile() { TempFile_Dirname := A_Temp "\AutoHotkey\" If (!FileExist(TempFile_Dirname)) { DirCreate TempFile_Dirname } TempFile_Basename := A_Now "." A_MSec TempFile_Fullpath := TempFile_Dirname TempFile_Basename Return TempFile_Fullpath } ; ------------------------------ ; ; Windows_RefreshTrayIcons ; |--> Removes any 'dead' tray icons from the notification area / system tray ; |--> Citation: https://www.autohotkey.com/boards/viewtopic.php?p=156072#p156072 ; Windows_RefreshTrayIcons() { CoordMode "Mouse", "Window" RB_DetectHiddenWindows := A_DetectHiddenWindows DetectHiddenWindows 1 SetTitleMatchMode 3 ; Title must [ EXACTLY MATCH ] the given WinTitle WM_MOUSEMOVE := 0x0200 ; https://www.autohotkey.com/docs/v1/misc/SendMessageList.htm For Each_Id, Each_Title in ["ahk_class Shell_TrayWnd","ahk_class NotifyIconOverflowWindow"] { For Each_Id, Each_ControlName in ["ToolbarWindow321", "ToolbarWindow322", "ToolbarWindow323", "ToolbarWindow324"] { For Each_Id, Each_IconSize in [24,32] { Try { ControlGetPos(&xTray, &yTray, &wdTray, &htTray, Each_ControlName, Each_Title) } Catch as e { } Else { y := Integer(htTray-10) While (y > 0) { x := Integer(wdTray-(Each_IconSize/2)) While (x > 0) { Point := ( Integer(Integer(y) << 16) + Integer(x) ) PostMessage(WM_MOUSEMOVE, 0, Point, Each_ControlName, Each_Title) x -= Integer(Each_IconSize/2) } y -= Integer(Each_IconSize/2) } } } } } DetectHiddenWindows RB_DetectHiddenWindows } ; ------------------------------ ; ; WinGet_ahk_id ; | ; |--> Description: ; | Determines target process (exe)'s [ unique ID (e.g. 'HWND', which is short for "handle to window") ] ; | Intended to transparently inspect THROUGH "ApplicationFrameHost.exe" (which runs Windows 10 'apps' (applications)) ; | ; |--> Ex) Win_ahk_id := WinGet_ahk_id("A") ; WinGet_ahk_id(WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="") { Win_ahk_exe := WinGetProcessName(WinTitle,WinText,ExcludeTitle,ExcludeText) If (Win_ahk_exe = "ApplicationFrameHost.exe") { Win_ahk_id := ControlGetHwnd("Windows.UI.Core.CoreWindow1",WinTitle,WinText,ExcludeTitle,ExcludeText) } Else { Win_ahk_id := WinGetID(WinTitle,WinText,ExcludeTitle,ExcludeText) } Return Win_ahk_id } ; ------------------------------ ; ; WinGet_IsWin10App ; | ; |--> Description: ; | Determines if target-app is running in "ApplicationFrameHost.exe" (which runs Windows 10 'apps' (applications)) ; | ; |--> Ex) Win_is_win10_app := WinGet_IsWin10App("A") ; WinGet_IsWin10App(WinTitle:="A") { Win_ahk_exe := WinGetProcessName(WinTitle) Win_is_win10_app := 0 If (Win_ahk_exe = "ApplicationFrameHost.exe") { Win_is_win10_app := 1 } Return Win_is_win10_app } ; ------------------------------ ; ; WinGet_SizeState ; | ; |--> Description: ; | Returns "Minimized", "Restored" or "Maximized" depending on the value returned from WinGetMinMax ; | ; |--> Ex) Win_size_state := WinGet_SizeState("A") ; WinGet_SizeState(WinTitle:="A",WinText:="") { Win_MinMaxState := WinGetMinMax(WinTitle,WinText) Win_size_state := "" If (Win_MinMaxState == 0) { Win_size_state := "restored" } Else If (Win_MinMaxState == -1) { Win_size_state := "minimized" } Else If (Win_MinMaxState == 1) { Win_size_state := "maximized" } Return Win_size_state } ; ------------------------------ ; ; WinGet_MonitorIndex ; | ; |--> Description: ; | Returns the Monitor Index (integer) of the monitor containing target window ; | ; |--> Ex) Win_MonitorIndex := WinGet_MonitorIndex(("ahk_id " WinGetID("A"))) ; WinGet_MonitorIndex(WinTitle:="A",WinText:="") { ; Default to monitor #1 Win_MonitorIndex := 1 ; Determine the center position for target window WinGetPos(&Win_XPos, &Win_YPos, &Win_Width, &Win_Height, WinTitle) Win_Center_XPos := Win_XPos + (Win_Width/2) Win_Center_YPos := Win_YPos + (40/2) ; Compensate for the taskbar being 40px tall (Assume non-vertically stacked monitors) ; Walk through each connected display Loop MonitorGetCount() { Each_MonitorIndex := A_Index ; Docs: "Check if the specified monitor exists and optionally retrieve the bounding coordinates of its working area" - https://www.autohotkey.com/docs/v2/lib/MonitorGetWorkArea.htm MonitorGetWorkArea(Each_MonitorIndex, &EachMonitor_LeftCoord, &EachMonitor_TopCoord, &EachMonitor_RightCoord, &EachMonitor_BottomCoord) ; Determine if the center of target window is currently located within the bounds of this monitor's work area If ((Win_Center_XPos>=EachMonitor_LeftCoord) && (Win_Center_XPos<=EachMonitor_RightCoord)) { If ((Win_Center_YPos>=EachMonitor_TopCoord) && (Win_Center_YPos<=EachMonitor_BottomCoord)) { Win_MonitorIndex := Each_MonitorIndex Break } } } ; Return the monitor index which the target window is currently centered on Return Win_MonitorIndex } ; ------------------------------ ; ; WinSnap ; |--> "I wanted to be able to set a window to the top half or bottom half of a monitor just like windows 7 can do with left and right. I couldn't find a good script that worked well with my 3 monitor landscape / portrait layout. So I wrote one." -MrMaxP ; |--> https://www.autohotkey.com/board/topic/108780-move-window-to-half-quarter-of-current-monitor/?p=648327 ; WinSnap(WinTitle:="A",WinText:="",ExcludeTitle:="",ExcludeText:="",Destination_Direction:="Left",Destination_Size:="Half",Destination_MonitorNumber:="UseCurrentMonitor") { ; Destination_Direction := [ "Left", "Right", "Top", "Bottom", "Maximized", "Restored" ] ; Destination_Size := [ "Half","Left","Right","Top","Bottom" ] global DebugMode global WinSnap_Prior_Destination_Direction global WinSnap_Prior_Destination_MonitorNumber global WinSnap_Prior_Destination_Size SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle CoordMode "Mouse", "Screen" ; Strip the word "Monitor" off of the destination monitor's string (to get it as an integer) Destination_MonitorNumber := StrReplace(Destination_MonitorNumber,"Monitor","") ; Detect repeat hotkey presses & cycle windows across all monitors in response If ((A_PriorHotkey==A_ThisHotkey) && (A_TimeSincePriorHotkey <= 2000)) { ; This IS a repeated hotkey press RepeatHotkeyPress := True If (WinSnap_Prior_Destination_Direction=="Left") { ; Snap to the right on the same monitor as the last snap Destination_Direction := "Right" Destination_MonitorNumber := WinSnap_Prior_Destination_MonitorNumber } Else If (WinSnap_Prior_Destination_Direction=="Right") { ; Snap to the left on the "next" monitor (to the right assumed) Destination_Direction := "Left" Destination_MonitorNumber := ( WinSnap_Prior_Destination_MonitorNumber + 1 ) If (Destination_MonitorNumber > MonitorGetCount()) { ; Wrap around back to the first/leftmost monitor if the window was already on the right of the rightmost monitor Destination_MonitorNumber := 1 } } } Else { ; This is NOT a repeated hotkey press - Store its values to iterate off of later RepeatHotkeyPress := False ; If there's only one monitor, force requests to use monitor "1", instead If (MonitorGetCount()==1) { Destination_MonitorNumber := 1 } ; Instantiate the "prior" values based on these initial, non-repeated values (baseline) WinSnap_Prior_Destination_Direction := Destination_Direction WinSnap_Prior_Destination_MonitorNumber := Destination_MonitorNumber WinSnap_Prior_Destination_Size := Destination_Size } ; ------------------------------ Loop 50 { ; Windows .exes can start in the background well before their visible window component is grabbable by AHK ; |--> Give the target Window(s) some breathing room to start up, but also act on them as soon as they are started Win_hwnd := WinExist(WinTitle,WinText,ExcludeTitle,ExcludeText) If (Win_hwnd) { Break } Else { Sleep 100 } } ; ------------------------------ If (!Win_hwnd) { TooltipOutput := A_ScriptName " - " A_ThisFunc "`n" TooltipOutput := TooltipOutput "`n" TooltipOutput := TooltipOutput "Error - No window found matching:" "`n" TooltipOutput := TooltipOutput "`n" TooltipOutput := TooltipOutput " Win_hwnd: [ " Win_hwnd " ]" "`n" If (WinTitle != "") { TooltipOutput := TooltipOutput " WinTitle: [ " WinTitle " ]" "`n" } If (WinText != "") { TooltipOutput := TooltipOutput " WinText: [ " WinText " ]" "`n" } If (ExcludeTitle != "") { TooltipOutput := TooltipOutput " ExcludeTitle: [ " ExcludeTitle " ]" "`n" } If (ExcludeText != "") { TooltipOutput := TooltipOutput " ExcludeText: [ " ExcludeText " ]" "`n" } ShowToolTip(TooltipOutput,,,,4000) } Else { ; Check if action to be performed is a simple window restore If (Destination_Direction=="Restored") { ; ; Set window state to "Restored" ; |--> Do not handle window restoration onto other monitors, as the dimensions of a window could skew it outside of the bounds of target monitor (and I'm too lazy to do the coding for making sure the window from monitor "1" (for example) fits onto a potentially-smaller monitor "2", but also if you resize the window in the process, it wouldn't truly be a 'restore' action anymore, so yeah just skip the 'feature' of restoring to any monitor other than the window's current monitor) ; WinRestore(WinTitle, WinText) } Else { ; Get the window's current xpos, ypos, width & height WinGetPos(&Win_XPos, &Win_YPos, &Win_Width, &Win_Height, WinTitle, WinText) ; Check if window is Maximized/Minimized, then prep accordingly If (WinGetMinMax(WinTitle,WinText)==1) { ; Window is Maximized --> Adjust its xpos and ypos by +8 (as Windows (for some reason) sets the top-left coords of maximized windows to -8,-8 x,y relative to the top-left coords of the monitor it's on) ; Win_XPos := Win_XPos + 8 ; Win_YPos := Win_YPos + 8 } Else If ((WinGetMinMax(WinTitle,WinText)==-1) || ((WinGetMinMax(WinTitle,WinText)!=1) && (Win_Width < -8) && (Win_Height < -8))) { ; Note: Window [xpos,ypos] can sometimes be set to [-8,-8] when maximized ; Window is Minimized (which prevents AHK from obtaining the window's current xpos, ypos, width & height) --> Restore it WinRestore(WinTitle, WinText) Sleep 750 WinGetPos(&Win_XPos, &Win_YPos, &Win_Width, &Win_Height, WinTitle, WinText) } Do_Maximized := False ; Calculate the top center edge Win_Center_XPos := Win_XPos + Win_Width/2 Win_Center_YPos := Win_YPos + (40/2) ; Compensate for the taskbar being 40px tall - assume non-vertically stacked monitors Win_Center_MonitorNumber := 0 WinMove_XPos := -1 WinMove_YPos := -1 WinMove_Width := -1 WinMove_Height := -1 Matched_MonitorNumber := -1 Loop MonitorGetCount() { Each_MonitorIndex := A_Index ; Docs: "Check if the specified monitor exists and optionally retrieve the bounding coordinates of its working area" - https://www.autohotkey.com/docs/v2/lib/MonitorGetWorkArea.htm MonitorGetWorkArea(Each_MonitorIndex, &EachMonitor_LeftCoord, &EachMonitor_TopCoord, &EachMonitor_RightCoord, &EachMonitor_BottomCoord) ; Determine if the current iteration's monitor is the destination monitor MoveTo_ThisMonitor := False ; ------------------------------ If (DebugMode == 1) { TooltipOutput := "" TooltipOutput := TooltipOutput " " "`n" TooltipOutput := TooltipOutput "Each_MonitorIndex: " Each_MonitorIndex "`n" TooltipOutput := TooltipOutput "`n" TooltipOutput := TooltipOutput "EachMonitor_LeftCoord: " EachMonitor_LeftCoord "`n" TooltipOutput := TooltipOutput "EachMonitor_RightCoord: " EachMonitor_RightCoord "`n" TooltipOutput := TooltipOutput "`n" TooltipOutput := TooltipOutput "EachMonitor_TopCoord: " EachMonitor_TopCoord "`n" TooltipOutput := TooltipOutput "EachMonitor_BottomCoord: " EachMonitor_BottomCoord "`n" TooltipOutput := TooltipOutput "`n" TooltipOutput := TooltipOutput "RepeatHotkeyPress: " RepeatHotkeyPress "`n" TooltipOutput := TooltipOutput "`n" TooltipOutput := TooltipOutput "Destination_Direction: " Destination_Direction "`n" TooltipOutput := TooltipOutput "Destination_MonitorNumber: " Destination_MonitorNumber "`n" TooltipOutput := TooltipOutput "Destination_Size: " Destination_Size "`n" TooltipOutput := TooltipOutput "`n" TooltipOutput := TooltipOutput "WinSnap_Prior_Destination_Direction: " WinSnap_Prior_Destination_Direction "`n" TooltipOutput := TooltipOutput "WinSnap_Prior_Destination_MonitorNumber: " WinSnap_Prior_Destination_MonitorNumber "`n" TooltipOutput := TooltipOutput "WinSnap_Prior_Destination_Size: " WinSnap_Prior_Destination_Size "`n" TooltipOutput := TooltipOutput " " ; ShowToolTip(TooltipOutput,EachMonitor_LeftCoord,EachMonitor_TopCoord,(Each_MonitorIndex+1),60000) ShowToolTip(TooltipOutput,EachMonitor_LeftCoord,EachMonitor_TopCoord,(Each_MonitorIndex*2),60000) } ; Determine if the center of target window is currently located within the bounds of this monitor's work area If ((Win_Center_XPos>=EachMonitor_LeftCoord) && (Win_Center_XPos<=EachMonitor_RightCoord)) { If ((Win_Center_YPos>=EachMonitor_TopCoord) && (Win_Center_YPos<=EachMonitor_BottomCoord)) { ; Window is located on this monitor Win_Center_MonitorNumber := A_Index If (InStr(Destination_MonitorNumber,"Current")==True) { ; Set the destination monitor equal to the window's current monitor MoveTo_ThisMonitor := True } } } If (Destination_MonitorNumber==Each_MonitorIndex) { ; Set the destination monitor equal to a predefined monitor MoveTo_ThisMonitor := True } If (MoveTo_ThisMonitor == True) { ; Monitor is to be used as the window's destination Matched_MonitorNumber := Each_MonitorIndex EachMonitor_Width := (EachMonitor_RightCoord - EachMonitor_LeftCoord) EachMonitor_Height := (EachMonitor_BottomCoord - EachMonitor_TopCoord) EachMonitor_HalfWidth := (EachMonitor_Width / 2) EachMonitor_HalfHeight := (EachMonitor_Height / 2) EachMonitor_Center_XPos := EachMonitor_LeftCoord + EachMonitor_HalfWidth EachMonitor_Center_YPos := EachMonitor_TopCoord + EachMonitor_HalfHeight If (Destination_Direction=="Maximized") { ; Set window state to "Maximized" Do_Maximized := True ; WinMove_XPos := EachMonitor_LeftCoord - 8 ; WinMove_YPos := EachMonitor_TopCoord - 8 ; WinMove_Width := EachMonitor_Width + 16 ; WinMove_Height := EachMonitor_Height + 16 WinMove_XPos := EachMonitor_LeftCoord WinMove_YPos := EachMonitor_TopCoord WinMove_Width := EachMonitor_HalfWidth WinMove_Height := EachMonitor_HalfHeight } Else If (Destination_Direction=="Restored") { ; Set window state to "Restored" ; ; HANDLED ABOVE ; } Else { Destination_Combined := ( Destination_Direction "-" Destination_Size ) If (Destination_Combined=="Left-Half") { ; Left Half WinMove_XPos := EachMonitor_LeftCoord WinMove_YPos := EachMonitor_TopCoord WinMove_Width := EachMonitor_HalfWidth WinMove_Height := EachMonitor_Height } Else If (Destination_Combined=="Right-Half") { ; Right Half WinMove_XPos := EachMonitor_Center_XPos WinMove_YPos := EachMonitor_TopCoord WinMove_Width := EachMonitor_HalfWidth WinMove_Height := EachMonitor_Height } Else If (Destination_Combined=="Top-Half") { ; Top Half WinMove_XPos := EachMonitor_LeftCoord WinMove_YPos := EachMonitor_TopCoord WinMove_Width := EachMonitor_Width WinMove_Height := EachMonitor_HalfHeight } Else If (Destination_Combined=="Bottom-Half") { ; Bottom Half WinMove_XPos := EachMonitor_LeftCoord WinMove_YPos := EachMonitor_Center_YPos WinMove_Width := EachMonitor_Width WinMove_Height := EachMonitor_HalfHeight } Else If ((Destination_Combined=="Top-Left") || (Destination_Combined=="Left-Top")) { ; Top-Left Quadrant WinMove_XPos := EachMonitor_LeftCoord WinMove_YPos := EachMonitor_TopCoord WinMove_Width := EachMonitor_HalfWidth WinMove_Height := EachMonitor_HalfHeight } Else If ((Destination_Combined=="Bottom-Left") || (Destination_Combined=="Left-Bottom")) { ; Bottom-Left Quadrant WinMove_XPos := EachMonitor_LeftCoord WinMove_YPos := EachMonitor_Center_YPos WinMove_Width := EachMonitor_HalfWidth WinMove_Height := EachMonitor_HalfHeight } Else If ((Destination_Combined=="Top-Right") || (Destination_Combined=="Right-Top")) { ; Top-Right Quadrant WinMove_XPos := EachMonitor_Center_XPos WinMove_YPos := EachMonitor_TopCoord WinMove_Width := EachMonitor_HalfWidth WinMove_Height := EachMonitor_HalfHeight } Else If ((Destination_Combined=="Bottom-Right") || (Destination_Combined=="Right-Bottom")) { ; Bottom-Right Quadrant WinMove_XPos := EachMonitor_Center_XPos WinMove_YPos := EachMonitor_Center_YPos WinMove_Width := EachMonitor_HalfWidth WinMove_Height := EachMonitor_HalfHeight } If ((WinMove_XPos!=-1) && (WinMove_YPos!=-1) && (WinMove_Width!=-1) && (WinMove_Height!=-1)) { ; ; Half/Quarter sized 'snap' windows --> Add strange proprietary pixel deltas which Windows uses for half-screen sized windows ; |--> May vary for specific applications... ; Win_ahk_exe := WinGetProcessName(WinTitle,WinText) If (Win_ahk_exe=="Code.exe") { ; VS Code ignores this offset, and is sized as-expected (using an offset of 0px) DeltaPixels := 0 } Else If (Win_ahk_exe=="firefox.exe") { ; Firefox uses a 5px base offset DeltaPixels := 5 } Else { ; Everything else seems to use a 5px base offset (default..?) DeltaPixels := 7 } WinMove_XPos := WinMove_XPos - DeltaPixels WinMove_YPos := WinMove_YPos - 0 WinMove_Width := WinMove_Width + ( 2 * DeltaPixels ) WinMove_Height := WinMove_Height + DeltaPixels } } Break } } ; If we are using the "Current" monitor as the destination, then set it respectively If ((RepeatHotkeyPress==False) && (InStr(Destination_MonitorNumber,"Current")==True)) { Destination_MonitorNumber := Win_Center_MonitorNumber } ; Check for error(s) If ((WinMove_XPos==-1) && (WinMove_YPos==-1) && (WinMove_Width==-1) && (WinMove_Height==-1)) { TooltipOutput := "" TooltipOutput := TooltipOutput " " "`n" TooltipOutput := TooltipOutput " Error - Invalid Argument(s) passed to function `"" A_ThisFunc "`"" " " "`n" TooltipOutput := TooltipOutput " |" "`n" TooltipOutput := TooltipOutput " |--> Call: " A_ThisFunc " ( `"" Destination_Direction "`" , `"" Destination_Size "`" , `"" Destination_MonitorNumber "`" , `"" WinTitle "`" , `"" WinText "`" )" " " "`n" TooltipOutput := TooltipOutput " |" "`n" TooltipOutput := TooltipOutput " |--> Script: " A_ScriptFullPath " " "`n" TooltipOutput := TooltipOutput " |" "`n" TooltipOutput := TooltipOutput " |--> Destination_MonitorNumber = [" Destination_MonitorNumber "]" " " "`n" TooltipOutput := TooltipOutput " |--> Destination_Direction = [" Destination_Direction "]" " " "`n" TooltipOutput := TooltipOutput " |--> Destination_Combined = [" Destination_Combined "]" " " "`n" TooltipOutput := TooltipOutput " |" "`n" TooltipOutput := TooltipOutput " |--> Win_Center_MonitorNumber = [" Win_Center_MonitorNumber "]" " " "`n" TooltipOutput := TooltipOutput " |--> Win_Center_XPos = [" Win_Center_XPos "]" " " "`n" TooltipOutput := TooltipOutput " |--> Win_Center_YPos = [" Win_Center_YPos "]" " " "`n" TooltipOutput := TooltipOutput " |" "`n" TooltipOutput := TooltipOutput " |--> WinMove_XPos = [" WinMove_XPos "]" " " "`n" TooltipOutput := TooltipOutput " |--> WinMove_YPos = [" WinMove_YPos "]" " " "`n" TooltipOutput := TooltipOutput " |--> WinMove_Width = [" WinMove_Width "]" " " "`n" TooltipOutput := TooltipOutput " |--> WinMove_Height = [" WinMove_Height "]" " " "`n" TooltipOutput := TooltipOutput " |" "`n" TooltipOutput := TooltipOutput " |--> Each_MonitorIndex = [" Each_MonitorIndex "]" " " "`n" TooltipOutput := TooltipOutput " |--> EachMonitor_Center_XPos = [" EachMonitor_Center_XPos "]" " " "`n" TooltipOutput := TooltipOutput " |--> EachMonitor_Center_YPos = [" EachMonitor_Center_YPos "]" " " "`n" TooltipOutput := TooltipOutput " |--> EachMonitor_Width = [" EachMonitor_Width "]" " " "`n" TooltipOutput := TooltipOutput " |--> EachMonitor_Height = [" EachMonitor_Height "]" " " "`n" TooltipOutput := TooltipOutput " |--> EachMonitor_HalfWidth = [" EachMonitor_HalfWidth "]" " " "`n" TooltipOutput := TooltipOutput " |--> EachMonitor_HalfHeight = [" EachMonitor_HalfHeight "]" " " "`n" TooltipOutput := TooltipOutput " " ShowToolTip(TooltipOutput,,,,60000) } Else { ; If (DebugMode == 1) { ; MsgBox("Matched_MonitorNumber=[ " Each_MonitorIndex " ]" "`n" "Do_Maximized=[ " Do_Maximized " ]" "`n" "WinMove ( " WinTitle " , " WinText " , , " WinMove_XPos " , " WinMove_YPos " , " WinMove_Width " , " WinMove_Height " )", A_ScriptName " - " A_ThisFunc) ; } If (Do_Maximized==False) { If (WinGetMinMax(WinTitle,WinText)==1) { ; Window is maximized --> Restore it (in preparation for resizing) WinRestore(WinTitle,WinText) } } ; If the window is where it already needs to be, then don't move it WinGetPos(&Win_XPos, &Win_YPos, &Win_Width, &Win_Height, WinTitle, WinText) If ((Win_XPos!=WinMove_XPos) || (Win_YPos!=WinMove_YPos) || (Win_Width!=WinMove_Width) || (Win_Height!=WinMove_Height)) { ; Move the window to specified x/y position and resize it to have specified width/height WinMove(WinMove_XPos, WinMove_YPos, WinMove_Width, WinMove_Height, WinTitle, WinText) ; Store the destination values for potential repeat hotkey presses to relatively position themselves off-of WinSnap_Prior_Destination_Direction := Destination_Direction WinSnap_Prior_Destination_MonitorNumber := Destination_MonitorNumber WinSnap_Prior_Destination_Size := Destination_Size ; Sleep 500 } If (Do_Maximized==True) { ; Maximize the Window on the target monitor If (WinGetMinMax(WinTitle,WinText)!=1) { ; Window is not maximized --> Maximize it WinMaximize(WinTitle,WinText) } } } } } Return } ; Variables to track the recent previous calls to function "WinSnap" WinSnap_Prior_Destination_Direction := "" WinSnap_Prior_Destination_MonitorNumber := 0 WinSnap_Prior_Destination_Size := "" ; ------------------------------ ; ; WinSnap_ToGrid ; | ; |--> Description: ; | Resizes and moves target window to a given position on a grid, applying an optional rowSpan & colSpan ; | ; |--> Parameters: ; | @param {integer} numRows The number of rows in the grid ; | @param {integer} numCols The number of columns in the grid ; | @param {integer} row The specific row within the grid to place the window ; | @param {integer} col The specific column within the grid to place the window ; | @param {integer} rowSpan The specific row within the grid to place the window ; | @param {integer} colSpan The specific column within the grid to place the window ; | ; |--> Citation: https://gist.github.com/AWMooreCO/1ef708055a11862ca9dc ; | ; |--> Ex) ; WinSnap_ToGrid("A",,1,4,1,1,1,1) ; Snap to the leftmost 1/4 (column) of screen (1 column of a 4-column layout) ; WinSnap_ToGrid("A",,1,4,1,1,1,2) ; Snap to the centermost 1/2 (column) of screen (2 columns of a 4-column layout) ; WinSnap_ToGrid("A",,3,3,2,2) ; Snap to the centermost 1/9 (sector) of screen (1 column, 1 row of a 3-column, 3-row layout) ; WinSnap_ToGrid(WinTitle:="A", WinText:="", numRows:=1, numCols:=1, row:=1, col:=1, rowSpan:=1, colSpan:=1) { Win_hwnd := ("ahk_id " WinGetID(WinTitle)) ; Determine which monitor target window is located on Win_MonitorIndex := WinGet_MonitorIndex(Win_hwnd) ; Get target monitor's dimensions on-screen MonitorGetWorkArea(Win_MonitorIndex, &MonitorWorkArea_LeftCoord, &MonitorWorkArea_TopCoord, &MonitorWorkArea_RightCoord, &MonitorWorkArea_BottomCoord) ; Get target window's dimensions on-screen WinGetPos(&Win_XPos, &Win_YPos, &Win_Width, &Win_Height, Win_hwnd) ; If Window is Maximized or Minimized, restore it If ((WinGetMinMax(Win_hwnd)==1) || (WinGetMinMax(Win_hwnd)==-1) || ((WinGetMinMax(Win_hwnd)!=1) && (Win_Width < -8) && (Win_Height < -8))) { ; Note: Window [xpos,ypos] can sometimes be set to [-8,-8] when maximized WinRestore(Win_hwnd) } ; Determine the ColWidth and RowHeight of a grid cell RowHeight := ((MonitorWorkArea_BottomCoord - MonitorWorkArea_TopCoord) / numRows) ColWidth := ((MonitorWorkArea_RightCoord - MonitorWorkArea_LeftCoord) / numCols) ; Determine the x and y offsets WinMove_XPos := Floor(MonitorWorkArea_LeftCoord + (col - 1) * ColWidth) WinMove_YPos := Floor(MonitorWorkArea_TopCoord + (row - 1) * RowHeight) ; Apply rowSpan/colSpan after determining offsets WinMove_Width := Floor(ColWidth * colSpan) WinMove_Height := Floor(RowHeight * rowSpan) ; Move and resize the active window WinMove(WinMove_XPos, WinMove_YPos, WinMove_Width, WinMove_Height, Win_hwnd) Return } ; ------------------------------ ; ; Win_ToggleRestoreMaximize ; |--> Toggle target window between "Maximized" and "Non-Maximized" (or "Restored") states ; Win_ToggleRestoreMaximize(WinTitle:="A") { global DebugMode Win_MinMaxState := WinGetMinMax(WinTitle) DebugString := "Win_MinMaxState=[ " Win_MinMaxState " ]" If (Win_MinMaxState = "") { ; ??? Window-state not pulled as-intended WinMaximize(WinTitle) DebugString := DebugString "`n" " |--> Do WinMaximize" } Else { If (Win_MinMaxState == 0) { ; 0: The window is restored (neither minimized nor maximized) - do WinMaximize to maximize it WinMaximize(WinTitle) DebugString := DebugString "`n" " |--> Do WinMaximize" } Else If (Win_MinMaxState == -1) { ; -1: The window is minimized - do WinRestore to unminimize it WinRestore(WinTitle) DebugString := DebugString "`n" " |--> Do WinRestore" } Else If (Win_MinMaxState == 1) { ; 1: The window is maximized - do WinRestore to unmaximize it WinRestore(WinTitle) DebugString := DebugString "`n" " |--> Do WinRestore" } Else { ; Fallthrough-catch WinMaximize(WinTitle) DebugString := DebugString "`n" " |--> Do WinMaximize" } } If (DebugMode == 1) { TrayTip "AHK", DebugString ; Toast Notification } Return } ; ------------------------------ ; ; Xbox_ExportCaptures ; |--> Win10 download & delete Game Clips / Screenshots via "Xbox Console Companion" Win10 App ; Xbox_ExportCaptures() { global DebugMode CoordMode "Mouse", "Screen" SetControlDelay -1 SetDefaultMouseSpeed 0 SetKeyDelay 0, -1 SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle AwaitModifierKeyup() ; Wait until all modifier keys are released ; ------------------------------ ; ; Runtime Options ; MaxFilesToDownload := 0 ; 0 = Unlimited ; MaxFilesToDownload := 2 Download_GameClips := 0 Download_Screenshots := 0 ; ------------------------------ ; Download Game clips? A_MsgBoxResult := MsgBox("Download Game Clips?", A_ScriptName " - " A_ThisFunc,3) If (A_MsgBoxResult = "Yes") { Download_GameClips := 1 } ; Download Screenshots ? If (A_MsgBoxResult != "Cancel") { A_MsgBoxResult := MsgBox("Download Screenshots?", A_ScriptName " - " A_ThisFunc,3) If (A_MsgBoxResult = "Yes") { Download_Screenshots := 1 } } ; ------------------------------ If ((Download_GameClips != 0) || (Download_Screenshots != 0)) { WinTitle := "Xbox Console Companion" ; Win_ahk_id := WinGetID("A") Win_ahk_id := WinGetID(WinTitle) Win_hwnd := ("ahk_id " Win_ahk_id) WinTitle := WinGetTitle(Win_hwnd) Win_ahk_class := WinGetClass(Win_hwnd) Win_ahk_exe := WinGetProcessName(Win_hwnd) Win_ahk_pid := WinGetPID(Win_hwnd) Win_size_state := WinGet_SizeState(Win_hwnd) ; Win10_ahk_id := WinGet_ahk_id(WinTitle) Win10_ahk_id := WinGet_ahk_id(Win_hwnd) Win10_title := WinGetTitle("ahk_id " Win10_ahk_id) Win10_ahk_class := WinGetClass("ahk_id " Win10_ahk_id) Win10_ahk_pid := WinGetPID("ahk_id " Win10_ahk_id) Win10_ahk_exe := WinGetProcessName("ahk_id " Win10_ahk_id) Win_MinMaxState := WinGetMinMax(Win_hwnd) Tooltip_Header := A_ThisFunc "`n" "----------" TickCount_RuntimeStart := A_TickCount Count_FilesProcessed := 0 Color_Buffering_GameClips := "0x2E2E2E" Color_Buffering_Screenshots := "0x171717" Color_DL_Button_NotDownloading := "0x171717" Color_DL_Button_Downloading := "0x595758" Color_Loaded_CapturesPage := "0xFFFFFF" Color_Loaded_OnXboxLiveTab := "0xFFFFFF" Loop 2 { If (A_Index == 1) { Download_MediaType := "Game clips" ; Download "Game clips" } Else { Download_MediaType := "Screenshots" ; Download "Screenshots" } If ((Download_MediaType == "Game clips") && (Download_GameClips == 0)) { ; ; If option "Download_GameClips" is disabled (set to 0), skip downloading/deleting Xbox Live Game clips ; Continue } Else If ((Download_MediaType == "Screenshots") && (Download_Screenshots == 0)) { ; ; If option "Download_Screenshots" is disabled (set to 0), skip downloading/deleting Xbox Live Screenshots ; Continue } Else { Tooltip_StartupJobs := Tooltip_Header If (Download_MediaType == "Game clips") { WaitDuration_MediaType := 1.5 } Else { WaitDuration_MediaType := 1.0 } Loop 4 { Tooltip_NewStats := "" If (A_Index == 1) { ; ------------------------------ ; ; Resizing 'Xbox Console Companion' Window ; Tooltip_NewStats := ( "Prepping Xbox window..." ) ToolTip ( Tooltip_StartupJobs "`n" Tooltip_NewStats ), 1, 1 WinActivate(Win_hwnd) Sleep 500 If (Win_size_state != "restored") { WinActivate(Win_hwnd) WinRestore(Win_hwnd) Sleep 1000 } WinActivate(Win_hwnd) ; ; Move the window to specified x/y position and resize it to have specified width/height ; WinMove(-7,0,1280,800,WinTitle) Sleep 500 Tooltip_StartupJobs := ( Tooltip_StartupJobs "`n" Tooltip_NewStats " Done" ) Sleep 500 } Else If (A_Index == 2) { ; ------------------------------ ; ; Loading 'Captures' tab ... ; TickCount_LoadCaptures := A_TickCount WinActivate(Win_hwnd) MouseClick "Left", 23, 314 ; Load 'Captures' tab (left-panel) Sleep 500 Loop { Sleep 100 WaitDuration_Seconds := Round(((A_TickCount-TickCount_LoadCaptures)/1000), 1) Tooltip_NewStats := ( "Loading 'Captures' (tab): " WaitDuration_Seconds "s ..." ) ToolTip ( Tooltip_StartupJobs "`n" Tooltip_NewStats ), 1, 1 If ( WaitDuration_Seconds > 0.5 ) { ; Wait a minimum short-duration per download WinActivate(Win_hwnd) ; ; Check the color of each pixel in a 2-D horizontal line which passes over the "On This PC" and "On Xbox Live" tab name texts ; |--> Keep checking until a white color (0xFFFFFF) is found somewhere along said coordinate line (which denotes the page has loaded) ; If (PixelSearch(&Px, &Py, 61, 140, 280, 140, Color_Loaded_CapturesPage, 0)) { Tooltip_StartupJobs := ( Tooltip_StartupJobs "`n" Tooltip_NewStats " Done" ) ToolTip ( Tooltip_StartupJobs ), 1, 1 Sleep 500 Break } Else { Continue } } } } Else If (A_Index == 3) { ; ------------------------------ ; ; Loading 'On Xbox Live' (tab)... ; TickCount_LoadXboxLive := A_TickCount WinActivate(Win_hwnd) MouseClick "Left", 220, 138 ; Load 'On Xbox Live' tab (top-option within 'Captures') Sleep 500 Loop { Sleep 100 WaitDuration_Seconds := Round(((A_TickCount-TickCount_LoadXboxLive)/1000), 1) Tooltip_NewStats := ( "Loading 'On Xbox Live' (tab): " WaitDuration_Seconds "s ..." ) ToolTip ( Tooltip_StartupJobs "`n" Tooltip_NewStats ), 1, 1 If ( WaitDuration_Seconds > 0.5 ) { ; Wait a minimum short-duration per download ; ; Check the color of each pixel in a 2-D horizontal line which passes over the "By date" and "Everything" dropdown texts ; |--> Keep checking until a white color (0xFFFFFF) is found somewhere along said coordinate line (which denotes the tab has loaded) ; WinActivate(Win_hwnd) If ( (PixelSearch(&Px, &Py, 61, 180, 280, 180, Color_Loaded_OnXboxLiveTab, 0)) || (WaitDuration_Seconds > 20) ) { Tooltip_StartupJobs := ( Tooltip_StartupJobs "`n" Tooltip_NewStats " Done" ) ToolTip ( Tooltip_StartupJobs ), 1, 1 Sleep 500 Break } Else { Continue } } } } Else If (A_Index == 4) { If (Download_MediaType == "Game clips") { ; ------------------------------ ; ; Loading 'Game clips' (filter)... ; Tooltip_NewStats := ( "Showing 'Game clips' (filter) ..." ) ToolTip ( Tooltip_StartupJobs "`n" Tooltip_NewStats ), 1, 1 WinActivate(Win_hwnd) MouseClick "Left", 221, 181 ; Show 'Game clips', only - (under the "Everything v" dropdown/filter - second option from the top) Sleep 500 WinActivate(Win_hwnd) Send "{Up}" Sleep 250 WinActivate(Win_hwnd) Send "{Up}" Sleep 250 WinActivate(Win_hwnd) Send "{Down}" Sleep 250 WinActivate(Win_hwnd) Send "{Enter}" Tooltip_StartupJobs := ( Tooltip_StartupJobs "`n" Tooltip_NewStats " Done" ) ToolTip ( Tooltip_StartupJobs ), 1, 1 Sleep 1000 } Else { ; ------------------------------ ; ; Loading 'Screenshots' (filter)... ; Tooltip_NewStats := ( "Showing 'Screenshots' (filter) ..." ) ToolTip ( Tooltip_StartupJobs "`n" Tooltip_NewStats ), 1, 1 WinActivate(Win_hwnd) MouseClick "Left", 221, 181 ; Show 'Screeshots', only - (under the "Everything v" dropdown/filter - bottom option) Sleep 500 WinActivate(Win_hwnd) Send "{Down}" Sleep 250 WinActivate(Win_hwnd) Send "{Down}" Sleep 250 WinActivate(Win_hwnd) Send "{Enter}" Tooltip_StartupJobs := ( Tooltip_StartupJobs "`n" Tooltip_NewStats " Done" ) ToolTip ( Tooltip_StartupJobs ), 1, 1 Sleep 1000 } } } Loop { Tooltip_EachFile_Stats := Tooltip_Header Tooltip_EachFile_Stats := Tooltip_EachFile_Stats "`n" "Net " Download_MediaType " processed: " Count_FilesProcessed Total_RuntimeDuration_Seconds := Round(((A_TickCount-TickCount_RuntimeStart)/1000), 1) Tooltip_EachFile_Stats := Tooltip_EachFile_Stats "`n" "Net Runtime Duration: " Total_RuntimeDuration_Seconds "s" MediaFile_Iteration := A_Index TickCount_FileExists := A_TickCount NextDownloadExists_Passed := 0 Buffer_Passed := 0 Download_Passed := 0 ; ------------------------------ ; ; Processing File #x / y ; If (MaxFilesToDownload > 0) { ; ; If option "MaxFilesToDownload" is set no a non-zero value, use its value as the maximum number of files to be downloaded ; Tooltip_EachFile_Stats := Tooltip_EachFile_Stats "`n" "Processing File # " MediaFile_Iteration "/" MaxFilesToDownload ":" If (MediaFile_Iteration >= MaxFilesToDownload) { Break } } Else { Tooltip_EachFile_Stats := Tooltip_EachFile_Stats "`n" "Processing File # " MediaFile_Iteration ":" } ; ------------------------------ ; ; File-check duration ... ; Loop { Sleep 100 WaitDuration_Seconds := Round(((A_TickCount-TickCount_FileExists)/1000), 1) Tooltip_NewStats := ( "File-check duration: " WaitDuration_Seconds "s ..." ) ToolTip ( Tooltip_EachFile_Stats "`n" Tooltip_NewStats ), 1, 1 If ( WaitDuration_Seconds > WaitDuration_MediaType ) { ; Wait a minimum short-duration per download WinActivate(Win_hwnd) ; ; Check the color of each pixel in a 2-D horizontal line which passes over the top Game clip / Screenshot's filename text ; |--> Keep checking until a white color (0xFFFFFF) is found somewhere along said coordinate line (which denotes the file line item has become selectable) ; If ( PixelSearch(&Px, &Py, 165, 280, 355, 280, 0xFFFFFF, 43) ) { NextDownloadExists_Passed := 1 Tooltip_EachFile_Stats := ( Tooltip_EachFile_Stats "`n" Tooltip_NewStats " Done" ) ToolTip ( Tooltip_EachFile_Stats ), 1, 1 Break } Else { If (WaitDuration_Seconds > 10) { ; ; Top row-item (filename) not found - Assume no more files exist ; NextDownloadExists_Passed := 0 Tooltip_EachFile_Stats := ( Tooltip_EachFile_Stats "`n" Tooltip_NewStats " Not found" ) ToolTip ( Tooltip_EachFile_Stats ), 1, 1 Break } Else { Continue } } } } ; ------------------------------ ; ; Buffering... ; If ( NextDownloadExists_Passed == 1 ) { TickCount_StartBuffer := A_TickCount Loop { Sleep 100 WaitDuration_Seconds := Round(((A_TickCount-TickCount_StartBuffer)/1000), 1) Tooltip_NewStats := ( "Buffer duration: " WaitDuration_Seconds "s ..." ) ToolTip ( Tooltip_EachFile_Stats "`n" Tooltip_NewStats ), 1, 1 If ( WaitDuration_Seconds > WaitDuration_MediaType ) { ; Wait a minimum short-duration per download ; Check the thumbnail's 4 corners to see if they all match the gray buffering (loading) overlay's color WinActivate(Win_hwnd) Color_Thumbnail_BotLeft := PixelGetColor(425, 470) Color_Thumbnail_TopLeft := PixelGetColor(425, 215) Color_Thumbnail_TopRight := PixelGetColor(900, 215) Color_Thumbnail_BotRight := PixelGetColor(900, 470) If ((Color_Thumbnail_BotLeft == Color_Buffering_GameClips) && (Color_Thumbnail_TopLeft == Color_Buffering_GameClips) && (Color_Thumbnail_TopRight == Color_Buffering_GameClips) && (Color_Thumbnail_BotRight == Color_Buffering_GameClips)) { Continue ; Still Buffering (Game clip) } Else If ((Color_Thumbnail_BotLeft == Color_Buffering_Screenshots) && (Color_Thumbnail_TopLeft == Color_Buffering_Screenshots) && (Color_Thumbnail_TopRight == Color_Buffering_Screenshots) && (Color_Thumbnail_BotRight == Color_Buffering_Screenshots)) { Continue ; Still Buffering (Screenshot) } Else { Buffer_Passed := 1 Tooltip_EachFile_Stats := ( Tooltip_EachFile_Stats "`n" Tooltip_NewStats " Done" ) ToolTip ( Tooltip_EachFile_Stats ), 1, 1 Sleep 1000 Break } } } ; ------------------------------ ; ; Downloading... ; TickCount_StartDownload := A_TickCount DownloadBtn_XPos_LeftInterior := 418 ; Same xpos for [ Game clips ] & [ Screenshots ] DownloadBtn_XPos_Center := 542 ; Same xpos for [ Game clips ] & [ Screenshots ] If (Download_MediaType == "Game clips") { DownloadBtn_YPos_Center := 772 ; Game clips } Else { DownloadBtn_YPos_Center := 730 ; Screenshots } Loop { If (A_Index == 1) { WinActivate(Win_hwnd) MouseClick "Left", DownloadBtn_XPos_Center, DownloadBtn_YPos_Center ; Click "Download" on currently-selected file } Sleep 100 WaitDuration_Seconds := Round(((A_TickCount-TickCount_StartDownload)/1000), 1) Tooltip_NewStats := ( "Download duration: " WaitDuration_Seconds "s ..." ) ToolTip ( Tooltip_EachFile_Stats "`n" Tooltip_NewStats ), 1, 1 If ( WaitDuration_Seconds > WaitDuration_MediaType ) { ; Wait a minimum short-duration per download MouseMove 0, 0 ; Check the leftmost side of the "Download" button to see if it is still downloading the current file (it turns a lighter gray, 0x595758, while downloading, compared to its base of 0x171717) WinActivate(Win_hwnd) Color_DL_Button_LeftSide := PixelGetColor(DownloadBtn_XPos_LeftInterior, DownloadBtn_YPos_Center) If (Color_DL_Button_LeftSide == Color_DL_Button_NotDownloading) { Download_Passed := 1 Tooltip_EachFile_Stats := ( Tooltip_EachFile_Stats "`n" Tooltip_NewStats " Done" ) ToolTip ( Tooltip_EachFile_Stats ), 1, 1 Sleep 1500 Break } } } } ; ------------------------------ ; ; Deleting... ; If ((NextDownloadExists_Passed == 1) && (Buffer_Passed == 1) && (Download_Passed == 1)) { DeleteBtn_XPos_TrashCan := 853 ; Same xpos for [ Game clips ] & [ Screenshots ] If (Download_MediaType == "Game clips") { DeleteBtn_YPos_Center := 731 ; Game clips } Else { DeleteBtn_YPos_Center := 618 ; Screenshots } Tooltip_NewStats := "Deleting ..." ToolTip ( Tooltip_EachFile_Stats "`n" Tooltip_NewStats ), 1, 1 WinActivate(Win_hwnd) MouseClick "Left", DeleteBtn_XPos_TrashCan, DeleteBtn_YPos_Center ; Click "Delete" once download has finished Sleep 1000 Tooltip_NewStats := Tooltip_NewStats " Confirming ..." ToolTip ( Tooltip_EachFile_Stats "`n" Tooltip_NewStats ), 1, 1 WinActivate(Win_hwnd) MouseClick "Left", 519, 449 ; Confirm file-deletion (via "OK" button on popup) Sleep 500 Tooltip_EachFile_Stats := ( Tooltip_EachFile_Stats "`n" Tooltip_NewStats " Done" ) ToolTip ( Tooltip_EachFile_Stats ), 1, 1 Sleep 1500 Count_FilesProcessed := Count_FilesProcessed + 1 } Else { Tooltip_NewStats := "Info: " If (NextDownloadExists_Passed != 1) { Tooltip_NewStats := Tooltip_NewStats "`n" "All " Download_MediaType " have been downloaded" } Else { If (Buffer_Passed != 1) { Tooltip_NewStats := Tooltip_NewStats "`n" "Error: Buffering unable to complete" } If (Download_Passed != 1) { Tooltip_NewStats := Tooltip_NewStats "`n" "Error: Download unable to complete" } } Tooltip_EachFile_Stats := ( Tooltip_EachFile_Stats "`n" Tooltip_NewStats ) ToolTip ( Tooltip_EachFile_Stats ), 1, 1 Sleep 2500 Break } } ; ------------------------------ ; ; Net Files Processed && Net Runtime Duration ; Tooltip_Closer_Stats := Tooltip_Header Tooltip_Closer_Stats := Tooltip_EachFile_Stats "`n" "Net Files Processed: " Count_FilesProcessed Total_RuntimeDuration_Seconds := Round(((A_TickCount-TickCount_RuntimeStart)/1000), 1) Tooltip_Closer_Stats := Tooltip_EachFile_Stats "`n" "Net Runtime Duration: " Total_RuntimeDuration_Seconds "s" ToolTip ( Tooltip_Closer_Stats ), 1, 1 Sleep 2000 } } ; ------------------------------ ; ; Count & timestamp files in the output directory then show the output directory - https://www.autohotkey.com/docs/v2/lib/LoopFiles.htm ; Count_FilesInOutputDir := 0 Fullpath_Output_XboxCaptures := ( EnvGet("USERPROFILE") "\Videos\Captures" ) Loop Files (Fullpath_Output_XboxCaptures "\*") { ; Exclude files matching a given regex pattern - https://www.autohotkey.com/docs/v2/lib/RegExMatch.htm RegexPattern_Exclude := "(.*).(ini|lnk)$" If (!RegExMatch(A_LoopFileFullPath, RegexPattern_Exclude)) { Count_FilesInOutputDir++ } } ; Even if no files were processed, check to see if there are any files to rename If ((Count_FilesProcessed > 0) || (Count_FilesInOutputDir > 0)) { ; Run the timestamping script (renames files to their basename plus their metadata created-on date) Tooltip_Closer_Stats := Tooltip_Closer_Stats "`n" "Count_FilesInOutputDir = [ " Count_FilesInOutputDir " ]" Tooltip_Closer_Stats := Tooltip_Closer_Stats "`n" "Running metadata-timestamper script..." ToolTip ( Tooltip_Closer_Stats ), 1, 1 Run("wsl.exe /bin/bash -c 'sync_cloud_infrastructure; bulk_rename_based_on_media_creation_date --dry-run 0;'") Sleep 2000 ; Open the output videos directory Tooltip_Closer_Stats := Tooltip_Closer_Stats "`n" "Opening output directory..." ToolTip ( Tooltip_Closer_Stats ), 1, 1 Run(Fullpath_Output_XboxCaptures) Sleep 2000 Tooltip_Closer_Stats := ( Tooltip_Closer_Stats "`n" "Runtime complete for '" Download_MediaType "'" ) ToolTip ( Tooltip_Closer_Stats ), 1, 1 Sleep 2000 } ClearTooltip(10000) } Return } ; ------------------------------ ; ; Youtube_EditDraft_Submit ; |--> Click "Edit Draft" then "Next"*3 then "Submit" to walk Youtube videos from "Draft" to live state ; |--> !!! MAKE SURE TO FILTER TO: "Visibility: Draft" !!! ; ; Youtube_EditDraft_Submit() { global DebugMode CoordMode "Mouse", "Screen" CoordMode "Pixel", "Screen" SetControlDelay -1 SetDefaultMouseSpeed 0 SetKeyDelay 0, -1 SetTitleMatchMode 2 ; Title must [ CONTAIN ] the given WinTitle AwaitModifierKeyup() ; Wait until all modifier keys are released WinTitle := "Channel content - YouTube Studio - Google Chrome" If (WinExist(WinTitle)) { WinActivate(WinTitle) Sleep 100 ; Make sure that the user enables filter [ "Visibility: Draft" ] before continuing with this script LF := "`n" Echo_Tooltip := "" Echo_Tooltip := Echo_Tooltip "YouTube Channel content" Echo_Tooltip := Echo_Tooltip LF A_Space Echo_Tooltip := Echo_Tooltip LF A_Space Echo_Tooltip := Echo_Tooltip LF A_Space A_Space A_Space "Please apply the following filter:" Echo_Tooltip := Echo_Tooltip LF A_Space Echo_Tooltip := Echo_Tooltip LF A_Space A_Space A_Space A_Space A_Space A_Space "Visibility: Draft" Echo_Tooltip := Echo_Tooltip LF A_Space Echo_Tooltip := Echo_Tooltip LF A_Space Echo_Tooltip := Echo_Tooltip LF A_Space A_Space A_Space "Has this filter been applied?" A_MsgBoxResult := MsgBox(Echo_Tooltip, A_ScriptName " - " A_ThisFunc,4) If (A_MsgBoxResult = "Yes") { Sleep 100 ; Move the window to specified x/y position and resize it to have specified width/height WinMove(-7,0,1734,1407,WinTitle) Loop { Tooltip_Header := "Chrome - Click 'Refresh'" ToolTip ( Tooltip_Header ), 1, 112 xpos := 94 ypos := 61 ControlClick ("x" xpos " y" ypos), WinTitle Sleep 2000 Tooltip_Header := "Youtube - Click 'Edit Draft'" ToolTip ( Tooltip_Header ), 1, 112 xpos := 1601 ypos := 414 xpos_rightedge := xpos + 20 Loop { Sleep 100 Color_xpos_ypos := PixelGetColor(xpos, ypos) PixelSearch_Blue1 := PixelSearch(&Px, &Py, xpos, ypos, xpos_rightedge, ypos, 0x065FD4, 50 ) PixelSearch_Blue2 := PixelSearch(&Px, &Py, xpos, ypos, xpos_rightedge, ypos, 0x196CD7, 50 ) Tooltip_Debug := ( Tooltip_Header "`n" ) Tooltip_Debug := ( Tooltip_Debug "Color_xpos_ypos=[" Color_xpos_ypos "]" "`n" ) Tooltip_Debug := ( Tooltip_Debug "PixelSearch_Blue1=[" PixelSearch_Blue1 "]" "`n" ) Tooltip_Debug := ( Tooltip_Debug "PixelSearch_Blue2=[" PixelSearch_Blue2 "]" "`n" ) ToolTip ( ( DebugMode == 1 ) ? ( Tooltip_Debug ) : ( Tooltip_Header ) ), 1, 1 If ( PixelSearch_Blue1 || PixelSearch_Blue2 ) { Break } } Sleep 250 ControlClick ("x" xpos " y" ypos), WinTitle Sleep 100 Tooltip_Header := "Youtube - Click 'Next' > 'Next' > 'Save'" ToolTip ( Tooltip_Header ), 1, 112 xpos := 1274 ypos := 1313 xpos_rightedge := xpos + 20 Loop 3 { Loop { Sleep 100 Color_xpos_ypos := PixelGetColor(xpos, ypos) PixelSearch_Blue1 := PixelSearch(&Px, &Py, xpos, ypos, xpos_rightedge, ypos, 0x065FD4, 50 ) PixelSearch_Blue2 := PixelSearch(&Px, &Py, xpos, ypos, xpos_rightedge, ypos, 0x196CD7, 50 ) Tooltip_Debug := ( Tooltip_Header "`n" ) Tooltip_Debug := ( Tooltip_Debug "Color_xpos_ypos=[" Color_xpos_ypos "]" "`n" ) Tooltip_Debug := ( Tooltip_Debug "PixelSearch_Blue1=[" PixelSearch_Blue1 "]" "`n" ) Tooltip_Debug := ( Tooltip_Debug "PixelSearch_Blue2=[" PixelSearch_Blue2 "]" "`n" ) ToolTip ( ( DebugMode == 1 ) ? ( Tooltip_Debug ) : ( Tooltip_Header ) ), 1, 1 If ( PixelSearch_Blue1 || PixelSearch_Blue2 ) { Break } } ControlClick ("x" xpos " y" ypos), WinTitle Sleep 100 } Sleep 100 Tooltip_Header := "Youtube - Click 'Close'" ToolTip ( Tooltip_Header ), 1, 112 xpos := 1056 ypos := 955 xpos_rightedge := xpos + 20 Loop { Sleep 100 Color_xpos_ypos := PixelGetColor(xpos, ypos) PixelSearch_Blue1 := PixelSearch(&Px, &Py, xpos, ypos, xpos_rightedge, ypos, 0x065FD4, 50 ) PixelSearch_Blue2 := PixelSearch(&Px, &Py, xpos, ypos, xpos_rightedge, ypos, 0x196CD7, 50 ) Tooltip_Debug := ( Tooltip_Header "`n" ) Tooltip_Debug := ( Tooltip_Debug "Color_xpos_ypos=[" Color_xpos_ypos "]" "`n" ) Tooltip_Debug := ( Tooltip_Debug "PixelSearch_Blue1=[" PixelSearch_Blue1 "]" "`n" ) Tooltip_Debug := ( Tooltip_Debug "PixelSearch_Blue2=[" PixelSearch_Blue2 "]" "`n" ) ToolTip ( ( DebugMode == 1 ) ? ( Tooltip_Debug ) : ( Tooltip_Header ) ), 1, 112 If ( PixelSearch_Blue1 || PixelSearch_Blue2 ) { Break } } ControlClick ("x" xpos " y" ypos), WinTitle Sleep 250 } } } ClearTooltip(10000) Return } ; ------------------------------ ; ; ClearSplashText ; |--> If called with a positive [ Period ], wait [ Period ] milliseconds, executes [ Label ], then repeats (until explicitly cancelled) ; |--> If called with a negative [ Period ], wait [ Period ] milliseconds, executes [ Label ], then returns ; ; ClearSplashText(Period) { ; SetTimer () => SplashTextOff(), (Period * -1) ; Return ; } ; ; ; ------------------------------------------------------------ ; ------------------------------------------------------------ ; --- DOCUMENTATION --- ; ------------------------------------------------------------ ; ------------------------------------------------------------ ; ; ------------------------------ ; ; *** To obtain the unique code(s) thrown by the keyboard per-keypress: ; ; // Create a separate AutoHotkey (.ahk) Script and paste these 3 lines into ; // it. Make sure to save it with a .ahk file extension: ; ; ----- BEGIN KEY-CODE LO ----- ; #InstallKeybdHook ; #Persistent ; KeyHistory ; ----- END OF FILE ----- ; ; // NOTE: After you've saved it, run it, and a command prompt (w/ white background) will ; // display the codes for any key pressed while it is running. ; ; // SC: Refer to the "SC" column to acquire the "scan code" of any keys pressed (string, length 3) ; // VK: Refer to the "VK" column to acquire the "virtual key code" of any keys pressed (string, length 2) ; // Key: Refer to the "Key" column to acquire the "Hotstring" of any keys pressed (string, length varies) ; ; // NOTE: If the above method fails, refer to: https://www.autohotkey.com/docs/v2/lib/GetKeyName.htm ; ; ------------------------------ ; ; *** TO DETERMINE THE COMMAND BEING SENT: ; SC029:: ; SplashTextOn, 250, 40, Debugging, Command Sent ; Sleep 500 ; RandomSleep := Random(1000,1500) ; Sleep RandomSleep ; SplashTextOff ; -- Remainder of your script ; ; ------------------------------ ; ; MouseClick("[Button]",[X_Coord],[Y_Coord],[ClickCount],[Speed],"[U|D]","[Relative]") ; ; PARAMS: ; [Button] = { Left, Right, Middle, X1, X2, WheelUp (or WU), WheelDown (or WD), WheelLeft (or WL), WheelRight (or WR) --- DEFAULTS TO LEFT IF OMITTED } ; [X_Coord] = { Screen Horizontal-Position to fire the click --- DEFAULTS TO CURRENT CURSOR X-COORDINATE } ; [Y_Coord] = { Screen Vertical-Position to fire the click --- DEFAULTS TO CURRENT CURSOR Y-COORDINATE } ; [ClickCount] = { Click this many times --- DEFAULTS TO 1 CLICK, IF OMITTED } ; [Speed] = { Movement speed of mouse across the screen - 0 is Instant --- DEFAULTS TO DEFAULT MOUSE MOVE SPEED SET BY [SetDefaultMouseSpeed Speed], OTHERWISE DEFAULTS TO 2 } ; [U|D] = { Only do a Click-Down (D) or Click-Up (U) click-event --- DEFAULTS A *DOWN* FOLLOWED BY AN *UP* EVENT, IF OMITTED} ; [Relative] = { If set to ("R"), the X & Y Coordinates will be treated as an offset to mouse's current position --- DEFAULTS TO NON-RELATIVE MOVEMENT, IF OMITTED } ; ; ------------------------------ ; ; MouseClickDrag WhichButton, X1, Y1, X2, Y2 [, Speed, Relative] ; ; ------------------------------ ; ; MouseMove X, Y [, Speed, Relative] ; ; ------------------------------ ; ; EXAMPLE_ControlClick() { ; ;;; ; ;;; ControlClick [, Control-or-Pos, WinTitle, WinText, WhichButton, ClickCount, Options, ExcludeTitle, ExcludeText] ; ;;; ; CoordMode "Mouse", "Screen" ; SetDefaultMouseSpeed 0 ; SetControlDelay -1 ; ; WinTitle := WinGetTitle("A") ; WinTitle := "NoxPlayer" ; xpos := (A_ScreenWidth - 20) ; ypos := 315 ; ControlClick ("x" xpos " y" ypos), WinTitle ; } ; ; ------------------------------ ; ; MsgBox has tons of options for confirmations on popups ( Manual @ https://www.autohotkey.com/docs/v2/lib/MsgBox.htm ) ; ...:: ; WinGetActiveStats, WinTitle, Width, Height, X, Y ; WinGetText, WinText, A ; A_MsgBoxResult := MsgBox("WinTitle: `n" WinTitle "`n`n" "Window Size: `n Width: (" Width ") Height: (" Height ") `n`nWindow Coordinates: `n X (" X ") Y (" Y ") `n`nSkip WinText?, A_ScriptName " - " A_ThisFunc,4) ; If (A_MsgBoxResult = "Yes") ; Return ; If (A_MsgBoxResult = "No") ; MsgBox(("WinText `n" WinText), A_ScriptName " - " A_ThisFunc) ; Return ; If (A_MsgBoxResult = "Timeout") ; Return ; Return ; ; ------------------------------ ; ; Menu, tray, add ; Creates a separator line. ; Menu, tray, add, "Lineage-2", MenuHandler ; Creates a new menu item. ; return43 ; ; MenuHandler: ; MsgBox(("You selected " A_ThisMenuItem " from menu " A_ThisMenu), A_ScriptName " - " A_ThisFunc) ; MsgBox(("A_TitleMatchMode[" A_TitleMatchMode "], A_TitleMatchModeSpeed=[" A_TitleMatchModeSpeed "]", A_ScriptName " - " A_ThisFunc) ; Return ; ; Menu, FileMenu, Add, Script Icon, MenuHandler_FileMenu ; Menu, FileMenu, Add, Suspend Icon, MenuHandler_FileMenu ; Menu, FileMenu, Add, Pause Icon, MenuHandler_FileMenu ; Menu, FileMenu, Icon, Script Icon, A_AhkPath, 2 ;Use the 2nd icon group from the file ; Menu, FileMenu, Icon, Suspend Icon, A_AhkPath, -206 ;Use icon with resource identifier 206 ; Menu, FileMenu, Icon, Pause Icon, A_AhkPath, -207 ;Use icon with resource identifier 207 ; Menu, MyMenuBar, Add, &File, :FileMenu ; Gui Menu, MyMenuBar ; Gui Add, Button, gExit, Exit This Example ; Gui Show ; MyGui.Show() ; MenuHandler_FileMenu: ; Return ; ; Exit: ; ExitApp ; ; Example: Using in-line if conditional(s) ; ; y := ( ( y = 8 ) ? ( 2008 ) : ( ( y = 9 ) ? ( 2009 ) : ( ( y = 0 ) ? ( 2010 ) : ( 2011 ) ) ) ) ; ; ------------------------------ ; ; Example: Compare two Strings' Displayed Character-Widths (Strlen doesn't have a whole lot to do with actual/displayed character-widths) ; ; CompareCharacterWidths() { ; LF := "`n" ; Echo1 := String = [ Chr(0x0061) ] Strlen = [ StrLen( Chr(0x0061) ) ] ; Echo2 := String = [ Chr(0x030a) ] Strlen = [ StrLen( Chr(0x030a) ) ] ; Echo_Tooltip := "" ; Echo_Tooltip := Echo_Tooltip LF " String=|" Chr(0x0061) "| StrLen=|" StrLen( Chr(0x0061) ) "|" ; Echo_Tooltip := Echo_Tooltip LF A_Space ; Echo_Tooltip := Echo_Tooltip LF " String=|" Chr(0x030a) "| StrLen=|" StrLen( Chr(0x030a) ) "|" ; Echo_Tooltip := Echo_Tooltip LF A_Space ; MsgBox(Echo_Tooltip, A_ScriptName " - " A_ThisFunc) ; Return ; } ; ------------------------------ ; ; ;;; Example: Custom Popups ; ; DemoCustomPopups() { ; ; SetTimer(CustomMsgBox_DemoCustomPopups,50) ; ; |--> Ensure that this callback script kills this SetTimer, otherwise it will keep running indefinitely ; ; A_MsgBoxResult := MsgBox("Popup MsgBox Question? or Statement!", A_ScriptName " - " A_ThisFunc,3) ; ; If (A_MsgBoxResult = "Yes") { ; TrayTip "AHK", "Leftmost Button Selected" ; Toast Notification ; } ; If (A_MsgBoxResult = "No") { ; TrayTip "AHK", "Center Button Selected" ; Toast Notification ; } ; If (A_MsgBoxResult = "Cancel") { ; TrayTip "AHK", "Rightmost Button Selected" ; Toast Notification ; } ; ; Return ; ; } ; ; CustomMsgBox_DemoCustomPopups() { ; If (WinExist(Popup_MsgBox_WindowTitle)) { ; Return ; Continue waiting for the "A_Clipboard or ClipboardAll" window to appear ; } ; SetTimer(A_ThisFunc,"Off") ; WinActivate ; ControlSetText "LEFT_BUTTON", "Button1" ; ControlSetText "CENTER_BUTTON", "Button2" ; ControlSetText "RIGHT_BUTTON", "Button3" ; Return ; } ; ; ; ------------------------------ ; ; Alphabetical Command and Function Index: https://www.autohotkey.com/docs/v2/lib/ ; |--> A_Clipboard: https://www.autohotkey.com/docs/v2/lib/A_Clipboard.htm ; |--> ControlGetText: https://www.autohotkey.com/docs/v2/lib/ControlGetText.htm ; |--> For Each: https://www.autohotkey.com/docs/v2/lib/For.htm ; |--> GetKeyState: https://www.autohotkey.com/docs/v2/lib/GetKeyState.htm ; |--> Hotkey: https://www.autohotkey.com/docs/v2/lib/Hotkey.htm#IfWin ; |--> KeyWait: https://www.autohotkey.com/docs/v2/lib/KeyWait.htm ; |--> Loop Parse: https://www.autohotkey.com/docs/v2/lib/LoopParse.htm ; |--> Menu: https://www.autohotkey.com/docs/v2/lib/Menu.htm ; |--> Ord: https://www.autohotkey.com/docs/v2/lib/Ord.htm ; |--> RegExReplace: https://www.autohotkey.com/docs/v2/lib/RegExReplace.htm ; |--> Run/RunWait: https://www.autohotkey.com/docs/v2/lib/Run.htm ; |--> SetTimer: https://www.autohotkey.com/docs/v2/lib/SetTimer.htm ; |--> SysGet: https://www.autohotkey.com/docs/v2/lib/SysGet.htm ; |--> SplitPath: https://www.autohotkey.com/docs/v2/lib/SplitPath.htm ; |--> SplitPath A_ScriptDir, &OutFileName, &OutDir, &OutExtension, &OutNameNoExt, &OutDrive ; ; ------------------------------ ; ; Variables and Expressions: https://www.autohotkey.com/docs/Variables.htm#BuiltIn ; | ; |--> Operators in Expressions - If (...) statements, including mathematical operators: https://www.autohotkey.com/docs/Variables.htm#Operators ; | ; |--> Arrays/Objects - Simple Arrays, e.g. "Indexed Arrays": https://www.autohotkey.com/docs/Objects.htm#Usage_Simple_Arrays ; | ; |--> Arrays/Objects - Associative Arrays, e.g. "Associative Arrays": https://www.autohotkey.com/docs/Objects.htm#Usage_Associative_Arrays ; | ; |--> Arrays/Objects - Pseudo-Arrays, e.g. "Variable Variables" (AVOID these to maintain syntax legibility & understandability): https://www.autohotkey.com/docs/misc/Arrays.htm#pseudo ; ; ------------------------------ ; ; List of Keys: https://www.autohotkey.com/docs/KeyList.htm ; | ; |--> Modifiers Keys: https://www.autohotkey.com/docs/KeyList.htm#modifier ; | ; |--> Multimedia Keys: https://www.autohotkey.com/docs/KeyList.htm#multimedia ; ; ------------------------------ ; ; Remapping Keys (Keyboard, Mouse and Joystick): https://www.autohotkey.com/docs/misc/Remap.htm ; ; ------------------------------ ; ; Hotkeys (Mouse, Joystick and Keyboard Shortcuts): https://www.autohotkey.com/docs/Hotkeys.htm#Symbols ; | ; |--> Hotkey Modifier Symbols: https://www.autohotkey.com/docs/Hotkeys.htm#Symbols ; ; # WinKey ; ; ! Alt ; ; + Shift ; ; ^ Ctrl ; ; NOTE: Most full-sized querty keyboards have two of each modifier key, one to the left-side of the spacebar, one to the right ; ; < Use the LEFT modifier key, e.g. <# (LWin), Use the RIGHT modifier key, e.g. ># (RWin), >! (RAlt), >+ (RShift), >^ (RCtrl) ; ; AppsKey (Application or Menu key, keycap symbol looks like a document w/ 3 lines) ; ; ------------------------------------------------------------ ; ; Citation(s) ; ; answers.microsoft.com | "Shortcut to sound control panel?" | https://answers.microsoft.com/en-us/windows/forum/windows_10-start/shortcut-to-sound-control-panel/32d5a6e7-fa92-4ca7-9033-cd38ba525542 ; ; docs.microsoft.com | "wscript | Microsoft Docs" | https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/wscript ; ; docs.microsoft.com | "WM_SYSCOMMAND message" | https://docs.microsoft.com/en-us/windows/win32/menurc/wm-syscommand ; ; gist.github.com | "Advanced Window Snap is a script for AutoHotKey that expands upon Windows built-in window-snapping hotkeys. · GitHub" | https://gist.github.com/AWMooreCO/1ef708055a11862ca9dc ; ; gist.github.com | "Media keys shortcuts for AutoHotkey · GitHub" | https://gist.github.com/mistic100/d3c0c1eb63fb7e4ee545 ; ; stackoverflow.com | "How can I set AutoHotKey's code to run only in chrome?" | https://stackoverflow.com/a/50180863 ; ; stackoverflow.com | "powershell - Setting screen resolution on Windows 10 - Stack Overflow" | https://stackoverflow.com/a/49375988 ; ; tools.ietf.org | "RFC 3339: Date and Time on the Internet: Timestamps" | https://tools.ietf.org/html/rfc3339 ; ; www.autohotkey.com | "Advanced Hotkey Features | AutoHotkey" | https://www.autohotkey.com/docs/HotkeyFeatures.htm#pass-through ; ; www.autohotkey.com | "CLSID List (Windows Class Identifiers)" | https://www.autohotkey.com/docs/misc/CLSID-List.htm <-- Example) ::{7007acc7-3202-11d1-aad2-00805fc1270e} ; ; www.autohotkey.com | "ControlGet List - Ask for Help - AutoHotkey Community" | https://www.autohotkey.com/board/topic/7649-controlget-list/ ; ; www.autohotkey.com | "Detect Current Windows Domain - Ask for Help - AutoHotkey Community" | https://www.autohotkey.com/board/topic/77940-detect-current-windows-domain/?p=495386 ; ; www.autohotkey.com | "determine if scaling is not 100% for monitor of a window, change PerMonitorSettings in registry, reflect change, verify - AutoHotkey Community" | https://www.autohotkey.com/boards/viewtopic.php?p=160615#p160615 ; ; www.autohotkey.com | "escape double quote - AutoHotkey Community" | https://www.autohotkey.com/boards/viewtopic.php?t=14082 ; ; www.autohotkey.com | "Get Current Micro/Nano seconds" | https://www.autohotkey.com/boards/viewtopic.php?p=126168#p126168 ; ; www.autohotkey.com | "Get Highest and Lowest value - Ask for Help - AutoHotkey Community" | https://www.autohotkey.com/board/topic/88376-get-highest-and-lowest-value/?p=560579 ; ; www.autohotkey.com | "Get the text content of a tool tip window - Ask for Help - AutoHotkey Community" | https://www.autohotkey.com/board/topic/53672-get-the-text-content-of-a-tool-tip-window/ ; ; www.autohotkey.com | "How to make AHK to type braces (curly brackets) - AutoHotkey Community" | https://www.autohotkey.com/boards/viewtopic.php?p=346714&sid=cf868beb68d8b6fefc7e3e69e7cdaeea#p346714 ; ; www.autohotkey.com | "How to paste multiline text - Ask for Help - AutoHotkey Community" | https://www.autohotkey.com/board/topic/65421-how-to-paste-multiline-text/ ; ; www.autohotkey.com | "How to quickly generate random strings? - AutoHotkey Community" | https://www.autohotkey.com/boards/viewtopic.php?t=76052 ; ; www.autohotkey.com | "How can I send a Windows toast notification? (TrayTip)" | https://www.autohotkey.com/boards/viewtopic.php?p=63507&sid=14b947240a145197c869c413824d8c50#p63507 ; ; www.autohotkey.com | "If Expression check to see if value is in Array" | https://www.autohotkey.com/boards/viewtopic.php?p=52627&sid=4e5a541af8d29ab16154c5a6dd379620#p52627 ; ; www.autohotkey.com | "ListView - G-Label Notifications (Primary)" | https://www.autohotkey.com/docs/v1/lib/ListView.htm#notify ; ; www.autohotkey.com | "Move window to half / quarter of current monitor - Scripts and Functions - AutoHotkey Community" | https://www.autohotkey.com/board/topic/108780-move-window-to-half-quarter-of-current-monitor/?p=648327 ; ; www.autohotkey.com | "Optimize StrLen, Unicode Version" | https://www.autohotkey.com/boards/viewtopic.php?p=106284#p106284 ; ; www.autohotkey.com | "Options and Styles for "Gui, Add, ListView, Options" | https://www.autohotkey.com/docs/v2/lib/ListView.htm#Options ; ; www.autohotkey.com | "PostMessage/SendMessage - #1: Press Win+O to turn off the monitor" | https://www.autohotkey.com/docs/v1/lib/PostMessage.htm#ExMonitorPower ; ; www.autohotkey.com | "PostMessage/SendMessage - #2: Start the user's chosen screen saver" | https://www.autohotkey.com/docs/v1/lib/PostMessage.htm#ExScreenSave ; ; www.autohotkey.com | "Run[Wait] Example #2: The following can be used to run a command and retrieve its output:" | https://www.autohotkey.com/docs/v1/lib/Run.htm#StdOut ; ; www.autohotkey.com | "SendInput %Clipboard% adds double linebreaks for Multiline - Ask for Help - AutoHotkey Community" | https://www.autohotkey.com/board/topic/88346-sendinput-clipboard-adds-double-linebreaks-for-multiline/ ; ; www.autohotkey.com | "Single line if statements" | https://www.autohotkey.com/board/topic/74001-single-line-if-statements/?p=470078 ; ; www.autohotkey.com | "Trim multiple lines" | https://www.autohotkey.com/boards/viewtopic.php?p=175097#p175097 ; ; www.autohotkey.com | "Windows 10? AutoHotkey Window Title, etc. - AutoHotkey Community" | https://www.autohotkey.com/boards/viewtopic.php?p=164262#p164262 ; ; www.autohotkey.com | "[HELP!] How to WinActivate without specifying window title? - Ask for Help - AutoHotkey Community" | https://www.autohotkey.com/board/topic/102763-help-how-to-winactivate-without-specifying-window-title/ ; ; www.reddit.com | "Possible to do SubStr() on multiple lines at once? : AutoHotkey" | https://www.reddit.com/r/AutoHotkey/comments/9f0qan/possible_to_do_substr_on_multiple_lines_at_once/ ; ; www.tenforums.com | "Resolution mismatch when using "Change the size of text..." - Windows 10 Forums" | https://www.tenforums.com/general-support/69742-resolution-mismatch-when-using-change-size-text.html#post869493 ; ; ------------------------------------------------------------