「マウスの右ボタンを押したままの状態で放置しておいて、1時間ごとに押し直すような事って出来ん?」って聞かれたので、「出来るんじゃね?」と適当に答えておきました。
それから1ヶ月……なんとなく思い出して本当に出来るのかどうか調べてみました。
P/Invokeで実現するためにまず定義をします。
using System.Runtime.InteropServices; class Win32 { [DllImport("user32.dll")] public static extern uint SendInput( uint nInputs, // INPUT 構造体の数(イベント数) INPUT[] pInputs, // INPUT 構造体 int cbSize // INPUT 構造体のサイズ ); public const int MOUSEEVENTF_MOVED = 0x0001; public const int MOUSEEVENTF_LEFTDOWN = 0x0002; public const int MOUSEEVENTF_LEFTUP = 0x0004; public const int MOUSEEVENTF_RIGHTDOWN = 0x0008; public const int MOUSEEVENTF_RIGHTUP = 0x0010; public const int MOUSEEVENTF_MIDDLEDOWN = 0x0020; public const int MOUSEEVENTF_MIDDLEUP = 0x0040; public const int MOUSEEVENTF_WHEEL = 0x0080; public const int MOUSEEVENTF_XDOWN = 0x0100; public const int MOUSEEVENTF_XUP = 0x0200; public const int MOUSEEVENTF_ABSOLUTE = 0x8000; public const int SCREEN_LENGTH = 0x10000; } [StructLayout(LayoutKind.Sequential)] struct INPUT { public int type; // 0 = INPUT_MOUSE(デフォルト), 1 = INPUT_KEYBOARD public MOUSEINPUT mi; } [StructLayout(LayoutKind.Sequential)] struct MOUSEINPUT { public int dx; public int dy; public int mouseData; public int dwFlags; public int time; public IntPtr dwExtraInfo; }
同僚の要望の動作をそのままトレースしても良かったんだけど、ここにはシンプルな例を書いておきます。
INPUT[] input = new INPUT[3] ; // 計3イベントを格納 // マウスを移動 input[0].mi.dx = Win32.SCREEN_LENGTH / 10; input[0].mi.dy = Win32.SCREEN_LENGTH / 10; input[0].mi.dwFlags = Win32.MOUSEEVENTF_MOVED | Win32.MOUSEEVENTF_ABSOLUTE; // 左ボタンを押下 input[1].mi.dwFlags = Win32.MOUSEEVENTF_LEFTDOWN; // 左ボタンを開放 input[2].mi.dwFlags = Win32.MOUSEEVENTF_LEFTUP; // マウスイベント送出 Win32.SendInput(3, input, Marshal.SizeOf(input[0]));
この手法を応用すれば、キーボード入力のデータを保持しておいておけば、ゲームのリプレイデータとして使えそうだなぁ。
今回調べた中で一番の発見は、マウスの移動させる単位のことを「ミッキー」と呼ぶこと。