#はじめに
その1の3では、マウスの動きを記録する機能を作りました。今回は、その記録した動作を再現する処理を作ります。
#環境
私の使用している環境を以下に挙げます。環境が異なる場合は適宜読み替えてください。
- Windows 10 pro
- Visual Studio 2019 Community Edition
#今回やること
- 画面に「再生」ボタンを追加する
- ファイルを読み込む
- 記録したマウス操作ごとに、マウスを動作させる
#ボタン追加
記録ボタンを追加した時と同様に、再生ボタンをダイアログに追加します。
次にダイアログのコールバック関数に、再生ボタンクリックのメッセージ処理を追加します。
case WM_COMMAND:
switch (LOWORD(wp))
{
case IDC_REC_BTN:
StartMouseHook(hDlgWnd);
return FALSE;
case IDC_PLAY_BTN:
return FALSE;
default:
return FALSE;
}
ボタンのIDをIDC_PLAY_BTN
としたので、そのボタンの処理をWM_COMMAND
の処理に追加します。
#ファイル読み込み
記録の時に保存したマウスイベントログファイルを読み込みます。
std::ifstream fin;
fin.open(L"rec.log", std::ios::in);
ifstream
を使用してファイルを読み取ります。
次に、ファイルを一行ずつ読み込みます。
while (true)
{
char line[128] = { 0 };
fin >> line;
if (line[0] == '\0')
continue;
}
>>
を使って、一行ずつ読み込みます。空行が来たら処理を終了しています。
次に、ファイルの内容を解析します。
ファイルはCSV形式で、以下のフォーマットで保存されています。
メッセージ, X座標, Y座標, タイムスタンプ
そこで、strtok_s
を使用して、カンマ区切り文字列をそれぞれ取得します。
取得した後は、それぞれの文字列を数値に変換し保持します。
char* ctx = nullptr;
char* token = strtok_s(line, ",", &ctx);
if (token == nullptr)
continue;
int msg = atoi(token);
token = strtok_s(nullptr, ",", &ctx);
if (token == nullptr)
continue;
int x = atoi(token);
token = strtok_s(nullptr, ",", &ctx);
if (token == nullptr)
continue;
int y = atoi(token);
token = strtok_s(nullptr, ",", &ctx);
if (token == nullptr)
continue;
int timestamp = atoi(token);
これで、保存したマウスメッセージの解析は完了です。
#マウス動作
解析した値を使用して、マウスを動かします。
マウスを動かすために、SendInput
関数を使用します。
UINT WINAPI SendInput(
_In_ UINT nInputs,
_In_ LPINPUT pInputs,
_In_ int cbSize
);
SendInput
は、キーボードやマウスをプログラムで操作するための関数です。
以下の通り、解析した値を設定して、SendInput
を呼び出します。
int time = prevtime == 0 ? 0 : timestamp - prevtime;
if (time < 0)
time = 0;
INPUT inp[1] = { 0 };
inp[0].type = INPUT_MOUSE;
inp[0].mi.time = 0;
inp[0].mi.dwExtraInfo = 0;
inp[0].mi.dx = x * (65535 / GetSystemMetrics(SM_CXSCREEN));
inp[0].mi.dy = y * (65535 / GetSystemMetrics(SM_CYSCREEN));
inp[0].mi.mouseData = 0;
inp[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
switch (msg)
{
case WM_LBUTTONDOWN:
inp[0].mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
break;
case WM_LBUTTONUP:
inp[0].mi.dwFlags |= MOUSEEVENTF_LEFTUP;
break;
case WM_MOUSEMOVE:
break;
case WM_MOUSEWHEEL:
break;
case WM_MOUSEHWHEEL:
break;
case WM_RBUTTONDOWN:
inp[0].mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
break;
case WM_RBUTTONUP:
inp[0].mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
break;
}
Sleep(time);
SendInput(1, inp, sizeof(INPUT));
INPUT
構造体に、INPUT_MOUSE
を指定して、マウスを動作させることを指定します。
そのあとは、xやyを設定します。これらの値は、画面の幅や高さを65535までで表す必要があるため、65535をスクリーンの幅と高さで割ったものをかけて算出しています。
ホイールの動作は今のところ未対応なので、処理を入れていません。暇を見つけて拡張します。
#動きを見てみましょう
動画だと、ただ絵を描いているだけに見えるかもしれませんが、記録したものを再生した動画です。本当ですよ~。
マウス動作を記録再生できるRPAをつくって、お絵かきを記録して再生してみた。 https://t.co/0gEdxJ3Y6K via @YouTube
— teamm (@teamm89201677) October 17, 2019
#つづく
これで、マウス動作の記録と再生ができるようになりました。UWSCでいうところの、低レベル記録です。
キーボードの記録再生は、同じようにフックして記録して再生すればいいので、簡単に作れると思います。
もし需要があれば書きますので、コメントください。
次回は、OpenCVを使った、画像指定による項目クリックの実装です。
https://qiita.com/yasunari_matsuo/items/1dd10e0379570eef96d0
これまでの記事は以下です。
その1の1
https://qiita.com/yasunari_matsuo/items/b1e56ad06c6a7843dfae
その1の2
https://qiita.com/yasunari_matsuo/items/a1d294f09ac21e9508b6
その1の3
https://qiita.com/yasunari_matsuo/items/14fe987a162936f7a1ae