Last active
June 14, 2024 22:08
-
-
Save Lorenzo501/3fbf66c341153ae1b3a36deef685c9e1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This is a productivity enhancer plus some quality-of-life features that takes care of tedious tasks for you, saving time for what matters. Click on the tray icon to view hotkey info. | |
The compiled script can be found at: https://.. | |
You won't have to dl the libraries nor have AHK installed if you use the compiled script, it will automatically create an INI file in AppData\Local. | |
This non-compiled script has an embedded INI at the bottom, but you have to follow these two steps before you can run this script: | |
Download and unzip archive in "Lib" folder: https://github.com/thqby/winrt.ahk | |
Download raw file into "Lib" folder: https://github.com/Descolada/UIA-v2/blob/main/Lib/UIA.ahk | |
********** EIGHT-HOTKEY REMOTE ********** | |
Multi- and single-function hotkeys | |
TIP: change the `Run` setting to `Maximize` in the properties wnd of the Paint shortcut (b/c the snip feature can open Paint in a small wnd, which will be remembered by the OS). | |
And go to `Settings > System > Focus assist` to turn off all `Automatic rules`, so that TrayTip notification banners can also be shown on the desktop wnd for example | |
PAUSE = MEDIA CONTROL | |
Quick-press to play/pause, double-press to play next & triple-press to play previous | |
WIN+G = GOD MODE | |
Quick-press to trigger god mode (a destination runs depending on the active/existing context wnd). Double-press to use active context wnd for selectable destination folder. | |
Long-press to use active context wnd for existing folder wnd (necessary for special folders). Triple-press to use active context wnd for typeable non-folder destination | |
Win+R = SMART RUN | |
Quick-press to open Run dialog with preferred input & double-press or long-press to configure preferred input | |
Win+C = CALC/CTRL | |
Quick-press to open Calculator & double-press or long-press to display control list of active wnd in realtime | |
Win+S = SNIP | |
Start snip to clipboard | |
PrintScreen = SCREENSHOT+ | |
Quick-press to use native fn, double-press to save to desktop as well & long-press to take screenshot or keep previous on demand, saving either one to desktop | |
XButton* = MOUSE MENU | |
Pressed-down to show two-option menu & release to select | |
MButton = CONCEAL CARET | |
Toggle caret in Notepad, VS Code or Visual Studio | |
********** AUTOMATION FEATURES ********** | |
Open a network stream in VLC once you click "Copy Stream URL" in uTorrent | |
Open videos of a specific folder in fullscreen | |
Unhide taskbar in specific fullscreen windows | |
Scroll namespace to top when nearby on VS edit control show event | |
Auto-close the annoying WinRAR and Software Ideas Modeler notifications | |
********** WINDOWS' BUILT-IN HOTKEYS ********** | |
Some native hotkeys that you should know about | |
Win+D = Show desktop | |
Win+; = Emoji menu (e.g. you could insert a checkmark into a txt file) | |
MButton = Cursor on URL opens website in new tab, cursor on app in taskbar opens new instance & cursor on scrollable area of website activates auto-scroll | |
Alt+F4 = When on desktop it'll show the shutdown menu | |
Ctrl+F = Open find wnd (any text that you select beforehand gets inserted into the Find wnd automatically) | |
F3 = Quickly find and select text that was previously entered in the find wnd but without having to open the Find wnd again | |
Win+Alt+B = Toggle HDR | |
*/ | |
#Requires AutoHotkey 2.1-alpha.9 ; For _menu.Show(,, 0), struct and `?? false` | |
#SingleInstance Force | |
; To make hotkeys work when an admin window is active | |
if (!A_IsCompiled && !InStr(A_AhkPath, "_UIA.exe")) | |
{ | |
Run("*UIAccess " A_ScriptFullPath) | |
ExitApp() | |
} | |
#Include <winrt.ahk-main\windows> | |
#Include <UIA> | |
Initialize() | |
#!b:: | |
{ | |
; This will temporarily enable Game Bar and use its HDR toggle hotkey (Game Bar is initially disabled to replace its Win+G hotkey action w/ god mode) | |
if (!RegRead("HKEY_CURRENT_USER\System\GameConfigStore", "GameDVR_Enabled")) | |
{ | |
RegWrite(1, "REG_DWORD", "HKEY_CURRENT_USER\System\GameConfigStore", "GameDVR_Enabled") | |
RegWrite(1, "REG_DWORD", "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\GameDVR", "AppCaptureEnabled") | |
Sleep(500) | |
Send("#!b") | |
Sleep(500) | |
; Win+G opens Game Bar by default in Windows, so this will disable it (press Win and type "Game Bar settings" to enable it again) | |
RegWrite(0, "REG_DWORD", "HKEY_CURRENT_USER\System\GameConfigStore", "GameDVR_Enabled") | |
RegWrite(0, "REG_DWORD", "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\GameDVR", "AppCaptureEnabled") | |
} | |
} | |
*Pause::HandleHotkeyActivation(() => Send("{Media_Play_Pause}"), () => Send("{Media_Next}"), () => Send("{Media_Prev}")) | |
#g::HandleGodModeHotkeyActivation(() => ShellNavigate("shell:::{ED7BA470-8E54-465E-825C-99712043E01C}")) | |
#r:: | |
{ | |
pressStartTime := A_TickCount | |
loop | |
{ | |
Sleep(10) | |
; Win+R Quick-Press & Double-Press. Opens the run dialog or the configuration dialog for preferred input | |
if (!GetKeyState("#", "P") && !GetKeyState("r", "P")) | |
{ | |
HandleHotkeyActivation(StartSmartRun, ConfigurePreferredSmartRunInput) | |
return | |
} | |
; Win+R Long-Press. Opens the configuration dialog for preferred input | |
if (A_TickCount - pressStartTime > 750) | |
{ | |
ConfigurePreferredSmartRunInput() | |
KeyWait("LWin") ; Prevents the Win+R hotkey from triggering again while it's still pressed down | |
return | |
} | |
} | |
StartSmartRun() | |
{ | |
Run("shell:::{2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}") | |
WinWaitActive("Run ahk_class #32770") | |
ControlSetText(IniRead(iniPath, "PreferredSmartRunInput"), "Edit1") | |
Send("^a") | |
} | |
ConfigurePreferredSmartRunInput() | |
{ | |
preferredInput := InputBox("Enter the preferred input to show by default in the Run dialog. " | |
"Use %LocalAppData%—it’s the one most people tend to use.`n`n" | |
"Pro Tip: QuickAssist for remote assistance (built into Windows).", "Preferred Input - Smart Run", "w397 h174", "%LocalAppData%") | |
if (preferredInput.Result = "OK") | |
{ | |
IniDelete(iniPath, "PreferredSmartRunInput") | |
IniWriteExistingContextWindows(preferredInput.Value, "PreferredSmartRunInput") ; Writes it below the godmode sections | |
} | |
} | |
} | |
#c:: | |
{ | |
pressStartTime := A_TickCount | |
loop | |
{ | |
Sleep(10) | |
; Win+C Quick-Press & Double-Press. Opens calculator or toggles the realtime control list | |
if (!GetKeyState("#", "P") && !GetKeyState("c", "P")) | |
{ | |
HandleHotkeyActivation(() => Run("Calc"), ToggleRealtimeControlList) | |
return | |
} | |
; Win+C Long-Press. This toggles the realtime control list | |
if (A_TickCount - pressStartTime > 750) | |
{ | |
ToggleRealtimeControlList() | |
KeyWait("LWin") ; Prevents the Win+C hotkey from triggering again while it's still pressed down | |
return | |
} | |
} | |
ToggleRealtimeControlList() | |
{ | |
static shouldShowRealtimeControlList := false | |
SetTimer(WatchActiveWindow, (shouldShowRealtimeControlList := !shouldShowRealtimeControlList) ? 200 : 0) | |
if (!shouldShowRealtimeControlList) | |
Tooltip() | |
} | |
} | |
#s:: | |
{ | |
static hook := 0 | |
if (hook) | |
DllCall("UnhookWinEvent", "Ptr", hook) | |
Run("ms-screenclip:") | |
hook := HookEvent(EVENT_OBJECT_NAMECHANGE, HandleSnipWinEvent) | |
; This (re)sets the timer to 10 minutes | |
SetTimer(DismissSnipNotification, -600000) | |
HandleSnipWinEvent(hWinEventHook, event, hWnd, *) | |
{ | |
try | |
if (WinGetTitle(hWnd) = "Snip & Sketch" && WinGetClass(hWnd) = "ApplicationFrameWindow") | |
{ | |
DllCall("UnhookWinEvent", "Ptr", hWinEventHook) | |
hook := 0 | |
Sleep(100) | |
WinClose(hWnd) | |
; Save clipboard image to temp folder to see its width and height (overwrites any that might've been saved in the past) | |
RunWait("PowerShell.exe -Command `"$img = get-clipboard -format image; $img.save('" A_Temp "\latestSnip.jpg')`"",, "Hide") | |
imageSize := GetImageSize(A_Temp "\latestSnip.jpg") | |
; The extra space is for the paint toolset ofcourse | |
rawPaintWinWidth := imageSize.Width + 27 | |
rawPaintWinHeight := imageSize.Height + 192 | |
; Initializing the paint wnd size (without the minimum, it will hide the paint toolset and without the maximum, it will go beyond the screen boundaries) | |
paintWinWidth := (rawPaintWinWidth >= 379 ? (rawPaintWinWidth <= A_ScreenWidth ? rawPaintWinWidth : A_ScreenWidth) : 379) | |
paintWinHeight := (rawPaintWinHeight >= 251 ? (rawPaintWinHeight <= A_ScreenHeight ? rawPaintWinHeight : A_ScreenHeight) : 251) | |
Run("mspaint.exe",, "Min") | |
WinWait("ahk_exe mspaint.exe") | |
WinSetTransparent(0) | |
if (paintWinWidth = A_ScreenWidth && paintWinHeight = A_ScreenHeight) | |
{ | |
WinMaximize() | |
Send("^v^+x") ; Pastes the image from clipboard and removes any white space that might remain | |
} | |
else | |
{ | |
WinActivate() | |
Send("^v^+x") ; Pastes the image from clipboard and removes any white space that might remain | |
WinRestore() ; Unmaximize if it's maximized | |
WinMove((A_ScreenWidth / 2) - (paintWinWidth / 2), (A_ScreenHeight / 2) - (paintWinHeight / 2), paintWinWidth, paintWinHeight) ; Moves to center w/ new size | |
} | |
WinSetTransparent("Off") | |
} | |
} | |
GetImageSize(imagePath) | |
{ | |
static shellObj := ComObject("Shell.Application") | |
SplitPath(imagePath, &fileName, &fileDir) | |
folderObj := shellObj.Namespace(fileDir) | |
if (!folderItemObj := folderObj.ParseName(fileName)) | |
throw ValueError("The image path does not contain a (valid) file", -1, imagePath) | |
sizeArray := StrSplit(folderItemObj.ExtendedProperty("Dimensions"), " x ") | |
; Ad hoc object which allows you to see its properties with IntelliSense, usable w/ dot notation (image size w/o invisible characters) | |
return {Width: LTrim(sizeArray[1], Chr(8234)), Height: RTrim(sizeArray[2], Chr(8236))} | |
} | |
; This gets rid of the snip notification and its hook, if it still exists | |
DismissSnipNotification(*) | |
{ | |
if (hook) | |
{ | |
Windows.UI.Notifications.ToastNotificationManager.History.Clear("Microsoft.ScreenSketch_8wekyb3d8bbwe!App") | |
DllCall("UnhookWinEvent", "Ptr", hook) | |
hook := 0 | |
} | |
} | |
} | |
*PrintScreen:: | |
{ | |
static _ := OnClipboardChange(HandleClipChanged), hasScreenshotInClipboard := false, latestScreenshotTime := 0, dialogCountdown | |
pressStartTime := A_TickCount | |
shouldTakeNewScreenshot := 0 | |
loop | |
{ | |
Sleep(10) | |
if (!GetKeyState("PrintScreen", "P")) | |
{ | |
; PrintScreen Quick-Press. This takes a new screenshot | |
if (A_TickCount - latestScreenshotTime > 500) | |
{ | |
Send("{PrintScreen}") | |
latestScreenshotTime := A_TickCount | |
return | |
} | |
; PrintScreen Double-Press. This saves the screenshot of the first press to desktop | |
break | |
} | |
; PrintScreen Long-Press. This conditionally takes a new screenshot and saves a screenshot to desktop | |
if (A_TickCount - pressStartTime > 750) | |
{ | |
; To identify a long-press and to execute the default action for long-press | |
shouldTakeNewScreenshot := "OK" | |
break | |
} | |
} | |
; Auto-saving any existing screenshot that is currently in the clipboard on long-press, w/ the option to take a new screenshot instead | |
if (shouldTakeNewScreenshot := "OK" && hasScreenshotInClipboard) | |
{ | |
dialogCountdown := 8 | |
HookEvent(EVENT_OBJECT_CREATE, HandleDialogEvent) | |
shouldTakeNewScreenshot := MsgBox("Auto-saving in 8 seconds..", "Existing screenshot detected!", "0x40000 T8") ; Saves "OK" or "Timeout" | |
Sleep(200) ; Waiting for the dialog close animation to end | |
} | |
if (shouldTakeNewScreenshot = "OK") | |
Send("{PrintScreen}"), latestScreenshotTime := A_TickCount | |
RunWait("PowerShell.exe -Command `"$img = get-clipboard -format image; $img.save('" A_Desktop "\screenshot " A_Now ".jpg')`"",, "Hide") | |
TrayTip("Saved to desktop", "Screenshot taken", 0x34) | |
SetTimer(HideTrayTip, -4000) | |
KeyWait("PrintScreen") ; Prevents the printscreen hotkey from triggering again while it's still pressed down | |
HandleClipChanged(*) => hasScreenshotInClipboard := A_TickCount - latestScreenshotTime < 1000 | |
HandleDialogEvent(hWinEventHook, event, hWnd, *) | |
{ | |
try | |
if (WinGetClass(hWnd) = "#32770") | |
{ | |
DllCall("UnhookWinEvent", "Ptr", hWinEventHook) | |
DllCall("EnableMenuItem", "Ptr", DllCall("GetSystemMenu", "UInt", hWnd, "Int", 0), "UInt", SC_CLOSE := 0xF060, "UInt", MF_GRAYED := 0x00000001) | |
ControlMove(24,, 150,, "Button1", hWnd) | |
ControlSetText("Take New Screenshot", "Button1", hWnd) | |
SetTimer(() => UpdateDialogTime(hWnd), 1000) | |
} | |
UpdateDialogTime(hWnd) | |
{ | |
try ControlSetText("Auto-saving in " (--dialogCountdown) " seconds..", "Static1", hWnd) | |
catch | |
SetTimer(, 0) | |
} | |
} | |
} | |
XButton1:: | |
XButton2:: | |
{ | |
mouseHook.Start() | |
SystemCursor("Hide") | |
_menu := Menu() | |
_menu.Add("Open Google", OpenGoogle) | |
_menu.Add() ; seperator line | |
_menu.Add("Open Maps", OpenMaps) | |
_menu.Show(,, 0) | |
WinWait("ahk_class #32768 ahk_exe " A_AhkPath,, 5) | |
ControlSend("{Down}") ; Highlights the first menu item | |
MouseGetPos(, &startCursorY) | |
MFS_HILITE := 0x00000080 | |
latestEventYNonZeroIncrease := 0 ; Upcoming changes will be non-zero | |
latestEventYNonZeroChangeAmount := 0 ; Change(s) to the first unique value are unreliable hence skipping that value | |
loop | |
{ | |
Sleep(50) | |
if (!mouseHook.ProcHandle) | |
{ | |
try ControlSend("{Enter}") | |
return | |
} | |
try | |
{ | |
latestEventYIncreaseToProcess := startCursorY - latestEvent.Y | |
if (latestEventYIncreaseToProcess = 0) | |
continue | |
if (latestEventYIncreaseToProcess != latestEventYNonZeroIncrease) | |
{ | |
latestEventYNonZeroIncrease := latestEventYIncreaseToProcess | |
if (latestEventYNonZeroChangeAmount++ = 0) | |
continue | |
menuOption1 := GetMenuItemInfo(0) | |
menuOption2 := GetMenuItemInfo(2) ; Seperator line is index 1 | |
if (menuOption1.FState & MFS_HILITE) | |
{ | |
if (latestEventYNonZeroIncrease < 0) | |
ControlSend("{Down}") | |
} | |
else if (menuOption2.FState & MFS_HILITE) | |
{ | |
if (latestEventYNonZeroIncrease > 0) | |
ControlSend("{Up}") | |
} | |
} | |
} | |
} | |
GetMenuItemInfo(index) | |
{ | |
menuItem := MenuItemInfo() | |
menuItem.FMask := 0x00000001 ; MIIM_STATE | |
DllCall("GetMenuItemInfo", "Ptr", _menu.Handle, "UInt", index, "Int", true, "Ptr", menuItem) | |
return menuItem | |
} | |
} | |
XButton1 up:: | |
XButton2 up::mouseHook.Stop() | |
#HotIf (WinActive("ahk_exe notepad.exe") && MouseIsOver("ahk_exe notepad.exe")) | |
MButton::WinActivate("ahk_class Progman") | |
#HotIf (WinActive("Visual Studio Code - Welcome ahk_exe chrome.exe")) | |
MButton::Send("{Alt}") | |
#HotIf (WinActive("Microsoft Visual Studio ahk_exe devenv.exe")) | |
MButton:: | |
{ | |
if ((focusedElement.Selection ?? false) && UIA.CompareElements(focusedElement.Latest, UIA.GetFocusedElement())) | |
{ | |
; Moves caret back to where it was | |
try focusedElement.Selection.Select() | |
focusedElement.Latest := unset | |
focusedElement.Selection := unset | |
} | |
else | |
{ | |
; Moves caret to the start of the Edit control | |
focusedElement.Latest := UIA.GetFocusedElement() | |
focusedElement.Selection := focusedElement.Latest.SelectionRange | |
documentRange := focusedElement.Latest.DocumentRange | |
documentRange.MoveEndpointByUnit(UIA.TextPatternRangeEndpoint.End, UIA.TextUnit.Document, -1) | |
documentRange.Select() | |
} | |
} | |
; Necessary to make A_ThisHotkey become one of these when pressed (HandleVisualStudioTextSelectionChangedEvent requires this) | |
~LButton:: | |
~RButton::return | |
#HotIf WinActive("ahk_exe uTorrent.exe") | |
~RButton:: | |
{ | |
static status := 0 | |
if (!status) | |
OnClipboardChange(HandleClipChanged, status := 1) | |
HandleClipChanged(*) | |
{ | |
if (WinActive("ahk_exe uTorrent.exe")) | |
{ | |
networkStream.IsActive := true | |
HookEvent(EVENT_OBJECT_CREATE, HandleMediaPlayerEvent) | |
Send("+{F10}p{Enter}{Tab}"), Run(A_ProgramFiles "\VideoLAN\VLC\vlc.exe --fullscreen " A_Clipboard) | |
} | |
OnClipboardChange(HandleClipChanged, status := 0) | |
HandleMediaPlayerEvent(hWinEventHook, event, hWnd, *) | |
{ | |
static isBeingShownAfterTorrentStartsUnforced := false, WS_EX_LAYERED := 0x00080000 | |
try | |
if (WinGetTitle(hWnd) = "VLC" && !isBeingShownAfterTorrentStartsUnforced) | |
{ | |
isBeingShownAfterTorrentStartsUnforced := true | |
try WinSetTransparent(0, hWnd) | |
try WinSetEnabled(false, "ahk_exe uTorrent.exe") | |
HotIf(MouseIsOverUTorrent) | |
Hotkey("LButton", ShowNetworkStreamMenu, "On") | |
Hotkey("RButton", ShowNetworkStreamMenu, "On") | |
DllCall("UnhookWinEvent", "Ptr", hWinEventHook) | |
Sleep(-1) ; Discards queued events that might remain | |
WinExist(hWnd) | |
; Waiting until VLC is full screen | |
try | |
loop | |
if (!isBeingShownAfterTorrentStartsUnforced) | |
return | |
else if (WinGetExStyle() = WS_EX_LAYERED) | |
break | |
Hotkey("LButton", "Off") | |
Hotkey("RButton", "Off") | |
try WinSetEnabled(true, "ahk_exe uTorrent.exe") | |
try WinActivate("ahk_exe uTorrent.exe") | |
try Send((ListViewGetContent("Count Focused", "SysListView322", WinExist("ahk_exe uTorrent.exe")) = 1 ? "{Down}{Up}" : "{Up}{Down}") "+{F10}s") | |
try WinActivate(hWnd) | |
try WinSetTransparent("Off", hWnd) | |
networkStream.IsActive := isBeingShownAfterTorrentStartsUnforced := false | |
} | |
MouseIsOverUTorrent(*) => MouseIsOver("ahk_exe uTorrent.exe") | |
; This makes it possible to abort the network stream when the download speed is too low | |
ShowNetworkStreamMenu(*) | |
{ | |
_menu := Menu() | |
_menu.Add("Abort Network Stream", AbortNetworkStream) | |
_menu.Show() | |
AbortNetworkStream(*) | |
{ | |
Hotkey("LButton", "Off") | |
Hotkey("RButton", "Off") | |
WinClose("ahk_exe vlc.exe") | |
WinSetEnabled(true, "ahk_exe uTorrent.exe") | |
WinActivate("ahk_exe uTorrent.exe") | |
networkStream.IsActive := isBeingShownAfterTorrentStartsUnforced := false | |
} | |
} | |
} | |
} | |
} | |
;********** LIBRARY ********** | |
Initialize() | |
{ | |
TraySetIcon("netshell.dll", 151) | |
A_IconTip := "Time Saver" | |
A_CoordModeTooltip := "Screen" ; For the tooltip shown when the tray icon is clicked and also for the realtime controls tooltip | |
A_CoordModeMouse := "Screen" ; For the XButton hotkeys | |
A_WinDelay := -1 ; For the snip feature, HandleTabsOutlinerEvent and the two different HandleMediaPlayerEvent functions | |
A_KeyDelay := -1 ; For the XButton hotkeys (ControlSend) and for Send b/c it reverts to the Event SendMode when another AHK script installs a native low-level keyboard/mouse hook | |
A_KeyDuration := 1 ; For the XButton hotkeys | |
global EVENT_OBJECT_CREATE := 0x8000 | |
global EVENT_OBJECT_SHOW := 0x8002 | |
global EVENT_OBJECT_NAMECHANGE := 0x800C | |
global dialog := {ShouldProcessInput: true} ; Ad hoc object, usable w/ dot notation (no need for class) | |
global latestEvent := {Y: unset} ; Ad hoc object, usable w/ dot notation (no need for class) | |
global mouseHook := PointerDeviceHook("Move|LButton Down", HandleMouseMoveEvent(eventInfo) | |
{ | |
latestEvent.Y := eventInfo.Pt.Y ; This mouse movement will be used to highlight a menu item | |
return true ; Blocks both interfering mouse actions | |
}) | |
global networkStream := {IsActive: false} ; Ad hoc object, usable w/ dot notation (no need for class) | |
global focusedElement := {Latest: unset, Selection: unset} ; Ad hoc object, usable w/ dot notation (no need for class) | |
; Determine whether to use the embedded INI or an INI file within AppData\Local | |
if (A_IsCompiled) | |
{ | |
global iniPath := EnvGet("LocalAppData") "Time Saver Config.ini" | |
; Creates an INI file in AppData\Local | |
if (!FileExist(iniPath)) | |
{ | |
iniFileObj := FileOpen(iniPath, 0x101) | |
iniFileObj.Write("/* EXAMPLE`n" | |
"[_ActiveContextWindows]`n" | |
"ahk_exe Taskmgr.exe=services.msc`n" | |
"[_ExistingContextWindows]`n" | |
"[_ExistingContextWindowPriority1]`n" | |
"ahk_exe Unity.exe=C:\Users\loren\Documents\Unity projects\VOXEL WAR\Assets`n" | |
"[_ExistingContextWindowPriority2]`n" | |
"ahk_exe devenv.exe=C:\Users\loren\Documents\Unity projects\VOXEL WAR\Assets\Scripts`n" | |
"[_ExistingContextWindowPriority3]`n" | |
"ahk_exe notepad.exe=chrome.exe https://www.autohotkey.com/docs/alpha/ChangeLog.htm --start-maximized --disable-features=GlobalMediaControls`n" | |
"[_ExistingContextWindowPriority4]`n" | |
"Workspace - Visual Studio Code ahk_exe chrome.exe=chrome.exe https://www.autohotkey.com/docs/alpha/ChangeLog.htm --start-maximized --disable-features=GlobalMediaControls`n" | |
"[_PreferredSmartRunInput]`n" | |
"%LocalAppData%`n" | |
"[_FullscreenVideosContextFolder]`n" | |
"C:/Users/loren/Downloads/Movies and series`n" | |
"[_FullscreenWindowsUnhideTaskbar]`n" | |
"Sourcetree ahk_exe SourceTree.exe`n" | |
"Software Ideas Modeler ahk_exe SoftwareIdeasModeler.exe`n" | |
"*/`n`n" | |
"/* Edit these variables yourself if necessary (e.g. to make it more specific you can add the ahk_class, and for the opposite effect you can replace the ahk_exe with an " | |
"ahk_class or title)`n" | |
"[ActiveContextWindows]`n" | |
"[ExistingContextWindows]`n" | |
"[PreferredSmartRunInput]`n" | |
"[FullscreenVideosContextFolder]`n" | |
"[FullscreenWindowsUnhideTaskbar]`n" | |
"*/") | |
iniFileObj.Close() | |
} | |
} | |
else | |
global iniPath := A_ScriptFullPath | |
; Makes tray icon merely show hotkey info on click | |
A_TrayMenu.Delete() | |
OnMessage(0x404, HandleTrayIconClick) ; 0x404 = WM_USER msg number (which can be found w/ Microsoft Spy++) | |
; Win+G opens Game Bar by default in Windows, so this will disable it (press Win and type "Game Bar settings" to enable it again) | |
if (RegRead("HKEY_CURRENT_USER\System\GameConfigStore", "GameDVR_Enabled")) | |
{ | |
RegWrite(0, "REG_DWORD", "HKEY_CURRENT_USER\System\GameConfigStore", "GameDVR_Enabled") | |
RegWrite(0, "REG_DWORD", "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\GameDVR", "AppCaptureEnabled") | |
} | |
; Create [ActiveContextWindows] hotkeys with the INI | |
if (section := IniRead(iniPath, "ActiveContextWindows")) | |
{ | |
linesSplit := StrSplit(section, "`n") | |
for (iteratedLine in linesSplit) | |
((iteratedCommandData) => ( | |
HotIf((*) => WinActive(iteratedCommandData[1])), | |
Hotkey("#g", (*) => HandleGodModeHotkeyActivation(() => ShellNavigate(iteratedCommandData[2]))) | |
))(StrSplit(iteratedLine, "=")) | |
} | |
; Create [ExistingContextWindowPriority*] hotkeys with the INI | |
try | |
loop | |
((iteratedCommandData) => ( | |
HotIf((*) => WinExist(iteratedCommandData[1])), | |
Hotkey("#g", (*) => HandleGodModeHotkeyActivation(() => ShellNavigate(iteratedCommandData[2]))) | |
))(StrSplit(IniRead(iniPath, "ExistingContextWindowPriority" A_Index), "=")) | |
; It'll simulate native non-fullscreen taskbar functionality in the specific fullscreen windows that you set here. Unforcefully allowing the taskbar to be shown when the cursor reaches | |
; the deactivated taskbar line (it won't activate the taskbar, so the taskbar retains its slide animation). Useful for non-video fullscreen windows | |
if (fullscreenWindowsUnhideTaskbarSection := IniRead(iniPath, "FullscreenWindowsUnhideTaskbar")) | |
{ | |
linesSplit := StrSplit(StrSplit(fullscreenWindowsUnhideTaskbarSection, "`n*/")[1], "`n") | |
for (iteratedLine in linesSplit) | |
GroupAdd("FullscreenWindows", iteratedLine) | |
} | |
HookEvent(EVENT_OBJECT_CREATE, HandleMediaPlayerEvent) | |
HookEvent(EVENT_OBJECT_SHOW, HandleFullscreenWinEvent) | |
HookEvent(EVENT_OBJECT_SHOW, HandleNotificationEvent) | |
ManageVisualStudioEventHandlers() ; Has a loop, so keep this at the bottom | |
HandleTrayIconClick(wParam, lParam, *) | |
{ | |
static WM_LBUTTONUP := 0x0202, WM_RBUTTONUP := 0x0205 | |
if (lParam = WM_LBUTTONUP || lParam = WM_RBUTTONUP) | |
{ | |
Tooltip("𝗛𝗢𝗧𝗞𝗘𝗬 𝗜𝗡𝗙𝗢`n" | |
"━━━━━━━━━━━━━━━━━━━━━━━━━━`n" | |
"𝗣𝗔𝗨𝗦𝗘 = MEDIA CONTROL`n" | |
"𝗪𝗜𝗡+𝗚 = GOD MODE`n" | |
"𝗪𝗶𝗻+𝗥 = SMART RUN`n" | |
"𝗪𝗶𝗻+𝗖 = CALC/CTRL`n" | |
"𝗪𝗶𝗻+𝗦 = SNIP`n" | |
"𝗣𝗿𝗶𝗻𝘁𝗦𝗰𝗿𝗲𝗲𝗻 = SCREENSHOT+`n" | |
"𝗫𝗕𝘂𝘁𝘁𝗼𝗻* = MOUSE MENU`n" | |
"𝗠𝗕𝘂𝘁𝘁𝗼𝗻 = CONCEAL CARET") | |
HotIf() | |
Hotkey("~*LButton", (*) => (Tooltip(), Hotkey("~*LButton", "Off")), "On") | |
} | |
} | |
} | |
HandleGodModeHotkeyActivation(shellNavigateFnObj) | |
{ | |
pressStartTime := A_TickCount | |
; Holding Win+G pressed down for 2sec will attempt to add the active context window along with a File Explorer window to the INI | |
loop | |
{ | |
Sleep(10) | |
if (!GetKeyState("#", "P") && !GetKeyState("g", "P")) | |
break | |
if (A_TickCount - pressStartTime > 2000) | |
{ | |
detectedFolderPath := DetermineAnyShellFolderWinExist(&locationName) | |
if (detectedFolderPath = "") | |
MsgBox("To save a special File Explorer window such as the Control Panel or the Recycle Bin as the Win+G destination folder; " | |
"first activate it, then the Win+G context window and lastly keep Win+G pressed for 2 seconds. " | |
"For special destinations that are not inside File Explorer, then use the (advanced) input box by pressing the Win+G hotkey three times." | |
, "No Open Folder Detected! - God Mode", 0x40000) | |
else | |
{ | |
IniWriteSectionOfChoice(WinGetProcessName("A"), detectedFolderPath) | |
TrayTip("Destination:`t" locationName, "Added to INI - God Mode", 0x10) | |
SetTimer(HideTrayTip, -4000) | |
KeyWait("LWin") ; Prevents the godmode hotkey from triggering again while it's still pressed down | |
} | |
return | |
} | |
} | |
HandleHotkeyActivation(shellNavigateFnObj, DoublePressAction, TriplePressAction) | |
; This lets you select a destination folder | |
DoublePressAction() | |
{ | |
dialog.ShouldProcessInput := true | |
HotIf(MouseIsOverCancelButton) | |
Hotkey("~*LButton", (*) => dialog.ShouldProcessInput := false, "On") | |
HookEvent(EVENT_OBJECT_SHOW, HandleDialogEvent) | |
selectedFolder := FileSelect("D", "shell:MyComputerFolder\", "Select folder as destination to be reached with Win+G and context window") | |
Hotkey("~*LButton", (*) => dialog.ShouldProcessInput := false, "Off") | |
if (dialog.ShouldProcessInput) | |
{ | |
if (selectedFolder = "") | |
MsgBox("To save a special File Explorer window such as the Control Panel or the Recycle Bin as the Win+G destination folder; " | |
"first activate it, then the Win+G context window and lastly keep Win+G pressed for 2 seconds. " | |
"For special destinations that are not inside File Explorer, then use the (advanced) input box by pressing the Win+G hotkey three times." | |
, "No Folder Selection Detected! - God Mode", 0x40000) | |
else | |
IniWriteSectionOfChoice(WinGetProcessName("A"), selectedFolder) | |
} | |
; Disables dialog close button and makes window stay always-on-top (the user should use the cancel button instead b/c it won't show a msg when there is no folder selected) | |
HandleDialogEvent(hWinEventHook, event, hWnd, *) | |
{ | |
try | |
if (WinGetClass(hWnd) = "#32770") | |
{ | |
DllCall("UnhookWinEvent", "Ptr", hWinEventHook) | |
DllCall("EnableMenuItem", "Ptr", DllCall("GetSystemMenu", "UInt", hWnd, "Int", 0), "UInt", SC_CLOSE := 0xF060, "UInt", MF_GRAYED := 0x00000001) | |
WinSetAlwaysOnTop(true, hWnd) | |
} | |
} | |
MouseIsOverCancelButton(*) | |
{ | |
try return (MouseGetPos(,, &winId, &control), WinExist("ahk_class #32770 ahk_id " winId) && control = "Button2") | |
return false | |
} | |
} | |
; Advanced: input box for special destination (e.g. https://youtube.com to open YouTube in your browser or shell folder shortcuts such as explorer.exe shell:AppsFolder) | |
TriplePressAction() | |
{ | |
static _gui | |
if (IsSet(_gui)) | |
_gui.Show() | |
else | |
{ | |
_gui := Gui("+AlwaysOnTop -SysMenu", "Advanced Dialog - God Mode") | |
_gui.BackColor := "White" | |
_gui.AddText(, "`nEnter destination to be reached with Win+G and context window`n") | |
_gui.AddEdit("vDestination w340 h23") | |
_gui.AddButton("default w88 h26 x170 y107", "OK").OnEvent("Click", ProcessUserInput) | |
_gui.AddButton("w88 h26 x+7 y107", "Cancel").OnEvent("Click", (*) => _gui.Hide()) | |
_gui.AddProgress("w360 h61 x0 y89 cF0F0F0", 100) | |
_gui.AddButton("w88 h26 x170 y107", "OK") ; Gray bg overlay | |
_gui.AddButton("w88 h26 x+7 y107", "Cancel") ; Gray bg overlay | |
_gui.Show("w360 h150") | |
} | |
ProcessUserInput(*) | |
{ | |
if ((destination := _gui.Submit().Destination) != "") | |
IniWriteSectionOfChoice(WinGetProcessName("A"), destination) | |
} | |
} | |
IniWriteSectionOfChoice(contextWindow, destination) | |
{ | |
HookEvent(EVENT_OBJECT_CREATE, HandleDialogEvent) | |
shouldAddToSectionExistingContextWindowPriorityN := MsgBox("The following context window will be used:`t" contextWindow | |
"`n`nClick `"Exist`" if the context window has to exist before it may trigger on hotkey press. It will then have the next available priority, " | |
"so when there is more than one of these context windows existing, whichever has the highest priority gets triggered. Otherwise click " | |
"`"Active`" if the context window has to be active", "Context Window Condition - God Mode", 0x40004) | |
if (shouldAddToSectionExistingContextWindowPriorityN = "Yes") | |
{ | |
IniWriteExistingContextWindows("ahk_exe " contextWindow "=" destination) | |
HotIf((*) => WinExist("ahk_exe " contextWindow)) | |
} | |
else | |
{ | |
IniWrite(destination, iniPath, "ActiveContextWindows", "ahk_exe " contextWindow) | |
HotIf((*) => WinActive("ahk_exe " contextWindow)) | |
} | |
Hotkey("#g", (*) => HandleGodModeHotkeyActivation(() => ShellNavigate(destination))) | |
HandleDialogEvent(hWinEventHook, event, hWnd, *) | |
{ | |
try | |
if (WinGetClass(hWnd) = "#32770") | |
{ | |
DllCall("UnhookWinEvent", "Ptr", hWinEventHook) | |
ControlSetText("Exist", "Button1", hWnd) | |
ControlSetText("Active", "Button2", hWnd) | |
} | |
} | |
} | |
} | |
HideTrayTip() | |
{ | |
TrayTip() ; Attempt to hide it the normal way | |
if (SubStr(A_OSVersion, 1, 3) = "10.") | |
A_IconHidden := true, Sleep(200), A_IconHidden := false | |
} | |
; Detects single, double, and triple-presses of a hotkey. This allows a hotkey to perform a different operation depending on how many times you press it (convenient encapsulation only) | |
HandleHotkeyActivation(onePressActionFnObj, doublePressActionFnObj, triplePressActionFnObj?) | |
{ | |
static quickPressCount := 0, _executeMultiFunctionHotkeyAction | |
maxPressCount := IsSet(triplePressActionFnObj) ? 3 : 2 | |
if (quickPressCount + 1 < maxPressCount) | |
++quickPressCount | |
else | |
{ | |
quickPressCount := maxPressCount | |
return | |
} | |
if (!IsSet(_executeMultiFunctionHotkeyAction)) | |
_executeMultiFunctionHotkeyAction := ExecuteMultiFunctionHotkeyAction | |
SetTimer(_executeMultiFunctionHotkeyAction, -500) | |
ExecuteMultiFunctionHotkeyAction() | |
{ | |
switch (quickPressCount) | |
{ | |
case 1: onePressActionFnObj() | |
case 2: doublePressActionFnObj() | |
case 3: triplePressActionFnObj() | |
} | |
quickPressCount := 0 | |
_executeMultiFunctionHotkeyAction := unset | |
} | |
} | |
; This writes a new section below [ExistingContextWindows] or the latest [ExistingContextWindowPriorityN] if there are any (the new section can be either part of godmode or custom) | |
IniWriteExistingContextWindows(pairs, section?) | |
{ | |
loop | |
{ | |
try IniRead(iniPath, "ExistingContextWindowPriority" A_Index) | |
catch | |
{ | |
if (!IsSet(section)) | |
section := "[ExistingContextWindowPriority" A_Index "]" | |
IniWrite("`n" section "`n" pairs, iniPath, A_Index = 1 ? "ExistingContextWindows" : "ExistingContextWindowPriority" A_Index - 1, "[TemporarySection]") | |
IniDelete(iniPath, "TemporarySection") | |
break | |
} | |
} | |
} | |
ShellNavigate(path) | |
{ | |
static shellObj := ComObject("Shell.Application") | |
if | |
( | |
InStr(path, "chrome.exe") && | |
!ProcessExist("chrome.exe") && | |
(hasTabsOutlinerExtension := DirExist(EnvGet("LocalAppData") "\Google\Chrome\User Data\Default\Extensions\eggkanocgddhmamlbiijnphhppkpkmkl")) | |
) | |
HookEvent(EVENT_OBJECT_NAMECHANGE, HandleTabsOutlinerEvent) | |
; Shows search field after it runs an AHK site (the initial delay is in case such a chrome window exists already, to affect the new tab when it has fully loaded after the 2nd delay) | |
if (InStr(path, "autohotkey.com")) | |
{ | |
Run(path) | |
Sleep(500) | |
if (WinWaitActive("AutoHotkey v2",, 15)) | |
Sleep(500), Send("!s") | |
return | |
} | |
; The first scope can change the active explorer window location (prevents unnecessarily opening another explorer window), but it can run all kinds of stuff just like the Run command | |
if ((activeWinId := WinActive("ahk_class CabinetWClass")) || (activeWinId := WinActive("ahk_class ExploreWClass"))) | |
{ | |
for (iteratedWindow in shellObj.Windows) | |
if ((activeWindow := iteratedWindow).hWnd = activeWinId) | |
break | |
activeWindow.Navigate2(path) | |
} | |
else | |
Run(path) | |
} | |
DetermineAnyShellFolderWinExist(&locationName?) | |
{ | |
static shellObj := ComObject("Shell.Application") | |
if ((latestActiveWinId := WinExist("ahk_class CabinetWClass")) || (latestActiveWinId := WinExist("ahk_class ExploreWClass"))) | |
{ | |
for (iteratedWindow in shellObj.Windows) | |
if ((latestActiveWindow := iteratedWindow).hWnd = latestActiveWinId) | |
break | |
locationName := latestActiveWindow.LocationName | |
return latestActiveWindow.Document.Folder.Self.Path | |
} | |
} | |
WatchActiveWindow() | |
{ | |
tooltipAxes := [A_ScreenWidth * 0.75, A_ScreenHeight] | |
try | |
{ | |
focusedHwnd := ControlGetFocus("A") | |
focusedClassNN := ControlGetClassNN(focusedHwnd) | |
controlList := "𝗖𝗼𝗻𝘁𝗿𝗼𝗹 𝗟𝗶𝘀𝘁 𝗢𝗳 𝗔𝗰𝘁𝗶𝘃𝗲 𝗪𝗶𝗻𝗱𝗼𝘄: " WinGetProcessName("A") | |
. "`n𝗙𝗼𝗰𝘂𝘀𝗲𝗱 𝗖𝗼𝗻𝘁𝗿𝗼𝗹: {𝗵𝗪𝗻𝗱: " focusedHwnd ", 𝗖𝗹𝗮𝘀𝘀𝗡𝗡: `"" focusedClassNN "`"}" | |
. "`n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`n" | |
for (classNN in WinGetControls("A")) | |
controlList .= classNN "`n" | |
if (controlList = "") | |
ToolTip("The active window has no controls.", tooltipAxes*) | |
else | |
ToolTip(ControlList, tooltipAxes*) | |
} | |
catch (TargetError) | |
ToolTip("No visible window is active.", tooltipAxes*) | |
} | |
SystemCursor(cmd) ; cmd = "Show|Hide|Toggle|Reload" | |
{ | |
static visible := true, c := Map() | |
static sys_cursors := [32512, 32513, 32514, 32515, 32516, 32642, 32643, 32644, 32645, 32646, 32648, 32649, 32650] | |
if (cmd = "Reload" || !c.Count) ; Reload when requested or at first call | |
{ | |
for (i, id in sys_cursors) | |
{ | |
h_cursor := DllCall("LoadCursor", "Ptr", 0, "Ptr", id) | |
h_default := DllCall("CopyImage", "Ptr", h_cursor, "UInt", 2, "Int", 0, "Int", 0, "UInt", 0) | |
h_blank := DllCall("CreateCursor", "Ptr", 0, "Int", 0, "Int", 0, "Int", 32, "Int", 32, "Ptr", Buffer(32 * 4, 0xFF), "Ptr", Buffer(32 * 4, 0)) | |
c[id] := {Default: h_default, Blank: h_blank} | |
} | |
} | |
switch (cmd) | |
{ | |
case "Show": visible := true | |
case "Hide": visible := false | |
case "Toggle": visible := !visible | |
default: return | |
} | |
for (id, handles in c) | |
{ | |
h_cursor := DllCall("CopyImage", "Ptr", visible ? handles.Default : handles.Blank, "UInt", 2, "Int", 0, "Int", 0, "UInt", 0) | |
DllCall("SetSystemCursor", "Ptr", h_cursor, "UInt", id) | |
} | |
} | |
class MenuItemInfo | |
{ | |
CbSize: u32 := ObjGetDataSize(this), FMask: u32, FType: u32, FState: u32, WID: u32, HSubMenu: iptr, HbmpChecked: iptr, HbmpUnchecked: iptr, DwItemData: uptr, DwTypeData: iptr | |
Cch: u32, HbmpItem: iptr | |
} | |
class Point | |
{ | |
X: i32, Y: i32 | |
} | |
/* | |
Example usage: (hook := PointerDeviceHook("Move|LButton Down|LButton Up", HandlePointerDeviceEvent)).Start() | |
/** @param {PointerDeviceHook.EventInfo} eventInfo Pointer device event info */` | |
HandlePointerDeviceEvent(eventInfo) | |
{ | |
ToolTip(Format(" | |
( | |
x{1}, y{2} | |
EventAction : {3} | |
EventKey : {4} | |
KeyUsageCount : {5} | |
KeyUsageTime : {6} | |
PressDuration : {7} | |
IsPenAction : {8} | |
)", eventInfo.Pt.X, eventInfo.Pt.Y, eventInfo.Action, eventInfo.Key, eventInfo.KeyUsageCount, eventInfo.KeyUsageTime, eventInfo.KeyPressDuration, eventInfo.IsPenAction)) | |
} | |
*/ | |
class PointerDeviceHook | |
{ | |
class InternalEventInfo | |
{ | |
Pt: Point | |
MouseData: i32 ; Necessary cast to "Int" | |
Flags: u32 | |
Time: u32 | |
ExtraInfo: uptr | |
} | |
class EventInfo | |
{ | |
Pt => PointerDeviceHook.EventInfo.IsKeyPressedDown && this._IsPtAdaptive ? PointerDeviceHook.EventInfo.LatestPt : this._Pt | |
/** @prop {string} Action The event action */ | |
Action => PointerDeviceHook.EventInfo.IsKeyPressedDown ? (PointerDeviceHook.EventInfo.LatestAction ?? this._Action) : this._Action | |
/** @prop {string} Key The event key */ | |
Key => PointerDeviceHook.EventInfo.IsKeyPressedDown ? PointerDeviceHook.EventInfo.KeyToKeep : this._Key | |
/** @prop {integer} KeyUsageCount Count how many times a key gets pressed in a short time (`KeyUsageCountTimeThreshold`) */ | |
KeyUsageCount => PointerDeviceHook.EventInfo.IsKeyPressedDown ? PointerDeviceHook.EventInfo.KeyUsageCountToKeep : this._KeyUsageCount | |
/** @prop {string} KeyUsageTime The time when the event key was pressed, scrolled, or used for a pen action */ | |
KeyUsageTime => PointerDeviceHook.EventInfo.IsKeyPressedDown ? PointerDeviceHook.EventInfo.KeyUsageTimeToKeep : this._KeyUsageTime | |
/** @prop {integer} KeyPressDuration The time elapsed since this key was pressed */ | |
KeyPressDuration => (this.KeyUsageTime ? A_TickCount - this.KeyUsageTime : 0) | |
/** @prop {integer} IsPenAction Whether or not the event is caused by a pen pointer device (not detected when using drawing tablet) */ | |
IsPenAction => PointerDeviceHook.EventInfo.IsKeyPressedDown ? PointerDeviceHook.EventInfo.IsPenActionToKeep : this._IsPenAction | |
/** @prop {boolean} IsKeyPressedDown The hook does not repeatedly trigger the down event while a key is pressed down, so those `onEvent` callbacks use timer & keeps relevant info */ | |
static IsKeyPressedDown := false | |
static __New() => this.LatestPt := Point() | |
__New() => this._Pt := Point() | |
} | |
/** @prop {Map} MsgList A list of actions and message codes */ | |
MsgList := Map( | |
512, "Move", | |
513, "LButton Down", | |
514, "LButton Up", | |
516, "RButton Down", | |
517, "RButton Up", | |
519, "MButton Down", | |
520, "MButton Up", | |
522, "Wheel", | |
523, "XButton{:d} Down", | |
524, "XButton{:d} Up") | |
/** @prop {integer} ProcHandle SetWindowsHookEx */ | |
ProcHandle := 0 | |
/** @prop {Map} PriorKeyObjects The map logs the time of when keys were previously pressed, as well as the count (both saved inside an object which is associated with a key) */ | |
PriorKeyObjects := Map() | |
/** @prop {integer} KeyUsageCountTimeThreshold The time in which the usage of the event key gets counted, or reset when the time threshold is reached (milliseconds) */ | |
KeyUsageCountTimeThreshold := 500 | |
/** | |
* @param {string} [action="All"] Move, LButton Down, MButton Up, etc (the `MsgList` property shows all of them) | |
* @param {(hookObj) => Integer} onEvent This callback gets called on the event (to block mouse actions the callback must return true w/ default value `shouldMaintainResponsiveness`) | |
* @param {integer} [shouldMaintainResponsiveness=false] Default is False, causing it to call `onEvent` in this thread in favor of mouse-action-blocking capability (consider using timer | |
* in `onEvent`). Specify True to call it in a different thread if the `onEvent` code causes considerable mouse lag, as a result the Proc becomes incapable of blocking mouse actions | |
* @param {integer} [criticalMode=0] Default is Disabled Mode. A (positive) Enabled Mode value is the message check interval. Specifying -1 turns on Critical but disables message checks | |
*/ | |
__New(action := "All", onEvent := (*) => 0, shouldMaintainResponsiveness := false, criticalMode := 0) | |
{ | |
static WM_LBUTTONUP := 0x0202, WM_RBUTTONUP := 0x0205, WM_MBUTTONUP := 0x0208, WM_MOUSEWHEEL := 0x020A, WM_XBUTTONDOWN := 0x020B, WM_XBUTTONUP := 0x020C | |
, LLMHF_INJECTED := 0x00000001, MI_WP_SIGNATURE := 0xFF515700, SIGNATURE_MASK := 0xFFFFFF00 | |
; This callback gets executed when a pointer-device hook event occurs. The fast mode should be used only when it is known exactly which thread(s) this callback will be called from | |
this.InternalCallback := CallbackCreate(PointerDeviceProc, (criticalMode && criticalMode != "Off") ? "F" : unset, 3) | |
PointerDeviceProc(nCode, wParam, lParam) | |
{ | |
if (criticalMode = -1 || criticalMode) | |
Critical(criticalMode) | |
internalEventInfo := StructFromPtr(PointerDeviceHook.InternalEventInfo, lParam) | |
eventInfo := PointerDeviceHook.EventInfo() | |
eventInfo._IsPtAdaptive := false | |
eventInfo._Key := 0 | |
switch (wParam) | |
{ | |
; internalEventInfo.MouseData contains a reserved low-order word, which we don't need, and the high-order word is the leftmost 16 bits (bitshift removes the rest) | |
case WM_MOUSEWHEEL: eventInfo._Action := (internalEventInfo.MouseData >> 16) > 0 ? "WheelUp" : "WheelDown" | |
case WM_XBUTTONDOWN, WM_XBUTTONUP: eventInfo._Action := Format(this.MsgList[wParam], internalEventInfo.MouseData >> 16) | |
default: eventInfo._Action := this.MsgList.Has(wParam) ? this.MsgList[wParam] : 0 | |
} | |
if (nCode < 0 || (action != "All" && !InStr(action, eventInfo._Action))) | |
return CallNextHookEx(nCode, wParam, lParam) | |
if (eventInfo._Action && eventInfo._Action != "Move") | |
{ | |
isKeyUpEvent := false | |
switch (wParam) | |
{ | |
case WM_LBUTTONUP, WM_RBUTTONUP, WM_MBUTTONUP, WM_XBUTTONUP: isKeyUpEvent := true | |
} | |
if (eventInfo._Key != eventInfo._Action) | |
eventInfo._Key := eventInfo._Action | |
if (!this.PriorKeyObjects.Has(eventInfo._Action)) | |
this.PriorKeyObjects[eventInfo._Action] := {Time: internalEventInfo.Time, Count: 0} | |
priorKey := this.PriorKeyObjects[eventInfo._Action] | |
eventInfo._KeyUsageCount := priorKey.Count += internalEventInfo.Time - priorKey.Time < this.KeyUsageCountTimeThreshold ? 1 : -priorKey.Count + 1 ; Resets to 1 if false | |
eventInfo._KeyUsageTime := priorKey.Time := internalEventInfo.Time | |
eventInfo._IsPenAction := DetermineIsPenAction(internalEventInfo.ExtraInfo) | |
if (isKeyUpEvent || wParam = WM_MOUSEWHEEL) | |
{ | |
eventInfo._Pt.X := internalEventInfo.Pt.X | |
eventInfo._Pt.Y := internalEventInfo.Pt.Y | |
PointerDeviceHook.EventInfo.IsKeyPressedDown := false | |
} | |
else | |
{ | |
eventInfo._IsPtAdaptive := true | |
PointerDeviceHook.EventInfo.LatestPt.X := internalEventInfo.Pt.X | |
PointerDeviceHook.EventInfo.LatestPt.Y := internalEventInfo.Pt.Y | |
PointerDeviceHook.EventInfo.LatestAction := unset | |
PointerDeviceHook.EventInfo.KeyToKeep := eventInfo._Key | |
PointerDeviceHook.EventInfo.KeyUsageCountToKeep := eventInfo._KeyUsageCount | |
PointerDeviceHook.EventInfo.KeyUsageTimeToKeep := internalEventInfo.Time | |
PointerDeviceHook.EventInfo.IsPenActionToKeep := eventInfo._IsPenAction | |
PointerDeviceHook.EventInfo.IsKeyPressedDown := true | |
SetTimer(() => (this.ProcHandle && PointerDeviceHook.EventInfo.IsKeyPressedDown ? onEvent(eventInfo) : SetTimer(, 0)), 50) | |
} | |
} | |
else if (PointerDeviceHook.EventInfo.IsKeyPressedDown) | |
{ | |
PointerDeviceHook.EventInfo.LatestPt.X := eventInfo._Pt.X := internalEventInfo.Pt.X | |
PointerDeviceHook.EventInfo.LatestPt.Y := eventInfo._Pt.Y := internalEventInfo.Pt.Y | |
PointerDeviceHook.EventInfo.LatestAction := eventInfo._Action | |
} | |
else | |
{ | |
eventInfo._Pt.X := internalEventInfo.Pt.X | |
eventInfo._Pt.Y := internalEventInfo.Pt.Y | |
eventInfo._KeyUsageTime := eventInfo._KeyUsageCount := eventInfo._Key := 0 | |
eventInfo._IsPenAction := DetermineIsPenAction(internalEventInfo.ExtraInfo) | |
} | |
if (shouldMaintainResponsiveness) | |
{ | |
SetTimer(() => onEvent(eventInfo), -1) | |
return CallNextHookEx(nCode, wParam, lParam) | |
} | |
else | |
return onEvent(eventInfo) && !(internalEventInfo.Flags & LLMHF_INJECTED) ? true : CallNextHookEx(nCode, wParam, lParam) | |
} | |
DetermineIsPenAction(extraInfo) => ((extraInfo & SIGNATURE_MASK) = MI_WP_SIGNATURE) | |
CallNextHookEx(nCode, wParam, lParam) => DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "UPtr", wParam, "Ptr", lParam) | |
} | |
/** Warning: Take caution when blocking mouse actions, you should not call this inside a mouse hotkey prefixed w/ the (~) tilde symbol (to make `Stop` unblock mouse actions properly) */ | |
Start() | |
{ | |
if (!this.ProcHandle) | |
this.ProcHandle := DllCall("SetWindowsHookEx", "Int", WH_MOUSE_LL := 14, "Ptr", this.InternalCallback, "Ptr", GetModuleHandle(), "UInt", 0) | |
GetModuleHandle() => DllCall("GetModuleHandle", "UInt", 0, "Ptr") | |
} | |
Stop() | |
{ | |
if (this.ProcHandle && DllCall("UnhookWindowsHookEx", "Ptr", this.ProcHandle)) | |
this.ProcHandle := 0 | |
} | |
__Delete() => (this.InternalCallback && (this.Stop(), CallbackFree(this.InternalCallback), this.InternalCallback := 0)) | |
} | |
OpenGoogle(*) | |
{ | |
SystemCursor("Show") | |
if (FileExist(A_ProgramFiles "\Google\Chrome\Application\chrome.exe")) | |
{ | |
if (ProcessExist("chrome.exe") || !(hasTabsOutlinerExtension := DirExist(EnvGet("LocalAppData") "\Google\Chrome\User Data\Default\Extensions\eggkanocgddhmamlbiijnphhppkpkmkl"))) | |
Run("chrome.exe https://www.google.com/ --start-maximized --disable-features=GlobalMediaControls") | |
else | |
{ | |
HookEvent(EVENT_OBJECT_NAMECHANGE, HandleTabsOutlinerEvent) | |
Run("chrome.exe https://www.google.com/ --start-maximized --disable-features=GlobalMediaControls") | |
} | |
} | |
else | |
Run("https://www.google.com/") | |
} | |
HandleTabsOutlinerEvent(hWinEventHook, event, hWnd, *) | |
{ | |
static isBeingClosed := false | |
try | |
if (WinGetTitle(hWnd) = "_crx_eggkanocgddhmamlbiijnphhppkpkmkl" && !isBeingClosed) | |
{ | |
isBeingClosed := true | |
try WinSetTransparent(0, hWnd) ; Gets rid of the close animation | |
try WinClose(hWnd) | |
DllCall("UnhookWinEvent", "Ptr", hWinEventHook) | |
Sleep(-1) ; Discards queued events that might remain | |
isBeingClosed := false | |
} | |
} | |
OpenMaps(*) | |
{ | |
SystemCursor("Show") | |
Run("shell:AppsFolder\Microsoft.WindowsMaps_8wekyb3d8bbwe!app") | |
if (!WinWaitActive("Maps ahk_class ApplicationFrameWindow",, 3)) | |
return | |
Sleep(300) | |
Send("^y{Ctrl down}") | |
loop (50) | |
Sleep(50), Send("{Home}") | |
Send("{Ctrl up}") | |
} | |
HandleMediaPlayerEvent(hWinEventHook, event, hWnd, *) | |
{ | |
static isBeingMadeFullscreen := false | |
try | |
if (!networkStream.IsActive && WinGetTitle(hWnd) = "VLC" && IsPlayingFromFullscreenVideosContextFolder() && !isBeingMadeFullscreen) | |
{ | |
isBeingMadeFullscreen := true | |
try WinSetTransparent(0, hWnd) | |
Sleep(300) ; Discards queued events that might remain and allows VLC to become fullscreen | |
Send("f") | |
try WinSetTransparent("Off", hWnd) | |
isBeingMadeFullscreen := false | |
} | |
IsPlayingFromFullscreenVideosContextFolder() | |
{ | |
playedMedia := IniRead(A_AppData "\vlc\vlc-qt-interface.ini", "RecentsMRL", "list") | |
; https://www.autohotkey.com/docs/v2/misc/RegEx-QuickRef.htm (Regular Expressions [RegEx] - Quick Reference) | |
if (fullscreenVideosContextFolderSection := StrReplace(IniRead(iniPath, "FullscreenVideosContextFolder"), " ", "%20")) | |
return playedMedia ~= "^file:///" fullscreenVideosContextFolderSection ; The ^ requires the match to be at the start | |
} | |
} | |
HandleFullscreenWinEvent(hWinEventHook, event, hWnd, *) | |
{ | |
if (WinExist("ahk_group FullscreenWindows ahk_id " hWnd)) | |
Sleep(200), MarkFullscreenWindow(hWnd, false) | |
} | |
; https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist2-markfullscreenwindow | |
MarkFullscreenWindow(hWnd := WinExist("A"), fullscreenStatusToSet := true) | |
{ | |
static tbl2 := CreateTaskbarList2() | |
ComCall(8, tbl2, "Ptr", hWnd, "Int", fullscreenStatusToSet) | |
CreateTaskbarList2() | |
{ | |
iid_ITaskbarList := "{56FDF342-FD6D-11d0-958A-006097C9A090}" ; Interface id (iid) | |
iid_ITaskbarList2 := "{602D4995-B13A-429B-A66E-1935E44F4317}" ; Interface id (iid) | |
clsid_TaskbarList := "{56FDF344-FD6D-11d0-958A-006097C9A090}" ; Class id (clsid) | |
tbl := ComObject(clsid_TaskbarList, iid_ITaskbarList) ; Creates the TaskbarList object | |
loop (10) | |
{ | |
try ComCall(3, tbl) ; Calls tbl.HrInit(), which initializes the TaskbarList object | |
catch | |
Sleep(50) | |
else | |
break | |
} | |
return ComObjQuery(tbl, iid_ITaskbarList2) ; Queries the TaskbarList object to get the TaskbarList2 object | |
} | |
} | |
MouseIsOver(winTitle, winText?, excludeTitle?, excludeText?) => (MouseGetPos(,, &winId), WinExist(winTitle " ahk_id " winId, winText?, excludeTitle?, excludeText?)) | |
ManageVisualStudioEventHandlers() | |
{ | |
static textSelectionChangedEventHandler := UIA.CreateAutomationEventHandler(HandleVisualStudioTextSelectionChangedEvent) | |
, structureChangedEventHandler := UIA.CreateStructureChangedEventHandler(HandleVisualStudioStructureChangedEvent) | |
, cacheRequest := UIA.CreateCacheRequest(["Type", "ClassName"],, UIA.TreeScope.Element) | |
loop | |
{ | |
WinWaitActive("Microsoft Visual Studio ahk_exe devenv.exe") | |
loop | |
{ | |
try | |
{ | |
visualStudioElement := UIA.ElementFromHandle("Microsoft Visual Studio ahk_exe devenv.exe") | |
break | |
} | |
catch | |
Sleep(100) | |
} | |
UIA.AddAutomationEventHandler(textSelectionChangedEventHandler, visualStudioElement, UIA.Event.Text_TextSelectionChanged) | |
UIA.AddStructureChangedEventHandler(structureChangedEventHandler, visualStudioElement,, cacheRequest) | |
WinWaitNotActive() ; To make it work with multiple VS windows, it'll remove the event handlers on deactivate, and event handlers are natively removed on close | |
try UIA.RemoveAutomationEventHandler(UIA.Event.Text_TextSelectionChanged, visualStudioElement, textSelectionChangedEventHandler) | |
UIA.RemoveStructureChangedEventHandler(structureChangedEventHandler, visualStudioElement) | |
} | |
} | |
; Reset caret hide state on relevant text selection | |
HandleVisualStudioTextSelectionChangedEvent(element, *) | |
{ | |
try (A_ThisHotkey != "MButton" && UIA.CompareElements(focusedElement.Latest, element)) ? (focusedElement.Latest := unset, focusedElement.Selection := unset) : Exit() | |
} | |
; Auto-scroll namespace on relevant structure change | |
HandleVisualStudioStructureChangedEvent(sender, changeType, *) | |
{ | |
; Only StructureChangeType_ChildAdded is allowed to continue | |
if (changeType != 0) | |
return | |
if (sender.CachedType != UIA.Type.Pane || sender.CachedClassName != "ViewPresenter") | |
return | |
for (iteratedEditControl in sender.FindElements({Type: "Edit"})) | |
{ | |
try namespaceTextRange := iteratedEditControl.DocumentRange.FindText("namespace") | |
; The bounding rectangles obj exists only in the returned array when the text range is near the top, but also has properties (X, Y, W, H) that you can technically use | |
if (IsSet(namespaceTextRange) && namespaceTextRange.GetBoundingRectangles().Length = 1) | |
namespaceTextRange.ScrollIntoView(1) | |
} | |
} | |
HandleNotificationEvent(hWinEventHook, event, hWnd, *) | |
{ | |
; One WinRAR wnd has the title used below (permanently ofcourse) and has "ahk_class #32770", while the other WinRAR wnd has the class used below and has temporary title "WinRAR". | |
; The Software Ideas Modeler wnd has no unique title nor class at any point but it does have a control with the text used below | |
try | |
if | |
( | |
WinGetTitle(hWnd) = "Please purchase WinRAR license" || (WinGetClass(hWnd) = "RarReminder" && WinGetProcessName(hWnd) = "WinRAR.exe") || | |
ControlGetText("WindowsForms10.STATIC.app.0.2bf8098_r8_ad12", hWnd) = "Thank you for using Software Ideas Modeler!" | |
) | |
WinSetTransparent(0, hWnd), WinClose(hWnd) | |
} | |
HookEvent(event, fnObj, pid := 0) => DllCall("SetWinEventHook", "UInt", event, "UInt", event, "Ptr", 0, "Ptr", CallbackCreate(fnObj), "UInt", pid, "UInt", 0, "UInt", 0) | |
/* EXAMPLE | |
[_ActiveContextWindows] | |
ahk_exe Taskmgr.exe=services.msc | |
[_ExistingContextWindows] | |
[_ExistingContextWindowPriority1] | |
ahk_exe Unity.exe=C:\Users\loren\Documents\Unity projects\VOXEL WAR\Assets | |
[_ExistingContextWindowPriority2] | |
ahk_exe devenv.exe=C:\Users\loren\Documents\Unity projects\VOXEL WAR\Assets\Scripts | |
[_ExistingContextWindowPriority3] | |
ahk_exe notepad.exe=chrome.exe https://www.autohotkey.com/docs/alpha/ChangeLog.htm --start-maximized --disable-features=GlobalMediaControls | |
[_ExistingContextWindowPriority4] | |
Workspace - Visual Studio Code ahk_exe chrome.exe=chrome.exe https://www.autohotkey.com/docs/alpha/ChangeLog.htm --start-maximized --disable-features=GlobalMediaControls | |
[_PreferredSmartRunInput] | |
%LocalAppData% | |
[_FullscreenVideosContextFolder] | |
C:/Users/loren/Downloads/Movies and series | |
[_FullscreenWindowsUnhideTaskbar] | |
Sourcetree ahk_exe SourceTree.exe | |
Software Ideas Modeler ahk_exe SoftwareIdeasModeler.exe | |
*/ | |
/* Edit these variables yourself if necessary (e.g. to make it more specific you can add the ahk_class, and for the opposite effect you can replace the ahk_exe with an ahk_class or title) | |
[ActiveContextWindows] | |
[ExistingContextWindows] | |
[PreferredSmartRunInput] | |
[FullscreenVideosContextFolder] | |
[FullscreenWindowsUnhideTaskbar] | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment