経緯
仕事で使うメッセンジャーツールで毎回同じメンバーのグループを作る必要があるのですが、
そのツールが提供する設定やらコマンドやらでは、その操作を自動化できそうになかったので、
しょうがなくSendKeys操作でやることにしました。
せっかくの機会なので、こういう場面で自動化しやすくするためにPowerShellの関数を作り、
その過程で得た知識の備忘録として記載。
SendKeysとは
・キーストローク(打鍵、キーを押すこと)によってキーに対応した情報をアプリに送ること。
また、キーストローク単体でSendKeysと同じ意味で使われることもある。
・自動化するにあたっての最終手段です。(妥協策)
メリット
・Windowsの標準ツールで実装、および、利用することができる。
(.NETやWSHの環境で動作できるため。他はよく知りません...)
・他のアプリのCUIコマンドやAPIを覚える必要がないので、学習コストが少ない。
デメリット
・SendKeysによる処理が実行中の間は他の操作ができない。
(フォーカスが変更されるので意図しない結果になってしまう)
キーの表記方法
キー | コードのサンプル ※()内は補足説明 |
---|---|
英数字記号 | "a", "123", "!", " "(Space) |
アクション | "{BS}", "{DEL}", "~"(Enter), "{LEFT}"(左矢印), "{F4}" |
制御 | "^"(Ctrlキー), "+"(Shiftキー), "%"(Altキー) ※1 |
エスケープ | "{^}"(^), "{{}{}}"({}) |
複数指定 | "^(ac)"(Ctrl+Aで全選択したのちCtrl+Cでコピー) |
ループ | "{a 5}"(aaaaa) ※2 |
※1 日本特有のキー(半角/全角、変換)やWindowsロゴキー、アプリケーションキーは利用できない。 | |
※2 1つのキーに対して指定できる。 | |
コードの一覧についてはこちらのドキュメントを参照してください。 | |
SendKeys メソッド |
実装における注意点
・フォーカス(SendKeys操作の対象)
普段、キーで操作しているときと同様、前面に操作したいアプリを配置すること。
→自動化処理のはじめにアプリを起動するか、もしくは、すでに起動中のアプリを前面にする。
・Wait
→アプリがキーストロークして反応できる状態まで待つ必要がある。
→ウィンドウのフォーカスだけではなく、ウィンドウ内のどこにフォーカスがくるのかも気にすること。
→マシンの性能によっては、Wait時間を調整する必要が出てくる。
・その他
→ショートカットキーについては事前に知っておくこと。
PowerShellでの実装
動作環境
・Windows10
・PowerShell 5.1
Add-Type -AssemblyName Microsoft.VisualBasic
Add-Type -AssemblyName System.Windows.Forms
<#
.Synopsis
実行中の任意のプロセスにキーストロークを送る操作をします。
.DESCRIPTION
パラメータのキーストローク、プロセス名がそれぞれ未指定の場合、何も実行されません。
キーストロークのみが指定された場合は実行時のフォーカスへキーストロークを送り、
プロセス名のみが指定された場合はフォーカスのみが指定されたプロセスに変更します。
.EXAMPLE
Send-Keys -KeyStroke "test.%~" -ProcessName "LINE"
このコマンドは既に起動中のLINEアプリに対して"test."と入力し、
Altキーを押しながらEnterキーを押下する操作をしています。
#>
function Send-Keys
{
[CmdletBinding()]
[Alias("sdky")]
Param
(
# キーストローク
# アプリケーションに送りたいキーストローク内容を指定します。
# キーストロークの記述方法は下記のWebページを参照。
# https://msdn.microsoft.com/ja-jp/library/cc364423.aspx
[Parameter(Mandatory=$false,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[string]
$KeyStroke,
# プロセス名
# キーストロークを送りたいアプリケーションのプロセス名を指定します。
# 複数ある場合は、PIDが一番低いプロセスを対象とする。
[Parameter(Mandatory=$false,
ValueFromPipelineByPropertyName=$true)]
[string]
$ProcessName,
# 待機時間
# コマンドを実行する前の待機時間をミリ秒単位で指定します。
[Parameter(Mandatory=$false,
ValueFromPipelineByPropertyName=$true)]
[int]
$Wait = 0
)
Process
{
$Process = ps | ? {$_.Name -eq $ProcessName} | sort -Property CPU -Descending | select -First 1
Write-Verbose $Process", KeyStroke = "$KeyStroke", Wait = "$Wait" ms."
sleep -Milliseconds $Wait
if ($Process -ne $null)
{
[Microsoft.VisualBasic.Interaction]::AppActivate($Process.ID)
}
[System.Windows.Forms.SendKeys]::SendWait($KeyStroke)
}
}
備考
Tabキーや方向キーを何回も連続で押す必要が出てきたら、以下のようなコードでスッキリと書けます。
# Before
Send-Keys "{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}test." -ProcessName "LINE"
# After
Send-Keys "$("{DOWN}" * 5)test." -ProcessName "LINE"
参考
Microsoft Developer Network|Windows Script Host
SendKeys メソッド
Windows管理者のためのWindows Script Host入門
第5回 WshShellオブジェクトの詳細(1) (4/4)