博多南ウェブサービスのblog

博多南ウェブサービスのサービス紹介

Powershell Core 7.3 から、SendMessage() を呼び出して、背面にあるGoogle Play Games BETA の画面をスワイプ操作したい

やりたいこと

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}
#                         )

やっていて困ったこと

参考