Thanks, that worked perfectly. Now I've learned how to use {Blind} and KeyWait too, which will help me in the future.
Any idea why the previous hotkey was so unpredictable? It's not too important now that you've helped me get this working, but I am still curious.
Code: Select all
#CommentFlag // ; Change to C++ comment style.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
███ ██ ██████ ████████ ███████ ███████
████ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ █████ ███████
██ ██ ██ ██ ██ ██ ██ ██
██ ████ ██████ ██ ███████ ███████
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//======================================================================================================================
// This AutoHotkey script provides lots of functionality, which I will eventually summarize here.
//
// You'll need to know these symbols to understand what's going on:
// # = Windows
// ! = Alt
// ^ = Ctrl
// + = Shift
//
// & = Combines keys in any order
// < = Use left (Alt/Ctrl/Shift)
// > = Use right (Alt/Ctrl/Shift)
//
// ~ = When the hotkey fires, its key's native function will not be blocked (hidden from the system)
// * = Wildcard: Fire the hotkey even if extra modifiers are being held down
//
// $ = This is usually only necessary if the script uses the Send command to send the keys that comprise the hotkey
// itself, which might otherwise cause it to trigger itself. The $ prefix forces the keyboard hook to be used to
// implement this hotkey, which as a side-effect prevents the Send command from triggering it.
//
//
// More advanced stuf:
//
// {Blind} = When {Blind} is the first item in the string, the program avoids releasing Alt/Control/Shift/Win if they
// started out in the down position. For example, the hotkey +s::Send {Blind}abc would send ABC rather than
// abc because the user is holding down the Shift key.
//
// KeyWait = Waits for a key or mouse/joystick button to be released or pressed down.
// KeyWait, KeyName [, Options]
//
//
// Misc notes:
// - The first comma can be omitted from most commands
// - Sending double slashes is a hassle, so I've been sending them one at a time. Two alternatives:
// - Send, %str__two_slashes%{Enter}{ASC 47}{ASC 47}
//
// DOCS:
// https://www.autohotkey.com/docs/KeyList.htm
// https://www.autohotkey.com/docs/Hotkeys.htm
// https://www.autohotkey.com/docs/commands/Send.htm
// https://www.autohotkey.com/docs/misc/Macros.htm
//
// Forums:
// https://autohotkey.com/boards/
//======================================================================================================================
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
██████ ██████ ███ ██ ███████ ██ ██████
██ ██ ██ ████ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ █████ ██ ██ ███
██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██████ ██████ ██ ████ ██ ██ ██████
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//======================================================================================================================
// Note that any function that wants to use these variables must have global as its first line.
//======================================================================================================================
dir__base := "C:/Dev/### WAREHOUSE ###/Scripting/"
dir__ahk := dir__base . "AutoHotkey/"
dir__bat := dir__base . "BATs/"
dir__python = "C:/Dev/### WAREHOUSE ###/Scripting/CodeAligner/ScriptCallers"
str__two_slashes = {ASC 47}{ASC 47}
// This is only meant to be put in the clipboard. It can't be sent directly.
str__comment_block = /***********************************************************************************************************************`r`n *`r`n **********************************************************************************************************************/`r`n
// Three non-breaking spaces. The bullets use NBSPs too.
str__indent =
str__bullet_1 = ■
str__bullet_2 = ►
str__bullet_3 = •
// Use this to print a NBSP: {ASCII 0160}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
██████ ██████ ██████ ███████ ██ ██ ██████ ████████ ██ ██ ███████ ██ ██ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██████ █████ ███████ ██ ██ ██ █████ █████ ████ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██████ ██████ ██ ██ ███████ ██ ██ ██████ ██ ██ ██ ███████ ██ ███████
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//======================================================================================================================
// ALERT USER WHEN THIS SCRIPT IS LOADED
// Note: go to Sound > Sounds and disable the Notification sound
//======================================================================================================================
#SingleInstance Force
#installKeybdHook
#Persistent
Menu, Tray, Icon , Shell32.dll, 25, 1
TrayTip, AutoHotKey, Started, , 1
HideTrayTip()
Return
//======================================================================================================================
// HOW TO MANAGE THIS SCRIPT - Ctrl+Win+Alt+R reloads, Ctrl+Alt+Win+E edits
//======================================================================================================================
^#!r::Reload
^#!e::Edit
//======================================================================================================================
// Stupid testing hotkey - Shift+F11 shows a box with clipboard contents.
//======================================================================================================================
+F11::
{
SplashTextOn, 800, 800, Clipboard, The clipboard contains:`n`n%clipboard%
WinMove, Clipboard, , 0, 0 // Move the splash window to the top left corner.
Msgbox, Press OK to dismiss the SplashText
SplashTextOff
Return
}
//======================================================================================================================
// CONNECT TO VPNs WITH Alt+F12 (US) AND Ctrl+F12 (Canada). Shift+F12 starts WAMP.
//======================================================================================================================
^F12::
{
RunSilentBAT("ConnectToVPN_Canada.bat")
TrayTip, VPN - Canadian Data Center, Connecting, , 1
HideTrayTip()
Return
}
!F12::
{
RunSilentBAT("ConnectToVPN_US.bat")
TrayTip, VPN - US Data Center, Connecting, , 1
HideTrayTip()
Return
}
^!F12::
{
TrayTip, Info, Connect to VPNs with: Alt+F12 (US) or Ctrl+F12 (Canada), , 1
}
+F12::
{
Run, C:\Dev\wamp64\wampmanager.exe
Return
}
//======================================================================================================================
// COPY, OPEN CHROME AND SEARCH - Ctrl+Shift+C
//======================================================================================================================
^+c::
{
Send, ^c
Sleep 50
Run, http://www.google.com/search?q=%clipboard%
Return
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
███████ ██████ ███████ ██████ ██ █████ ██ ██ ██ ██████ ████████ ██ ██ ███████ ██ ██ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
███████ ██████ █████ ██ ██ ███████ ██ ███████ ██ ██ ██ █████ █████ ████ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
███████ ██ ███████ ██████ ██ ██ ██ ███████ ██ ██ ██████ ██ ██ ██ ███████ ██ ███████
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//======================================================================================================================
// MIDDLE MOUSE BUTTON GOES UP IN EXPLORER - Ctrl+RButton opens ConEmu
//======================================================================================================================
#IfWinActive, ahk_class CabinetWClass
~MButton::
{
Send !{Up}
Return
}
^RButton::
{
ClipSaved := ClipboardAll
Send !d
Sleep 10
Send ^c
Run "C:/Dev/ConEmu/ConEmu64.exe"
// We want an exact match
SetTitleMatchMode, 3
// Wait a moment for the window to load, then move it (it was appearing offscreen)
Sleep 250
WinMove, cmd, , 0, 0
IfWinExist, cmd
WinActivate
Return
}
#IfWinActive
//======================================================================================================================
// WINDOWS KEY + H TOGGLES HIDDEN FILES -- Doesn't currently seem to work
//======================================================================================================================
#h::
RegRead, HiddenFiles_Status, HKEY_CURRENT_USER, Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced, Hidden
If HiddenFiles_Status = 2
RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced, Hidden, 1
Else
RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced, Hidden, 2
WinGetClass, eh_Class,A
If (eh_Class = "#32770" OR A_OSVersion = "WIN_VISTA")
send, {F5}
Else PostMessage, 0x111, 28931,,, A
Return
//======================================================================================================================
// NOTEPAD++ HOTKEYS
//======================================================================================================================
#If WinActive("ahk_exe " "notepad++.exe")
// The * lets this hotkey work with extra modifier keys. By adding {Blind}, AHK will avoid releasing Shift if the
// user is holding it. This lets this single hotkey handle click-and-drag box selection and (Shifted) box-select-to.
// Thanks Exaskryz!
*MButton::
Send {Blind}{LAlt down}{LButton down}
KeyWait, MButton
Send {Blind}{LButton up}{LAlt up}
return
// Allows middle/thumb button to be used for box selection (Alt + LButton). This doesn't work as intended.
//MButton::!LButton
// After clicking somewhere, you can Shift+middle/thumb to box select to a new point. Doesn't work as intended.
//+MButton::+!LButton
// Ctrl+Shift+A will select a line
^+a::
Send {Home down}{Home up}{Shift down}{End down}{End up}{Shift up}
Return
//------------------------------------------------------------------------------------------------------------------
// BULLET - LEVEL 1
//------------------------------------------------------------------------------------------------------------------
F1::
{
// Save clipboard contents for later
original_clip_contents := ClipboardAll
clipboard = %str__bullet_1%
Send, ^v
// Revert to original clipboard contents
Clipboard := original_clip_contents
Return
}
//------------------------------------------------------------------------------------------------------------------
// BULLET - LEVEL 2
//------------------------------------------------------------------------------------------------------------------
F2::
{
// Save clipboard contents for later
original_clip_contents := ClipboardAll
clipboard = %str__bullet_2%
Send, ^v
// Revert to original clipboard contents
Clipboard := original_clip_contents
Return
}
//------------------------------------------------------------------------------------------------------------------
// BULLET - LEVEL 3
//------------------------------------------------------------------------------------------------------------------
F3::
{
// Save clipboard contents for later
original_clip_contents := ClipboardAll
clipboard = %str__bullet_3%
Send, ^v
// Revert to original clipboard contents
Clipboard := original_clip_contents
Return
}
#IfWinActive
//======================================================================================================================
// ANDROID STUDIO HOTKEYS
//======================================================================================================================
#If WinActive("ahk_exe " "studio64.exe")
// Allows middle/thumb button to be used for box selection (Alt + LButton)
MButton::+g
// F12 will send Ctrl+Shift+F12, which finds last change location
F12::
Send, ^+{BS}
Return
// F7 will send Shift+F6, which does a [refactor > rename]
F7::
Send, +{F6}
Return
#IfWinActive
//======================================================================================================================
// ATOM HOTKEYS
//======================================================================================================================
#If WinActive("ahk_exe " "atom.exe")
// Ctrl+Shift+A will select line content (not including indenting whitespace)
^+a::
Send {Home down}{Home up}{Shift down}{End down}{End up}{Shift up}
Return
#IfWinActive
//======================================================================================================================
// ECLIPSE HOTKEYS
//======================================================================================================================
#If WinActive("ahk_exe " "eclipse.exe")
// Runs file in Eclipse as a Java application
ScrollLock::
Send {Alt down}{Shift down}x{Shift up}{Alt up}
sleep 1000
Send j
Return
#IfWinActive
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
██ ███ ██ ███████ ███████ ██████ ████████ ████████ ███████ ██ ██ ████████
██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ███████ █████ ██████ ██ ██ █████ ███ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ████ ███████ ███████ ██ ██ ██ ██ ███████ ██ ██ ██
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//======================================================================================================================
// This types "// TODO: REMOVE", hits enter, then removes the "// " that Atom automatically inserts.
//======================================================================================================================
^Insert::
{
Send, /
Send, /
Send, {Space}TODO: REMOVE
Send, {Enter}{Backspace}{Backspace}{Backspace}
Return
}
//======================================================================================================================
// This types "// TODO: REMOVE"
//======================================================================================================================
!Insert::
{
Send, /
Send, /
Send, {Space}TODO: REMOVE
Return
}
//======================================================================================================================
// This hits enter, then types "// TODO: REMOVE"
//======================================================================================================================
+Insert::
{
Send, {Enter}//{Space}TODO: REMOVE
Return
}
//======================================================================================================================
// TEST
//======================================================================================================================
+^Insert::
{
clipboard = %str__comment_block%
Send, ^v
Return
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
██████ █████ ██ ██ ███████ ██████ ██████ ██ ██████ ████████ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ███████ ██ ██ ███████ ██ ██████ ██ ██████ ██ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██████ ██ ██ ███████ ███████ ███████ ██████ ██ ██ ██ ██ ██ ███████
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//======================================================================================================================
// These functions call Python scripts to act on the current selection. Your original clipboard is recovered afterwards.
//
// These all call short scripts that go on to call the actual scripts in CodeAligner. This is because I'm not sure how
// to call functions within a module from AHK.
//
// For tasks which can have spaces inserted before or after, there will be separate versions of the dummy scripts, which
// will pass in the appropriate please_insert_before parameter (or leave it out and let it default to True).
//
// align_via_clip__comments
// align_via_clip__ternary
// align_via_clip__equals__before
// align_via_clip__colon__after
//======================================================================================================================
^!q::
{
Result := invoke_python_on_selection("align_via_clip__comments.pyw")
Return
}
^!w::
{
Result := invoke_python_on_selection("align_via_clip__ternary.pyw")
Return
}
^!e::
{
Result := invoke_python_on_selection("align_via_clip__equals.pyw")
Return
}
^!r::
{
Result := invoke_python_on_selection("align_via_clip__colon__after.pyw")
Return
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
███████ ██ ██ ███ ██ ██████ ████████ ██ ██████ ███ ██ ███████
██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ████ ██ ██
█████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██████ ██ ████ ██████ ██ ██ ██████ ██ ████ ███████
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//======================================================================================================================
// This function wraps the next one. It makes things more concise and lets us pass in a filename instead of a path, as
// it uses the dir__python defined in the config section.
//======================================================================================================================
invoke_python_on_selection(script_name)
{
// TODO: Should we add ".pyw"?
return, copy__run_python__paste__recover_clip(dir__python + script_name)
}
//======================================================================================================================
// This function saves the clipboard, runs the provided script, pastes the result, then reverts to the original
// clipboard.
//
// TODO: Reselect what we just pasted
//======================================================================================================================
copy__run_python__paste__recover_clip(script_path)
{
// Save clipboard contents for later
original_clip_contents := ClipboardAll
// Put current selection in our clipboard
Clipboard=
Send, ^c
// Delay
sleep 200
// Now we call the script that was passed in
Run %script_path%
// Delay
sleep 200
// This holds the new clipboard value
modified_selected_text := Clipboard
// Paste the modified version of the selected text
Send, ^v
// Delay
sleep 200
// Revert to original clipboard contents
Clipboard := original_clip_contents
// Return modified version of selected text
return, modified_selected_text
}
//======================================================================================================================
// This function uses a simple Visual Basic script to run BAT files silently, with no annoying empty popup window.
//======================================================================================================================
RunSilentBAT(script_name)
{
global
script_path__silent_vbs := dir__ahk . "Run_BAT_Silently.vbs"
script_path__bat := dir__bat . script_name
Run, C:/Windows/System32/wscript.exe "%script_path__silent_vbs%" "%script_path__bat%"
}
//======================================================================================================================
// This function hides the Tray Tip/toast notification rather quickly. Required since the default minimum is ~10s.
//======================================================================================================================
HideTrayTip()
{
// Attempt to hide it the normal way
TrayTip
Sleep 1500
// Windows 10 requires special handling - I don't really understand this
if SubStr(A_OSVersion,1,3) = "10."
{
Menu Tray, NoIcon
// It may be necessary to adjust this sleep.
Sleep 500
Menu Tray, Icon
}
}