How can I ensure my application retains focus while SendKeys is called? (Is there a better way than using Sleep?)

10,947

As I mentioned in my comment, there's no need to put AppActivate() in a loop. It's a synchronous call and the function shouldn't return until it's activated the window (or failed trying).

If you're concerned about your window losing focus, you can call AppActivate() again after sending a few keystrokes or you can call it before every set of keystrokes.

For example:

If Not MySendKeys("AnApplication", "%{I}") Then MsgBox "Could not send %{I}"
If Not MySendKeys("AnApplication", "{End}") Then MsgBox "Could not send {End}"

Function MySendKeys(strApp, strKeys)
    If objShell.AppActivate(strApp) Then
        objShell.SendKeys strKeys
        MySendKeys = True
    End If
End Function
Share:
10,947
Eilidh
Author by

Eilidh

Intensely curious language-agnostic.

Updated on June 15, 2022

Comments

  • Eilidh
    Eilidh 8 months

    I am updating some scripts which need to switch focus to an application, send some keystrokes, before returning focus to another application.

    Option Explicit
    
    dim objShell 
    set objShell = WScript.CreateObject("WScript.Shell") 
    
    objShell.AppActivate "AnApplication"
    WScript.Sleep 1000 
    
    objShell.SendKeys("%{I}")
    ...
    objShell.SendKeys("{END}") 
    
    WScript.Sleep 1000
    objShell.AppActivate "AnotherApplication"
    
    Set objShell = Nothing
    

    I researched some improvements to make to these scripts, and one thing I wished to do was to remove the Sleep statements to speed up the execution of the scripts. In researching this, I found that it's suggested that you check the return value of AppActivate before continuing, to effectively make the script wait until the application has focus and can be sent keystrokes.

    I tried updating my script to do this -

    Option Explicit
    
    dim objShell 
    set objShell = WScript.CreateObject("WScript.Shell")
    
    While Not objShell.AppActivate "AnApplication" 
        Sleep 300
    Wend 
    
    objShell.SendKeys("%{I}")
    ...
    objShell.SendKeys("{END}")
    
    While Not objShell.AppActivate "AnotherApplication"
        Sleep 300
    Wend 
    

    However the keystrokes seem to only send after focus has been returned to AnotherApplication.

    Is there a way to do this to ensure that AnApplication has focus while the keystrokes are sent, without using Sleep?