Friendly.Windows.KeyMouseを作成しました!
github.com
あれだけ、キーマウスエミュレートをディスっておきながら、やるんかいってことなんですが・・・
繰り返しますが、最後の手段です。
もっと確実に簡単に操作できる手段があるならそちらを使ってください。どうしてもキー、マウスをエミュレートするテストがしたい場合や、他に手段がない場合にご利用ください。テスト中に全く触らなければ確実に(おそらく)動作しますが、処理中に机が揺れたりしてマウスが少し動いただけで失敗したりしますし。
確実に動作するキーマウスエミュレートなのです。(おそらく
半年ほど前にキーエミュレートに関する記事を書きました。
実はその時から、恐らく確実に動作するだろうキーマウスエミュレートは作れるだろうとは思っていたのですが、全面に押し出すものではないしなーと二の足を踏んでいました。
とは言え、要望はかなりあったので、一丁試しにやってみるかとの運びです。その辺の迷いが、Friendly.Windowsとかに実装するのではなく、新しいライブラリを追加しているとこにも表れています。
やっていることは単純
実装内容はいたって簡単で、旧来のキーマウスエミュレートAPIとFriendlyを組み合わせただけです。Friendlyでやっていることは
- 座標の取得
- 画面のアクティブ化(一部KeyのAPI)
- タイミングの調整
何故確実に動作させられるのか?
ポイントはタイミングの取り方なのです。
その辺は、前にこちらに長々と書いたのでご興味あれば参照お願いします。
Windowsアプリテスト自動化でのキーエミュレートはありなのか? - ささいなことですが。
マウスも実はこれでタイミングが取れます。
ビジーなタイミングを避ければ、キーマウスは失敗しない(はず)もちろんアプリ内で別スレッドでの非同期処理を実装している場合は、別途待ち処理が必要です。
意外とネックになるクリック、ダブルクリック問題にも対応
なんでかというと、クリック→クリックってやったときに、ダブルクリックになるという問題があります。「え、そんなのダブルクリック時間見ればいいんじゃない?」って思うでしょ?そうなんですけど、これではダメなんですよ。
//クリック送信 SendInput(inputArray.Length, inputArray, Marshal.SizeOf(inputArray[0])); //ダブルクリック時間待ち Thread.Sleep(SystemInformation.DoubleClickTime); //クリック送信 SendInput(inputArray.Length, inputArray, Marshal.SizeOf(inputArray[0])); //あれ?タイミングによってダブルクリックになる。
なぜかというと、ダブルクリックかどうかを判定するときに使う時間はあくまで対象のアプリが決めるからです。送信した時間から計測を始めても不正確なのです。相手が受信したタイミングから数えないといけない。それって相手の処理状態が分からないと無理なんですね。今回はタイマーメッセージを使うことにより、相手が受信したという状態を取得できるようにしています。実際のコードとは異なりますが、イメージ的には以下のようになるようにしています。
//クリック送信 SendInput(inputArray.Length, inputArray, Marshal.SizeOf(inputArray[0])); //タイマーメッセージが通るのを待つ //(相手に前に送ったマウスエミュレートが届いている) WaitForTimerMessage(_app); //ダブルクリック時間待ち Thread.Sleep(SystemInformation.DoubleClickTime); //クリック送信 SendInput(inputArray.Length, inputArray, Marshal.SizeOf(inputArray[0]));
サンプルコード
GitHubの方にも書きましたが、こっちにもサンプル書いておきます。
拡張メソッドなので、最初にusingおねがいします。
using Codeer.Friendly.Windows.KeyMouse;
キーエミュレート
var window = WindowControl.FromZTop(app); var target = new FormsTextBox(window.Dynamic()._keyTest); //引数はSystem.Windows.Forms.SendKeysと同じ仕様です。 target.SendKeys("aBc"); //CONTROL + Q target.SendControlAndKey(Keys.Q); //SHIFT + Q target.SendShiftAndKey(Keys.A); //ALT + Q target.SendAltAndKey(Keys.Q); //CONTROL + SHIFT + ALT + Q target.SendModifyAndKey(true, true, true, Keys.Q);
マウスエミュレート
var window = WindowControl.FromZTop(app); var target = new WindowControl(window.Dynamic()._mouseTest); //左クリック 座標はコントロールの中央です。 target.Click(); //ボタンと座標指定 target.Click(MouseButtonType.Middle, new Point(4, 5)); //ダブルクリックも同様 target.DoubleClick(); target.DoubleClick(MouseButtonType.Middle, new Point(4, 5)); //Drag & Drop. var dropTarget = new WindowControl(window.Dynamic()._dropTest); target.MouseDown(MouseButtonType.Left, new Point(0, 0)); dropTarget.MouseUp(MouseButtonType.Left, new Point(2, 3));
キーとマウスを同時に操作
var window = WindowControl.FromZTop(app); var target = new WindowControl(window.Dynamic()._keyMouseTest); //ALT + MouseClick; app.KeyDown(Keys.Menu); target.Click(): app.KeyUp(Keys.Menu);
ご意見お待ちしております!
まだβ版という位置づけにしているのでご意見あれば言ってください。反映していきます。