如何在powershell脚本中按一个键一秒钟?

art*_*221 4 powershell

我有一个 powershell 脚本:

$i = 0
$delay = 1000
while($i -eq 0)
{
$myshell = New-Object -com "Wscript.Shell"
$myshell.sendkeys("q")
Start-Sleep -m $delay
}
Run Code Online (Sandbox Code Playgroud)

它可以工作,但我不想只发送一会儿按键,而是想模拟按下一个按键一段时间,例如 1 秒。

pos*_*ote 5

要使用 sendkeys 将多个击键发送到任何内容,您可以这样做(实际上不需要 WScript 的东西):

Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait('q'*3)
# Results
<#
qqq
#>
Run Code Online (Sandbox Code Playgroud)

如果您尝试针对时间状态执行此操作,那么您需要提供该时间状态。所以,这意味着设置一个秒表。

https://duckduckgo.com/?q=%27powershell+using+a+timer%27&t=h_&ia=web

带有表单的计时器示例:

Add-Type -AssemblyName  Microsoft.VisualBasic,
                        PresentationCore,
                        PresentationFramework,
                        System.Drawing,
                        System.Windows.Forms,
                        WindowsBase,
                        WindowsFormsIntegration

$delay = 10
$Counter_Form = New-Object System.Windows.Forms.Form
$Counter_Form.Text = "Countdown Timer!"
$Counter_Form.Width = 450
$Counter_Form.Height = 200
$Counter_Label = New-Object System.Windows.Forms.Label
$Counter_Label.AutoSize = $true 
$Counter_Form.Controls.Add($Counter_Label)
while ($delay -ge 0)
{
  $Counter_Form.Show()
  $Counter_Label.Text = "Seconds Remaining: $($delay)"
  start-sleep 1
  $delay -= 1
}
$Counter_Form.Close()
Run Code Online (Sandbox Code Playgroud)

使用计时器对象,一个简短的例子:

$Timer = New-Object system.diagnostics.stopwatch
$Timer.Start()
Start-Sleep -Milliseconds 1001
$Timer.Stop()
$timer
# Results
<#
IsRunning Elapsed          ElapsedMilliseconds ElapsedTicks
--------- -------          ------------------- ------------
    False 00:00:01.0055471                1005     10055471
#>
Run Code Online (Sandbox Code Playgroud)

所以,你最终会使用你的代码来完成上面的操作。

Add-Type -AssemblyName System.Windows.Forms
$Timer = New-Object system.diagnostics.stopwatch
$Timer.Start()
while ($Timer.ElapsedMilliseconds -le 1000)
{[System.Windows.Forms.SendKeys]::SendWait('q')}
# Results
<#
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
#>
Run Code Online (Sandbox Code Playgroud)

使用延迟/睡眠

Add-Type -AssemblyName System.Windows.Forms
$Timer = New-Object system.diagnostics.stopwatch
$Timer.Start()
while ($Timer.ElapsedMilliseconds -le 1000)
{
    Start-Sleep -Milliseconds 100
    [System.Windows.Forms.SendKeys]::SendWait('q')
}
# Results
<#
qqqqqqq
#>
Run Code Online (Sandbox Code Playgroud)

根据SilBee's评论更新:

对任何按键执行操作。

Add-Type -AssemblyName System.Windows.Forms
$Timer = New-Object system.diagnostics.stopwatch
$Timer.Start()
while ($Timer.ElapsedMilliseconds -le 1000)
{
    $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | OUT-NULL
    [System.Windows.Forms.SendKeys]::SendWait('q')
    Start-Sleep -Milliseconds 100
}
'Done'
$Timer
# Results
<#
Done

IsRunning Elapsed          ElapsedMilliseconds ElapsedTicks
--------- -------          ------------------- ------------
     True 00:00:02.0041171                2004     20041490


 q
#>
Run Code Online (Sandbox Code Playgroud)

如果您仅在特定键之后,那么 $Host 对象仍然提供该键。

$Host.UI.RawUI.ReadKey()
# Results
<#
q
VirtualKeyCode Character ControlKeyState KeyDown
-------------- --------- --------------- -------
            81         q       NumLockOn    True
#>
Run Code Online (Sandbox Code Playgroud)

因此,您可以为特定字母进行编码,然后分支到您选择的任何其他代码。

一个粗略的例子可能是这样的:

Add-Type -AssemblyName System.Windows.Forms
$Timer = New-Object system.diagnostics.stopwatch
$Timer.Start()
while (($Host.UI.RawUI.ReadKey()).Character -eq 'q')
{
    [System.Windows.Forms.SendKeys]::SendWait('q')
    Start-Sleep -Milliseconds 100

    If ($Timer.ElapsedMilliseconds -ge 5000)
    {Break}
}
'Done'
$Timer
# Results
<#
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqDone

IsRunning Elapsed          ElapsedMilliseconds ElapsedTicks
--------- -------          ------------------- ------------
     True 00:00:05.0420154                5042     50420519
#>
Run Code Online (Sandbox Code Playgroud)

再次强调,上面是用户触摸键盘,而不是模拟事件。

尝试模拟这种情况可能会导致 SendKeys 出现奇怪的结果/行为,而无需进行大量微调并涉及对 user32.dll 的潜在调用。

必须记住,按住是键盘设备的机械动作(通过键盘驱动程序向操作系统发出信号)。内存中没有这样的东西,所有代码都是在内存中触发的。