WPFから他のアプリをキーボード操作する

LLMといっしょにゲームをする準備のためにウィンドウハンドルを取得したアプリをキーボード操作するテストをしました。

対象のアプリはWebで公開されている倉庫番です。
FRG TOKYO 倉庫番→リンク



MainWindow.xaml

<Window x:Class="PostMessageTEST.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:PostMessageTEST"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="92*"/>
            <ColumnDefinition Width="185*"/>
            <ColumnDefinition Width="236*"/>
            <ColumnDefinition Width="211*"/>
            <ColumnDefinition Width="76*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="52*"/>
            <RowDefinition Height="100*"/>
            <RowDefinition Height="115*"/>
            <RowDefinition Height="108*"/>
            <RowDefinition Height="59*"/>
        </Grid.RowDefinitions>
        <Button x:Name="btnUp" Grid.Column="2" Content="↑" HorizontalAlignment="Left" Margin="30,21,0,0" Grid.Row="1" VerticalAlignment="Top" Width="168" Height="49" Click="btnUp_Click"/>
        <Button x:Name="btnDown" Grid.Column="2" Content="↓" HorizontalAlignment="Left" Margin="39,0,0,0" Grid.Row="3" VerticalAlignment="Center" Width="168" Height="49" Click="btnDown_Click"/>
        <Button x:Name="btnLeft" Grid.Column="1" Content="←" HorizontalAlignment="Left" Margin="10,30,0,0" Grid.Row="2" VerticalAlignment="Top" Width="157" Height="53" Click="btnLeft_Click"/>
        <Button x:Name="btnRight" Grid.Column="3" Content="→" HorizontalAlignment="Center" Margin="0,30,0,0" Grid.Row="2" VerticalAlignment="Top" Width="157" Height="53" Click="btnRight_Click"/>
    </Grid>
</Window>


MainWindow.xaml.cs
ウィンドウを「常に前に」の設定にしてキーをPostする時は倉庫番のウィンドウをアクティブにしています。
※ウィンドウタイトルを「Sokoban」にするためにゲームプレイ画面まで進めてから当プログラムを起動してください。

using System.Runtime.InteropServices;
using System.Windows;

namespace PostMessageTEST
{
    public partial class MainWindow : Window
    {
        private const int WM_KEYDOWN = 0x0100;
        private const int VK_LEFT = 0x25;
        private const int VK_UP = 0x26;
        private const int VK_RIGHT = 0x27;
        private const int VK_DOWN = 0x28;
        private IntPtr hwd = IntPtr.Zero;   

        public MainWindow()
        {
            InitializeComponent();
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            string strTitle = "";
            System.Collections.ArrayList list = new System.Collections.ArrayList();
           //「Sokoban」という文字が含まれたウィンドウタイトルを持つアプリの正式名を求める
            foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
            {
                if (0 <= p.MainWindowTitle.IndexOf("Sokoban"))
                {
                    strTitle = p.MainWindowTitle;
                    break;
                }
            }
            if (strTitle=="") return;
           //ウィンドウタイトルからウィンドウハンドルを求める
            hwd = FindWindow(null, strTitle);
            this.Topmost = true;
        }

        private void btnUp_Click(object sender, RoutedEventArgs e)
        {
            SetForegroundWindow(hwd);
            PostMessage(hwd, WM_KEYDOWN, VK_UP, 0);
        }

        private void btnRight_Click(object sender, RoutedEventArgs e)
        {
            SetForegroundWindow(hwd);
            PostMessage(hwd, WM_KEYDOWN, VK_RIGHT, 0);
        }

        private void btnLeft_Click(object sender, RoutedEventArgs e)
        {
            SetForegroundWindow(hwd);
            PostMessage(hwd, WM_KEYDOWN, VK_LEFT, 0);
        }

        private void btnDown_Click(object sender, RoutedEventArgs e)
        {
            SetForegroundWindow(hwd);
            PostMessage(hwd, WM_KEYDOWN, VK_DOWN, 0);
        }

        [DllImport("user32.dll")]
        private static extern IntPtr GetDesktopWindow();
        [DllImport("user32.dll")]
        private static extern IntPtr GetWindowDC(IntPtr hWnd);
        [DllImport("user32.dll")]
        private static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
        [DllImport("user32.dll")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
        [DllImport("user32.dll")]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

    }
}



結果
左矢印ボタンを押すとちゃんとキャラクターが左に移動しました。

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です