我正在更新一些需要将焦点切换到应用程序的脚本,发送一些键击,然后将焦点返回到另一个应用程序。
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
我研究了对这些脚本的一些改进,我希望做的一件事是删除Sleep
语句以加速脚本的执行。在研究这个时,我发现建议您在继续之前检查AppActivate
的返回值,以便有效地使脚本等到应用程序具有焦点并且可以发送击键。
我尝试更新我的脚本来执行此操作 -
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
然而,键盘似乎只在焦点返回到AnotherApplication后才发送。
有没有办法做到这一点,以确保AnApplication在发送击键时有焦点,而不使用Sleep?
答案 0 :(得分:3)
正如我在评论中提到的,没有必要将AppActivate()
置于循环中。这是一个同步调用,该函数不应该返回,直到它激活窗口(或尝试失败)。
如果您担心窗口失去焦点,可以在发送几次击键后再次拨打AppActivate()
,或者在每次键击之前调用它。
例如:
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
答案 1 :(得分:0)
这对我帮助很大,但我发现我需要添加少量时间让操作系统实际关注该窗口,因此我在WScript.Sleep 100
之间添加了AppActivate
和SendKeys
行。
哪个工作得很好,直到我意识到在某些情况下我的某些进程在脚本被调用之前已经退出,导致我的键击被发送到错误的窗口。请注意,问题是Shell.AppActivate
将发送命令以通过它的PID激活程序,但是没有什么可以检查该程序是否已退出。所以,我添加了另一个子查询活动PID的winmgmts(以及CommandLine,因为每个进程都被唯一地调用)。
这是我的贡献,最深切的谢意:
'================
Sub DelayedSendKeysWithFocusAndProcessCheck(str, procid, cmdline)
Call ProcCheck(procid, cmdline)
Shell.AppActivate procid
WScript.Sleep 100
Shell.SendKeys str
End Sub
'================
Sub ProcCheck(procid, cmdline)
CheckedPID = ""
CheckedCmdLine = ""
Set ProcessCollection = GetObject("winmgmts:\\" & ComputerName & "\roo" &_
"t\cimv2")
Set ProcessResults = ProcessCollection.ExecQuery(" Select * from Win32_Pr" &_
"ocess where ProcessID = '" & procid & "'")
For Each obj in ProcessResults
CheckedPID = obj.ProcessID
CheckedCmdLine = obj.CommandLine
Next
If CheckedPID <> procid Then
Shell.Popup "PID " & procid & " (" & cmdline & ") appears to have exite" &_
"d!", 0, "Called Process is Missing!", vbOkOnly
Call EndScript
Else
Call RegExSearch(cmdline, CheckedCmdLine)
If ReturnValue(0) <> "" Then
Shell.Popup "The PID " & procid & " no longer shows the same command " &_
"line I started it with!" & vbcrlf & "When I started it, it used " & vbcrlf &_
cmdline & vbcrlf & "Now it shows " & CheckedCmdLine & "I'm going to exit no" &_
"w. You can try to run me again or simply open the windows manually." & vbcrlf &_
"(Please note that this is an incredibly rare error and you should probabl" &_
"y buy a lottery ticket.)", 0, "Called process command line has changed!", vbOkOnly
Call EndScript
End If
End If
End Sub
'================