3

Question

I'd like AutoHotkey to automatically detect when a certain pop-up dialog appears and take certain actions. How do I do that?

Concrete example

In my particular case, I'd like AutoHotkey to close the Update Table of Contents dialog Word displays when I want to update the table of contents.

This is the workflow:

  1. I update the titles in my Word document
  2. I press Ctrl+A to select the whole document
  3. I press F9 to update all fields
  4. This annoying modal dialog appears (which can't be configured away according to my Google searches) enter image description here

  5. Now, I need to press Arrow down to select Update entire table followed by Enter to press Ok and continue

I'd like AutoHotkey to automatically issue the Arrow down, Enter command because the above described workflow is something I perform a dozen times a day.

Of course, because I initiate the workflow, I could just write a AutoHotkey script that does the whole thing for me starting with Ctrl+A like this:

#IfWinActive ahk_class OpusApp
F9::
Send, ^a
Send, {F9}
Sleep, 200
Send, {Down}
Send, {Enter}
return

However, the above example is just for illustration purposes, and there are cases when pop-up dialogs appear at random and I'd like AutoHotkey perform some action depending on the pop-up dialog's title.

My research so far

  • Some Internet sources suggest to use a AutoHotkey loop that indefinitely loops and checks, say every second, whether a window with a certain title exists and then closes it. But I find that to be a waste of CPU resources
  • Some other Internet sources mention a shell hook along with a code snippet, and I think that's the way to go, but I don't understand the code snippet; could anyone explain how it works and give an understandable example provided this was the solution?

The following code snippet is copied from here.

SetBatchLines, -1
Process, Priority,, High


Gui +LastFound
hWnd := WinExist()


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


ShellMessage( wParam,lParam ) {
  If ( wParam = 32772 or WParam = 4) ;  HSHELL_WINDOWACTIVATED := 4 or 32772
       WinGetActiveTitle, Title
  If  ( Title = "sun 4 - foxtrot - Remote Desktop Connection" ) 
        SetCapsLockState, on
    else SetCapsLockState, off
}

I see the

If (Title = "sun 4 - foxtrot - Remote Desktop Connection") 

part. What what does the whole rest do?

0

You're going deep. Having a program monitor for a given window name isn't much of a tax on system resources. That's probably the way to go.

ShellMessage could be any name of your choosing, because it is the function called by OnMessage, which is what is triggered when your script receives a message. The contents of this function should be your code to make sure you're in the right window and to then issue the commands you want sent. Your function can accept up to four parameters, as defined in the help file for OnMessage.

The DllCall lines are the arcane bit that tie into Windows to get messages from the system. This is where you should know what you're doing if you're going to mess with hooding into Windows.

SetBatchLines, -1 and Process, Priority,, High say that your script is super important and should run full-speed all the time and no other system process should ever slow it down.

Gui +LastFound and hWnd := WinExist() are finding the unique ID of this script when it is running so that it can be registered with Windows in the subsequent DllCall.

0

For efficient code that doesn't poll and is more responsive you can adapt the code here:

http://www.autohotkey.com/board/topic/84397-winwait-framework-do-something-to-a-window-when-it-appears/

In the setup part of the file add these statements:

Update Table of Contents ahk_exe WINWORD.EXE    B       WordTOCupdate
Update Table of Figures ahk_exe WINWORD.EXE     B       WordTOCupdate

Make sure there are tabs between the columns in this setup part of the script (and not spaces, depending on the editor you're using). The exe name is also case sensitive since it uses RegEx matching unless you change it.

Then this code goes down in the body of the script...

;-------------------------------------------------------
; Check for Microsoft Word Update Table of Contents
;-------------------------------------------------------
WordTOCupdate:
    WinActivate             ;Set Window to Be on top
    SendInput !e{Enter}
return

You could also use the snippet you posted... it's basically the same thing.

Gui +LastFound
hWnd := WinExist()


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


ShellMessage( wParam,lParam ) {
  If ( wParam = 32772 or WParam = 4) ;  HSHELL_WINDOWACTIVATED := 4 or 32772
       WinGetActiveTitle, Title
  If  (Title="Update Table of Contents" ) 
  {
       SendInput !e{Enter}   
  }
} 

The !e sends Alt+e to update the entire table.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.