やりたいこと
2023/5/3時点の、Google Play Games BETA のプレイ画面に対して、プレイ画面が他のウィンドウの下にあっても、スワイプ操作したい。
やったこと
Powershell Core 7.3 から、SendMessage 関数 を呼び出して、スワイプ操作をエミュレートしたメッセージを送信した。
### C# Add-Type -TypeDefinition @" using System; using System.Runtime.InteropServices; public static class Win32 { [DllImport("user32.dll")] static extern IntPtr FindWindow( string lpClassName, string lpWindowName ); public static IntPtr FindWindowByName(string lpWindowName) { return FindWindow(null, lpWindowName); } [DllImport("user32.dll")] static extern int GetWindowThreadProcessId( IntPtr hWnd, IntPtr ProcessId ); [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); [DllImport("kernel32.dll")] static extern int GetCurrentThreadId(); [DllImport("user32.dll")] static extern bool SetWindowPos( IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags ); [DllImport("user32.dll")] static extern bool AttachThreadInput( int idAttach, int idAttachTo, bool fAttach ); [DllImport("user32.dll")] static extern IntPtr SendMessage( IntPtr hWnd, uint Msg, int wParam, int lParam ); static void SimulateBackGround( string lpWindowName, string simualtedTask, int x = 0, int y = 0, int movedX = 0, int movedY = 0 ) { var targetWnd = FindWindowByName(lpWindowName); var wakfuThreadID = GetWindowThreadProcessId(targetWnd, IntPtr.Zero); var foreWnd = GetForegroundWindow(); var windowThreadProcessId = GetCurrentThreadId(); AttachThreadInput(windowThreadProcessId, wakfuThreadID, true); int mousePos = (y << 16) | (x & 0xffff); int movedMousePos = (movedY << 16) | (movedX & 0xffff); const int WM_MOUSEMOVE = 0x0200; const int WM_LBUTTONDOWN = 0x0201; const int WM_LBUTTONUP = 0x0202; const int MK_LBUTTON = 0x0001; switch (simualtedTask) { case "tap": SendMessage(targetWnd, WM_MOUSEMOVE, 0, mousePos); SendMessage(targetWnd, WM_LBUTTONDOWN, MK_LBUTTON, mousePos); System.Threading.Thread.Sleep(50); SendMessage(targetWnd, WM_MOUSEMOVE, 0, mousePos); SendMessage(targetWnd, WM_LBUTTONUP, 0, mousePos); break; case "swipe": SendMessage(targetWnd, WM_MOUSEMOVE, 0, mousePos); SendMessage(targetWnd, WM_LBUTTONDOWN, MK_LBUTTON, mousePos); System.Threading.Thread.Sleep(100); SendMessage(targetWnd, WM_MOUSEMOVE, 0, movedMousePos); SendMessage(targetWnd, WM_LBUTTONDOWN, MK_LBUTTON, movedMousePos); System.Threading.Thread.Sleep(110); SendMessage(targetWnd, WM_LBUTTONUP, 0, movedMousePos); break; default: break; } const int SWP_NOSIZE = 0x0001; const int SWP_NOMOVE = 0x0002; const int SWP_SHOWWINDOW = 0x0040; SetWindowPos(foreWnd, -1, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); SetWindowPos(foreWnd, -2, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); AttachThreadInput(windowThreadProcessId, wakfuThreadID, false); } public static void TapBackGround( string lpWindowName, int x, int y ) { SimulateBackGround(lpWindowName, "tap", x, y); } public static void SwipeBackGround( string lpWindowName, int x, int y, int movedX, int movedY ) { SimulateBackGround(lpWindowName, "swipe", x, y, movedX, movedY); } } "@ ### Powershell Set-Variable WINDOW_TITLE -Option Constant -Value "操作したいアプリのウィンドウタイトル" [int]$local:startXforSwipe = 500 [int]$local:startYforSwipe = 600 [int]$local:endXforSwipe = 1000 [int]$local:endYforSwipe = 600 [Win32]::SwipeBackGround( ${WINDOW_TITLE}, ${startXforSwipe}, ${startYforSwipe}, ${endXforSwipe}, ${endYforSwipe} ) # tap # [int]$local:xforTap = 500 # [int]$local:yforTap = 600 # [Win32]::TapBackGround( # ${WINDOW_TITLE}, # ${xforTap}, # ${yforTap} # )
やっていて困ったこと
- FindWindow 関数にウィンドウのクラス名 (KIWICROSVM) を渡しても、上手くウィンドウハンドルが取得できなかった
- SetFocus 関数 を利用したもの で元のウィンドウを最前面に戻そうとしたが、上手くいかなかった
- swipe 操作をマウスでエミュレートしようとして、'left click down' -> 'mouse move, move, move' -> 'left click up' といったメッセージを送信しても上手くいかなかった