Skip to content

Instantly share code, notes, and snippets.

@davebrny
Last active April 15, 2023 20:29
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davebrny/4f14e1edb4fac2fc2459c3d87fa537f7 to your computer and use it in GitHub Desktop.
Save davebrny/4f14e1edb4fac2fc2459c3d87fa537f7 to your computer and use it in GitHub Desktop.
🚚 (autohotkey) - reload running scripts from a context menu
/*
[script info]
version = 0.8
description = reload running scripts from a context menu
author = davebrny
source = https://gist.github.com/davebrny/4f14e1edb4fac2fc2459c3d87fa537f7
[settings]
hotkey_menu = ^+`
hotkey_default = ^`
hotkey_last = !`
icon_size = 32
sort_by_recent = true
default_script =
[ini end]
*/
#noEnv
#singleInstance, force
setWorkingDir, % a_scriptDir
detectHiddenWindows, on
setTitleMatchMode 2
onExit, save_exit
iniRead, section, % a_lineFile, settings ; load ini settings
loop, parse, % section, `n, `r
{
stringGetPos, pos, a_loopField, =, L1
stringMid, ini_key, a_loopField, pos, , L
stringMid, ini_value, a_loopField, pos + 2
%ini_key% := ini_value
}
sort_type := (sort_by_recent = "true") ? "recent" : "alphabetical"
menu, tray, add
menu_add_options("tray")
if (default_script)
{
filename := filename(default_script)
menu, tray, add, % filename, script_reload_tray
menu, tray, default, % filename
menu, tray, tip, % "reloadr (" filename ")"
}
menu, tray, click, 1 ; reload the default script with 1 click
; tray_icon := script_icon(a_lineFile) ; [ search for an icon: git.io/vyBcQ ]
if (tray_icon)
menu, tray, icon, % tray_icon
else menu, tray, icon, % a_winDir "\System32\shell32.dll", 239 ; 239 = reload icon on windows 10
hotkey, % hotkey_menu, create_menu
hotkey, % hotkey_default, default_script
hotkey, % hotkey_last, last_script
return ; end of auto-execute ---------------------------------------------------
create_menu:
setBatchLines, -1
script_paths := running_scripts()
if (sort_type = "alphabetical")
sort, script_paths
menu, main_menu, useErrorLevel
; put default at the top
if (default_script) and (sort_type = "recent")
{
menu_add(default_script)
if (inStr(script_paths, "`n"))
menu, main_menu, add
}
; add the rest
loop, parse, % script_paths, `n
{
if (sort_type = "recent") and (a_loopField = a_lineFile)
continue
else menu_add(a_loopField)
}
; put reloadr.ahk at the end
if (sort_type = "recent")
menu_add(a_lineFile)
menu, main_menu, add
menu, main_menu, default, % item_name(default_script)
menu, main_menu, useErrorLevel, off
menu_add_options("main_menu")
toolTip,
menu, main_menu, show
menu, main_menu, delete
try menu, startup_scripts, delete
setBatchLines, 10
return
default_script: ; (hotkey labels)
last_script:
script_paths := running_scripts()
if (last_script = "") ; switch to the last script that was reloaded
{
loop, parse, % script_paths, `n
last_script := a_loopField
until (a_loopField != default_script) and (a_loopField != a_lineFile)
}
if (%a_thisLabel% = "")
msg_tool(strReplace(a_thisLabel, "_script") " reload not set")
else
{
reload_script(%a_thisLabel%)
msg_tool(filename(%a_thisLabel%) "`n`nreloaded")
}
return
reload_script(script_path) {
global
if (script_path)
{
if (script_path != default_script)
last_script := script_path
run, "%script_path%" /restart
}
}
running_scripts() {
global default_script, last_script
winGet, running, list, ahk_class AutoHotkey
loop % running
{
winGetTitle, title, % "ahk_id " running%a_index%
path := regExReplace(title,"\s-\sAutoHotkey\s.*")
script_paths .= (script_paths ? "`n" : "") . path
}
; reset defaults if they dont exist
if !inStr(script_paths, default_script)
default_script := ""
if !inStr(script_paths, last_script)
last_script := ""
return script_paths
}
menu_add_options(parent_menu) {
global sort_type, script_paths
try menu, % "main_menu_options", delete
options := parent_menu "_options"
if (parent_menu != "tray")
{
menu, % options, add, Help , script_help
menu, % options, add, Window Spy, script_window_spy
menu, % options, add
menu, startup_scripts, add, Select to run a shortcut:, run_shortcut
menu, startup_scripts, disable, Select to run a shortcut:
menu, startup_scripts, add
loop, files, % a_startup "\*.lnk", F ; add any ahk shortcuts
{
fileGetShortcut, % a_loopFileFullPath, target
splitPath, % target, filename, , file_ext
if (file_ext = "ahk")
{
menu, startup_scripts, add, % filename, run_shortcut
if inStr(script_paths, "\" filename)
menu, startup_scripts, check, % filename
}
}
if (file_ext = "ahk")
menu, startup_scripts, add
menu, startup_scripts, add, Reload Startup Folder, reload_startup_folder
menu, startup_scripts, add, Reload .ahk Only , reload_startup_ahk
menu, main_menu_options, add, Startup Scripts, :startup_scripts
}
menu, % options, add, Sort By Recent, change_sort_type
menu, % options, % (sort_type = "recent") ? "check" : "unCheck", Sort By Recent
menu, % options, add
menu, % options, add, Compile All, Compile_All_Scripts
menu, % options, add, Reload All, reload_all
menu, % options, add, Exit All, exit_all
menu, % parent_menu, add, Options, % ":" options
}
item_name(script_path) { ; add (s)(p) to item text
global is_paused, is_suspended
script_state(script_path, is_paused, is_suspended)
state .= (is_suspended) ? "(s)" : ""
state .= (is_paused) ? "(p)" : ""
if (state)
state := a_tab . state
script_name := filename(script_path)
return script_name . state
}
script_state(script_path, byRef is_paused, byRef is_suspended) {
; by Fanatic Guru ; https://autohotkey.com/board/topic/57245-how-can-i-find-if-other-script-is-pausedsuspended-4-pausing/#entry647835
winGet, script_id, id, % script_path " ahk_class AutoHotkey"
; Force the script to update its Pause/Suspend checkmarks.
SendMessage, 0x211,,,, ahk_id %script_id% ; WM_ENTERMENULOOP
SendMessage, 0x212,,,, ahk_id %script_id% ; WM_EXITMENULOOP
; Get script status from its main menu.
mainMenu := DllCall("GetMenu", "uint", script_id)
fileMenu := DllCall("GetSubMenu", "uint", mainMenu, "int", 0)
is_paused := DllCall("GetMenuState", "uint", fileMenu, "uint", 4, "uint", 0x400) >> 3 & 1
is_suspended := DllCall("GetMenuState", "uint", fileMenu, "uint", 5, "uint", 0x400) >> 3 & 1
DllCall("CloseHandle", "uint", fileMenu)
DllCall("CloseHandle", "uint", mainMenu)
}
menu_add(script_path) {
global icon_size, is_paused, is_suspended
menu_text := item_name(script_path)
menu, main_menu, add, % menu_text, script_reload
if isFunc("script_icon")
icon_path := icon_search(script_path)
menu, main_menu, icon, % menu_text, % icon_path, , % icon_size
splitPath, script_path, filename, , file_ext, name_no_ext
try menu, % menu_text, delete
if (file_ext = "ahk")
{
menu, % menu_text, add, Set As Default , set_as_default
menu, % menu_text, add
menu, % menu_text, add, Open , script_open
menu, % menu_text, add, Help , script_help
menu, % menu_text, add, Window Spy , script_window_spy
menu, % menu_text, add
menu, % menu_text, add, Run At Startup , run_at_startup
menu, % menu_text, add, Reload This Script , script_reload
menu, % menu_text, add, Edit This Script , script_edit
menu, % menu_text, add
menu, % menu_text, add, Compile , script_compile
menu, % menu_text, add
menu, % menu_text, add, Suspend Hotkeys , script_suspend
menu, % menu_text, add, Pause Script , script_pause
menu, % menu_text, add, Exit , script_exit
}
else if (file_ext = "exe")
{
menu, % menu_text, add, Help , script_help
menu, % menu_text, add, Window Spy , script_window_spy
menu, % menu_text, add
menu, % menu_text, add, Run At Startup , run_at_startup
menu, % menu_text, add, Reload This Script , script_reload
menu, % menu_text, add, Exit , script_exit
}
else if (inStr(script_path, "\\.\pipe\AHK_")) ; piped buffer
{
menu, % menu_text, add, Open , script_open
menu, % menu_text, add, Help , script_help
menu, % menu_text, add, Window Spy , script_window_spy
menu, % menu_text, add
menu, % menu_text, add, Suspend Hotkeys , script_suspend
menu, % menu_text, add, Pause Script , script_pause
menu, % menu_text, add, Exit , script_exit
}
menu, % menu_text, default, Reload This Script
if (is_paused)
menu, % menu_text, check, Pause Script
if (is_suspended)
menu, % menu_text, check, Suspend Hotkeys
shortcut := a_startup "\" name_no_ext ".lnk"
ifExist, % shortcut
menu, % menu_text, check, Run At Startup
else menu, % menu_text, unCheck, Run At Startup
menu, main_menu, add, % menu_text, % ":" menu_text
}
icon_search(script_path) {
global
squashed_path := "icon_" regExReplace(script_path, "[\W]")
stored_in := %squashed_path%
if (stored_in = "")
{
; icon_path := script_icon(script_path) ; [ search for an icon: git.io/vyBcQ ]
if (icon_path)
%squashed_path% := icon_path ; store value for next time the menu opens
}
else icon_path := stored_in ; use stored value
return icon_path
}
full_path(filename) { ; get the path that matches the filename
global script_paths
if (script_paths = "")
script_paths := running_scripts()
loop, parse, script_paths, `n
{
loop_filename := filename(a_loopField)
if (filename = loop_filename)
{
full_path := a_loopField
break
}
}
return full_path
}
item_file(menu_item) { ; get filename from menu text / remove (s)(p)
if menu_item contains (s),(p)
{
if (subStr(menu_item, -2, 3) = "(p)")
stringTrimRight, menu_item, menu_item, 3
if (subStr(menu_item, -2, 3) = "(s)")
stringTrimRight, menu_item, menu_item, 3
menu_item := trim(menu_item)
}
return menu_item
}
filename(path) {
splitPath, path, filename
return filename
}
msg_tool(msg, d="1800") {
toolTip, % msg
setTimer, msg_timer, % d
}
msg_timer() {
setTimer, msg_timer, off
toolTip, ; close
}
save_exit:
iniRead, saved_default, % a_lineFile, settings, default_script
if (default_script != saved_default)
iniWrite, % " " default_script, % a_lineFile, settings, default_script
exitApp
; menu actions =================================================================
set_as_default:
item_file := item_file(a_thisMenu)
try menu, tray, delete, % filename(default_script)
menu, tray, add, % item_file, script_reload_tray
menu, tray, default, % item_file
menu, tray, tip, % "reloadr (" item_file ")"
default_script := full_path(item_file)
msg_tool(item_file "`n`nset as default")
return
script_open: ; open list lines
winGet, hwnd, id, % item_file(a_thisMenu) " ahk_class AutoHotkey"
postMessage, 0x111, 65300, , , % "ahk_id " hwnd ; ID_TRAY_OPEN := 65300
return
script_help:
splitpath, a_ahkPath, , ahk_dir
run, % ahk_dir "\AutoHotkey.chm"
return
script_window_spy:
splitpath, a_ahkPath, , ahk_dir
run, % ahk_dir "\WindowSpy.ahk"
return
run_at_startup:
filename := item_file(a_thisMenu)
splitPath, filename, , , , name_no_ext
shortcut := a_startup "\" name_no_ext ".lnk"
ifExist, % shortcut
{
fileDelete, % shortcut
msg_tool("shortcut deleted")
}
else ; create shortcut
{
script_path := full_path(filename)
if isFunc("script_icon")
icon_path := icon_search(script_path)
fileCreateShortcut, % script_path, % shortcut, , , , % icon_path
msg_tool("shortcut created")
}
return
script_reload:
script_reload_tray:
if inStr(a_thisLabel, "tray")
{
filename := item_file(a_thisMenuItem)
script_path := default_script
}
else
{
filename := item_file(a_thisMenu)
script_path := full_path(filename)
}
if getKeyState("shift", "P")
{
winClose, % script_path " ahk_class AutoHotkey"
msg_tool(filename "`n`nclosed")
}
else
{
script_state(script_path, is_paused, is_suspended)
reload_script(script_path)
state := (is_paused) ? ", un-paused" : ""
state .= (is_suspended) ? ", un-suspended" : ""
msg_tool(filename "`n`nreloaded" . state)
}
return
script_edit:
run, % "edit " full_path(item_file(a_thisMenu)) ; open in the default note editor
return
script_compile:
script_path := full_path(item_file(a_thisMenu))
compile_this(script_path)
return
script_suspend:
filename := item_file(a_thisMenu)
postMessage, 0x111, 65305, , , % filename " - AutoHotkey"
script_state(filename, is_paused, is_suspended)
msg_tool((is_suspended) ? filename "`n`nsuspended" : filename "`n`nun-suspended")
return
script_pause:
filename := item_file(a_thisMenu)
postMessage, 0x111, 65306, , , % filename " - AutoHotkey"
script_state(filename, is_paused, is_suspended)
msg_tool((is_paused) ? filename "`n`npaused" : filename "`n`nun-paused")
return
script_exit:
filename := item_file(a_thisMenu)
winClose, % filename " ahk_class AutoHotkey"
msg_tool(filename "`n`nclosed")
return
run_shortcut:
filename := item_file(a_thisMenuItem)
splitPath, filename, , , , name_no_ext
shortcut := a_startup "\" name_no_ext ".lnk"
run, % shortcut
return
reload_startup_ahk: ; ahk only
reload_startup_folder: ; everything in the folder
msg_tool("startup refreshing . . . . ")
script_paths := running_scripts()
loop, files, % a_startup "\*.lnk"
{
fileGetShortcut, % a_loopFileFullPath, target
if (target = "")
continue
splitPath, % target, filename, , target_ext,
process, exist, % filename
this_PID = %errorLevel%
if (this_PID = 0) ; if the specified process did not appear within 5.5 seconds
{
if inStr(a_thisLabel, "_ahk") and (target_ext != "ahk")
continue
if inStr(script_paths, target) ; if the ahk script is already running
continue
run, % a_loopFileFullPath
msg_tool("starting: " a_loopFileName)
}
}
msg_tool("`nstartup reload complete")
return
change_sort_type:
if (sort_type = "recent")
{
sort_type := "alphabetical"
menu, %a_thisMenu%, unCheck, Sort By Recent
}
else ; if alphabetical
{
sort_type := "recent"
menu, %a_thisMenu%, check, Sort By Recent
}
iniRead, saved_value, % a_lineFile, settings, sort_by_recent
new_value := (sort_type = "recent") ? "true" : "false"
if (new_value != saved_value)
iniWrite, % " " new_value, % a_lineFile, settings, sort_by_recent
toolTip, % "sort type set to: " sort_type
sleep 600
reload
return
compile_all_scripts:
msgBox, 4, , % regExReplace(strReplace(a_thisLabel, "_icon"), "[\W_]", a_space) . "?"
ifMsgBox, yes
{
if (script_paths = "")
script_paths := running_scripts()
loop, parse, script_paths, `n
{
if (a_loopField)
compile_this(a_loopField)
}
msg_tool("compile all complete")
}
return
reload_all:
exit_all:
msgBox, 4, , % regExReplace(a_thisLabel, "[\W_]", a_space) . " Scripts?"
ifMsgBox, yes
{
if (script_paths = "")
script_paths := running_scripts()
if (a_thisLabel = "reload_all") and (sort_type = "recent")
{
loop, parse, script_paths, `n
temp_list := a_loopField "`n" temp_list ; reverse the order before reload
script_paths := temp_list
}
;# reload or close scripts
loop, parse, script_paths, `n
{
if (a_loopField = "") or (a_loopField = a_lineFile) ; skip this script
continue
if (a_thisLabel = "reload_all")
{
if (inStr(a_loopField, "\\.\pipe\AHK_")) ; skip piped
continue
run, % a_loopField " /restart"
}
else winClose, % a_loopField " ahk_class AutoHotkey"
msg_tool(filename(a_loopField) " . . . .")
sleep 90
}
;# reload or close this script
msg_tool("`n" strReplace(a_thisLabel, "_all") . " Complete")
sleep 300
if (a_thisLabel = "reload_all")
reload
else exitApp
}
return
compile_this(script_path) {
splitPath, script_path, filename, file_dir, file_ext, name_no_ext
if (file_ext = "ahk")
{
splitPath, a_ahkPath, , ahk_dir
ahk2exe := ahk_dir . "\Compiler\Ahk2Exe.exe"
; script icon
if isFunc("script_icon")
exe_icon := icon_search(script_path)
; compile
if (exe_icon)
run, "%ahk2exe%" /in "%script_path%" /icon "%exe_icon%", , hide
else run, "%ahk2exe%" /in "%script_path%", , hide
; wait until .exe is compiled
if inStr(a_thisLabel, "_All")
{
loop,
sleep 500
until (fileExist(file_dir "\" name_no_ext ".exe"))
or (a_index = 6) ; 3 seconds
or (winExist("Ahk2Exe Error ahk_exe Ahk2Exe.exe"))
}
msg_tool(filename "compiling . . . . ")
}
}
@davebrny
Copy link
Author

davebrny commented Nov 4, 2017

reloadr

reload running scripts from a context menu

reloadr menu

  • ctrl + shift + ` Β  (grave/backtick key) shows a list of running scripts
  • every script has the same options as the tray menu + the option to compile or create a startup shortcut
  • if a script is paused or suspended then a (p) or (s) will show on the right side of the menu
  • ctrl + ` reloads the default script
  • alt + ` reloads whatever script has been reloaded last (apart from the default)

options menu

  • sort the menu by recent or alphabetical
  • reload, exit or compile all running scripts
  • show which startup scripts are running. run them individually or all at once

menu icons

if script_icon() is in one of the function libraries then remove the comment in the icon_search() function to have icons show in the menu

limitations

this cant handle duplicate script names at the moment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment