AutoHotkey Tip of the Week: Quick Menu for Activating Open Windows

With a Few Modifications, the WindowList.ahk Script Pops Up a Menu of Open Windows for Quick Activation—Plus, How to Detect When a Windows Opens or Closes

I originally used the WindowList.ahk script as a demonstration of how to use the GUI DropDownList control as a list of selection options for activating open windows (included in the Digging Deeper Into AutoHotkey book). Once, while testing someone’s script, it proved very useful. I could not find the GUI window generated by the code. The script had placed the target window somewhere off the screen. The scriptwriter originally used a second monitor—which I didn’t have. The WindowList.ahk script moved the window back into my view.

As I reviewed the script, I realized that building a pop-up menu of open windows could serve a purpose similar to the QuickLinks.ahk script—except, rather than launching apps and Web sites, the menu would activate open windows. Now, that’s something that I can use!

I often keep numerous windows open simultaneously. Generally, I locate a window by hovering over the Windows Taskbar then selecting the image which looks right. It takes a second for the thumbnails to appear, then hovering over each helps me make my selection. But what if I could maintain a menu of all open Windows available in a menu for instant activation?

The WinGet, List Command

The WindowList.ahk script uses the WinGet, OutputVar, List command to build a list of all open windows—modeled after WinGet, …, List example found in the online AutoHotkey documentation. After screening out certain systems windows:

If (Title != "" and Class != "BasicWindow" and Title != "Start"
    and Title != "Program Manager")

the command captures the Process ID (or windows handle—Hwnd) of the open windows in the order they appear on the Windows Desktop (from top to bottom).

Window List Menu
Select from the WindowList menu to activate the open window.

While the original script built a GUI DropDownList, I easily added the pop-up Menu commands to the Loop. The new WindowListMenu.ahk script creates both the new pop-up menu and the original GUI DropDownList—each displaying a list of open windows for quick access and navigation. When launched, AutoHotkey scans the open windows and builds the activation menu from that list. The menu appears in most-recently-used order from topmost down.

While I added a Rescan Windows option to the top of the menu for manual updating, I didn’t want the one or two-second delay caused by rebuilding the menu. I felt that updating the menu in the background whenever a window opened or closed would provide a good solution. However, AutoHotkey needed to recognize when a new window opens or an old window closes. I found a technique for detecting new windows in the old AutoHotkey forums (as discussed below).

Although this script continues to build a GUI with a DropDownList similar to the original WindowList.ahk script, I find using a GUI window more cumbersome than the pop-up menu. If you don’t want or need the GUI DropDownList, then you can comment out or remove that code.

Use Ctrl+Alt+W, Ctrl+Win+M, or XButton2 (if available) to open the menu. (You may need to assign one of the menu opening Hotkeys to XButton2 in your mouse setup app.) Use Ctrl+Win+L to open the GUI window.

I used a number of tricks while putting together this script:

  1.  I included the Process IDs in the menu items to ensure unique menu item names. Otherwise, similar menu items (e.g. multiple blank Notepad windows) would only open the topmost window.
  2. On selection, the script parses the Process ID from the menu item name (ProcessID := StrSplit(A_ThisMenuItem,”—”)) and uses it to activate the correct window. Note: I use an em dash ( — ) (as opposed to the hyphen) as the delimiter since it’s unlikely to appear in a window title.
  3. I added the Menu, MenuName, UseErrorLevel command to prevent Menu command errors from breaking the script (e.g. the no icon found error).
  4. I used the Menu, WindowMenu, Delete command rather than the Menu, WindowMenu, DeleteAll command to remove the old menu before updates since DeleteAll does not remove excess menu width caused by long, previously-open window titles.
  5. For my XButton2 mouse button to work, I needed to configure my mouse settings app to call one of the Menu, WindowMenu, Show Hotkeys. (See Chapter Twenty-one, ” Multiple Hotkeys and Using The Extra Mouse Buttons” in the AutoHotkey Hotkey Techniques book.)
  6. The GUI DropDownList subroutine includes code for moving an out-of-view window back onto the screen. If you want the same capability in the menu, then copy the following code into the appropriate spot (after window activation) in the script:
    WinGetPos,X1,Y1,W1,H1,Program Manager
    WinGetPos,X2,Y2,W2,H2,% "ahk_id " ProcessID[2]
    If (X2 > W1 or Y2 > H1)
      WinMove, % "ahk_id " ProcessID[2],, 20, 20
  7. Don’t set DetectHiddenWindows, On. It overwhelms the list with hidden systems windows that you can’t access.

For now, I’ll concentrate on how to sense opening and closing windows to keep the menu updated in realtime.

Detecting When Windows Open and Close Windows

In working with both QuickLinks.ahk and this new script, I’ve noticed that menus can take a little time to update. Ideally, when I hit the Hotstring combination or activating mouse click (XButton2 in the case of WindowListMenu.ahk), the menu instantly pops open. I could prompt the menu to update each time I open it but waiting for the menu to update can take a second or two. Who wants to wait?

Preferably, the WindowList menu updates in the background when a window opens or closes. Then, when I need to access the menu, one click makes it instantly appear. But to accomplish this background activity, AutoHotkey must catch whenever a window opens or closes.

I found the following “Detect When a New Window Is Opened” routine in an answer by the forum user SKAN on the old AutoHotkey Forum. You can run this snippet directly to see how it works. I made a couple of modifications to detect both opening and closing windows:

#Persistent
Gui +LastFound
hWnd := WinExist()

DllCall( "RegisterShellHookWindow", UInt,hWnd )
MsgNum := DllCall( "RegisterWindowMessage", "Str","SHELLHOOK" )
OnMessage( MsgNum, "ShellMessage" )
Return

ShellMessage( wParam,lParam ) 
{
  If ( wParam = 1 ) or (wParam = 2) ; HSHELL_WINDOWCREATED := 1
  {
    WinGetTitle, Title, ahk_id %lParam%
    WinGetClass, Class, ahk_id %lParam%
    Switch wParam
    {
      Case 1:
        TrayTip, New Window Opened, Title:`t%Title%`nClass:`t%Class%
      Case 2:
        TrayTip, Window Closed, Title:`t%Title%`nClass:`t%Class%
    }
  }
}

Note: If you run the above code then begin opening and closing windows, you’ll see that Windows sends additional signals a little more often than expected or needed. I think hidden windows or other system actions cause these messages but, since they occur in the background, they don’t seem to cause a problem for the script except that occasionally I’ve found the menu in the middle of an update when I accessed it. (It would be nice to find code that would limit the response to only my open application’s windows. I haven’t found it yet.)

I often find and implement snippets using DllCall() and/or OnMessage() As long as they work, I rarely dig into all the details. I haven’t completely traced out the specifics of how the inner workings and hidden mechanisms of this code do the job, but by changing the results in the ShellMessage() function (in red) and adding it to the script I can now launch the Rescan Windows subroutine on every detected change. The menu updates in the background leaving a static menu that pops up instantly when I click my XButton2.

*          *          *

Library Benefits

For more examples of DllCall() and OnMessage(), see:

  • Chapter Thirty-two, “Changing Mouse Cursor Speed with AutoHotkey API Calls Slowing Down Mouse Cursor Movement with DllCall()” plus, the OnMessage() command function in Digging Deeper into AutoHotkey
  • Chapter Thirty-six: “Adding Color to ListView Rows (A_GuiEvent)—While a little more advanced, this AutoHotkey technique controls the font and background colors of ListView rows.” Using AutoHotkey commands and functions such as DllCall(), SendMessage, and OnMessage, an advanced technique for adding color to AutoHotkey ListView rows is used to enhance the To-Do List script in AutoHotkey Applications.
  • Chapter Thirty-three: Adding a Help Window to the AutoHotkey Reminder Script (OnMessage to monitor the Windows WM_HELP message (0x53))—in AutoHotkey Applications.
  • Chapter 13.1.5 “Optimizing the AutoHotkey Message Box” in Jack’s Motley Assortment of AutoHotkey Tips
  • Plus, a number of blogs using these functions including “Waiting for a Web Page to Load into a Browser AutoHotkey Tips.” (Search this site, “Jack’s AutoHotkey Blog”, using the function name.)

*          *          *

This WindowList menu operates so much faster than any of the alternative approaches to finding and activating open windows that I already find myself accessing it regularly.

Click the Follow button at the top of the sidebar on the right of this page for e-mail notification of new blogs. (If you’re reading this on a tablet or your phone, then you must scroll all the way to the end of the blog—pass any comments—to find the Follow button.)

jack

This post was proofread by Grammarly
(Any other mistakes are all mine.)

(Full disclosure: If you sign up for a free Grammarly account, I get 20¢. I use the spelling/grammar checking service all the time, but, then again, I write a lot more than most people. I recommend Grammarly because it works and it’s free.)

 

 

 

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s