Programmatically closing programs with hotkeys to AutoHotKey hidden scripts

I’ve been battling to get MaxLauncher buttons that run hotkeys. MaxLauncher is a program launcher that pops up on the screen and I looks like a keyboard. You can assign a file or folder to a key on the virtual keyboard. So if you want to send a hotkey, say Ctrl+W to a program, say Firefox, then you have to write a script file to make this happen.

Now these global hotkeys work with Stream Deck and with using a keyboard combination hotkeys even when in an active window of another program.

But I’ve had real difficulty getting it to work programmatically, that being running another script that will write keyboard hotkey presses that will then activate a function/action script of an actively run AutoHotKey script that is running in the Taskbar Tray.

AutoHotKey Hotkeys

With AutoHotKey you assign a hotkey in a script and you run the script and it runs as a background process in the windows environment. When you use the hotkey it calls and starts the function or part of script that you assigned to it. IIf the Hotkey activates a new webpage, this hotkey can be triggered even if you are in a different program, so the hotkey is available and assigned to that action and there is a listener in AutoHotKey that is running in the background and its triggered when that key combination is activated.

AutoHotKey can take over key combinations that may be assigned to other keys, so if the AutoHotKey script is not running that hotkey may do something different in a different program.

Eg in all office docs F1 is the help file, but AutoHotKey can have a script that assigns F1 to do a AutoHotKey script function that will run that AutoHotKey function until the script is stopped. It is global, unless you have either told it to only be activated in one specific program, or you have blacklisted a program so it works everywhere else apart from in that program.

Trying to write scripts to send hotkeys globally, not to active window

So, knowing what AutoHotKey hotkeys do, you’d think that writing a simple AutoHotKey script that did “SEND, ^W” would send that hotkey to the PC environment and activate whatever the hotkey function/action is to do.

I found it may have worked the first time or couple of times but then it stopped doing this. I tried in a number of ways using AutoHotKeys , Batch Files, Batch files in combination with VBA (in articles), Python & PowerShell.

Generally when I was just sending keystrokes to the PC none of these scripts worked after the first couple of times, if at all.

So global hotkeys do not seem to work. I need to delve into this a bit more.

Activating an exe program window to run the hotkey

The method that seems to work is by activating the window of the program that you want to send keystrokes to, then sending the keystrokes. So this is not a global hotkey but one specifically targeted to the program in which that hotkey works.

An example of this is the “CLOSE TAB” in Firefox. First activate the window, then uses ControlSend to target the active window.

WinActivate   , Mozilla Firefox						;activate Firefox     

SetKeyDelay, 10, 10   ; this seems important so typing not too fast, pause between each keystroke
ControlSend, ahk_parent, ^w	, ahk_class MozillaWindowClass    ;close tab

For some reason, if you just try send, ^W instead of closing the active tab, it tries closing them all and closing Firefox

So this works fine in an Exe file, it targets the program and the class to activate the window and then send the hotkey to.

Activating a .ahk script with hidden window to run the hotkey

But the above doesn’t happen with AutoHotKey scripts that are uncompiled (ie not .exe).

One issue is that the .ahk script is hidden in the task tray, it does not have a window that can be opened , eg like Firefox to look at. You could open the script in Notepad++ to look at it but that active window would be a Notepad++ window.

AutoHotKey scripts sitting in Task Tray

The 2nd issue is that the windows process just calls all the AutoHotKey scripts “AutoHotKey” processes. They have different process Id’s (PID) but are all identified as “AutoHotKey” processes, so you cannot target them by their winTitle – see image below

winTitle of script above is AutoCorrect.ahk

Processes in Windows

Inside windows, when you activate a program it goes into the list of active processes. You can see the programs in your Task Manager (Ctrl+Alt + Del)

As you see there are 3 instances of AutoHotKey running but we cannot get any information on which script is which, all we know is that they each have a different PID.

Now I’ve started a AHK compiled script called Time Capture++.exe

Time CaptureNotepad++.exe , a compiled AHK script

And if we go into Code Terminal and run >get-process this will give a list of all the active processes and we can see that the compiled script title is showing for TimeCapture++, so we can, in a ahk script add

winAcivate, TimeCapture++

This will activate the TimeCapture++ program so we can send keystrokes to it programmatically.

But we cannot do that with the uncompiled scripts as we have no WinTitle to activate.

This is the issue with the processes in Windws, if you look at the VS Code list in the Task Managers Detail tab, you see lots of instanses of code that are only differentiated by their PID.

ProcessID’s

Process ID’s (PID’s) are give to programs when they start up in Windows, so that they have a unique identifier and can be called by their PID’s.

If you close ab instance of a program down and then start it again, it will be allocated a different PID. So the PID changes each time you start it.

So how do you find what the CURRENT PID is for a specific program? or script?

In PowerShell you can use the command >get-process and this will, as seen above, make a list of all the active processes running, so for TimeCapture++.exe it is PID=9192, if there are multiple PID’s then you have to loop through all the instances to find the one you want.

For AutoHotKey scripts, they are all bunched under AutoHotKey for the process name, but inside AutoHotKey code there is a function WinGet, id, List, %ProcName% that can get the PID from the Script title. So we can loop through all the active AutoHotKey active processes until we find one that matches the Script title we have and then return the PID of that specific script.

In the script below we then tell that process to close and exit the script.

DetectHiddenWindows, ON
SetTitleMatchMode, 2

;find the script that you want to close
ProcName = AHKCommandPicker.ahk  

;get the id of the script
WinGet, id, List, %ProcName% 

;find the PID of the script (this is the new active process)
; each time a new instance is started it has  a different PID
Loop, %id%
{
    this_id := id%A_Index%
    WinActivate, ahk_id %this_id%
    WinGet, PID, PID, ahk_id %this_id%    
}

;Use the PID as the ID of the instance  and close it
  Process, Close,  %PID%
 
exitapp

Note that in the above script there is a ahk function DetectHiddenWindows, ON set to on so that it can detect scripts in the tray that may not have an active window that can display on the screen.

So now that we have found the specific PID we can now send a hotkey to that specific script programmatically so that it will activate the function/action of that hotkey in the targeted script.

DetectHiddenWindows, ON
;SetTitleMatchMode, 2

;find the script that you want to close
ProcName = AutoCorrect.ahk 

;get the id of the script
WinGet, id, List, %ProcName% 

;find the PID of the script (this is the new active process)
; each time a new instance is started it has  a different PID
Loop, %id%
{
    this_id := id%A_Index%
    WinActivate, ahk_id %this_id%
    WinGet, PID, PID, ahk_id %this_id%    
}

;after finding the PID activate the window with:
WinActivate, ahk_id %PID%

;Use the PID as the ID of the instance  and send a Hotkey to it to activate , in the case below a pop-up window to add a new hotstring
Send,  ^!5	

Other programs to find Process Names

In the case above we uses AutoHotKey to find a PID for a specific AutoHotKey script that was in the Task Tray and had a hidden window.

From the list of running processes in the Task Manager Detail Image above you can see that VS Code has multiple processes running but no name for each process, so there must be a method to find out which script is associated with a specific PID.

So there must be methods/functions in BATCH, PowerShell & Python to do this too. I may need to investigate later in some of these programs, especially when I move away from calling HotKeys in AHK scripts.

Simplifying AHK send keys to scripts & Winkey #

I’ve been messingh with trying to find PID’s for AutoHotKey scripts to send keys to and having problems with the keys not activating part of the scripts.

It seems the # (Winkey) is not liked . I’ve been trying send, controlsend to the ID. to the script title and all sorts of combinations. In the end, altering the # to ^! or ^+ sorts it all out, so new simpler way is :

DetectHiddenWindows, ON
 
WinActivate   , AutoCorrect.ahk						;activate script 
send, ^+5
ExitApp

And it even seems to work fine without the DetectHiddenWindows, ON

That was an hour and a half doing all sorts of testing, it looks so trivial at the end!!!

End comment

I have NOT been successful in being able to send programmatically a GLOBAL Hotkey that works consistently. I saw that inside RPA BluePrism there is a function that allows this at global level.

At the moment I’m able to target the specific scripts and run a hotkey inside of them and activate the function/action that I want. I can also do this inside Firefox too, which is the one that started this all off.

I suppose, one solution would be to compile the AHK scripts to EXE files then they would be easier to target with WinActivate, but I like my scripts in Script form so that I can play around and adjust them. I do do tweeks to my Email Tap and AutoCorrect quite often and even compiled scripts like TimeCapture & FileSaveLaunch I want to edit as I go. Its more convenient with a script as you don’t need to do the extra step of compiling it over and over after each tweek.

I feel I have a better understanding of the interaction of the programs in the windows environment, but there is a lot I still don’t understand.

At some point I’ll be moving away from AHK scripts and trying to do email interactions, most probably in Thunderbird Email. Since I’ve had success with AHK I may be sticking with that, but it may be worthwhile trying some of the other programs too. Whatever works.

I wanted to write this process down as I’ve been flumoxed by it for almost a week now and have not been able to be clear about the steps I’ve taken or the lack of understanding of why my testing has failed as I’ve gone along. I’m still confused but at least I’ve documented my steps so far.

I’ve been trying to do a video and have been waffling a lot around the topic and going off on tangents, so its good to talk it out as it makes you realise you don’t have an understanding on the issue if you ramble. So it makes you step back and re-assess the issue so you have it clearer in your own mind so you can explain it more clearly to others.

Video