PowerShellでキー入力の自動化

stenretniです。インフルエンザと花粉症でなかなかマスクをはずすタイミングがつかめません。

stenretniはAutoHotkeyなどでキー入力を自動化するのが好きなのですが、触るPC全てにこのソフトを入れるわけにもいきません。Windows標準での手段をここ数年探していたのですが、最近PowerShellから.NETのメソッドが一通り呼びだせることに気がつきました。.NETにはSendKeysという人間と同様のキー入力をしてくれる命令があるので、これを使えば(少なくともWindows 7なら)ダブルクリックをするとキーボード入力が走るバッチが書けます。

以下はメモ帳を使った例です。

@powershell -NoProfile -ExecutionPolicy Unrestricted "&([ScriptBlock]::Create((cat -encoding utf8 \"%~f0\" | ? {$_.ReadCount -gt 2}) -join \"`n\"))" %*
@exit /b
# ↑ PowerShellスクリプトをbatにラッピングするためのおまじない

# SendKeysを使えるようにする
add-type -AssemblyName System.Windows.Forms

# 前面にあるウィンドウにキーボード入力を送る
function send([string]$key)
{
  [System.Windows.Forms.SendKeys]::SendWait($key)
  sleep 0.5
}

start notepad
sleep 1
send "Hello, world!"

実用するには、キー入力が望むウィンドウに送られることが大事です。そのため、ウィンドウを切り替えたりウィンドウが切り替わるのを待機したりしたいことがあります。これにはVisualBasicのAppActivate命令が使えます。

(他にもMicrosoft.VisualBasic.Interactionには便利そうなメソッドがいくつかあります)

add-type -AssemblyName Microsoft.VisualBasic

# 指定のタイトルのウィンドウを探して、前面に持ってくる
function activate_window([string]$title)
{
  [Microsoft.VisualBasic.Interaction]::AppActivate($title)
}

# 指定のプロセス名のタイトルを取得
function get_process_window_title([string]$process_name)
{
  return [string](Get-Process $process_name | select MainWindowTitle)
}

# 指定のプロセス名のタイトルに指定の文字列が含まれるか調べる
function title_contains([string]$process_name, [string]$title)
{
  $got = get_process_window_title($process_name)
  return ([bool]$got) -and $got.Contains($title)
}

# 指定のプロセスのメインウィンドウのタイトルが指定のものになるまで待つ
function wait_while_window([string]$process_name, [string]$title)
{
  while (title_contains($process_name, $title))
  {
    sleep 0.25
  }
}

# 指定のプロセスのメインウィンドウのタイトルが指定のものでなくなるのを待つ
function wait_until_window([string]$process_name, [string]$title)
{
  while (!(title_contains($process_name, $title)))
  {
    sleep 0.25
  }
}

Leave a Reply