How Do I Press a Key for One Second in Powershell Script?

How Do I Press a Key for One Second in Powershell Script?

I have a powershell script:

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

It works but instead of sending a key only for a moment, I want to simulate pressing a key for a while, e.g. 1 second.

3

1 Answer

To send multiple keystrokes to whatever with sendkeys, you can just do this ( no real need for the WScript stuff):

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

If you are trying to do this against a time state, then you need to provide that. So, that means setting up a stopwatch.

An example of a timer with a form:

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()

Using a timer object, a short example:

$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
#>

So, you end up going down the above, with your code.

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
#>

Using a delay/sleep

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
#>

Update based on SilBee's comment:

Taking action on any keypress.

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
#>

If you are only after a specific key, then the $Host object still provides that.

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

Thus you can code for a specific letter, then branch to whatever other code you choose.

A rough example, could be something like this:

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
#>

Again, the above is a user touching the keyboard, not a simulated event.

Trying to simulate that can/will lead to odd results/behavior with SendKeys, without a lot of fine-tuning and involving potentially calls to user32.dll.

It must be remembered, that press and hold is a mechanical action of the keyboard device (signal to the OS via the keyboard driver). There is no such thing in memory, which is where all code is fired.

4

Your Answer

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

Elena Rostova
Author

Elena Rostova

Elena Rostova holds a Master's degree in Public Health Journalism. She covers groundbreaking medical research, holistic wellness trends, mental health awareness, and nutritional science.