私はオンラインで多くの解決策を見てきましたが、どれも私が望んでいることを正確に実行しません。アプリケーションがバックグラウンドで実行されているときに、特定のプロセス(コンソールアプリケーションではない)でキーを押すための最良/最も簡単な方法は何ですか。修飾子などは必要ありません。
4 に答える
あなたが探しているものは、グローバルキーボードフックと呼ばれています。詳細と例については、MSDNを参照してください。
最も簡単な方法でキーが押されているプロセスを特に気にしない場合は、GetAsyncKeyStateを呼び出すことです。キーボードを引っ掛けず、継続的に呼び出す必要があるため、かなり制限されています。私の意見では、キーボードをフックするのが最善の方法です。
SetWindowsHookExを使用すると、フックプロシージャが関連付けられるスレッドの識別子を実際に明示的に指定できるため、特定のプロセスのキーをフックできます(dwThreadIdを参照)。
使用できるクラスは次のとおりです(元々はMicrsoftブログにありましたが、現時点では作成者の名前が見つからないようです!)
public delegate IntPtr KeyboardProcess(int nCode, IntPtr wParam, IntPtr lParam);
public sealed class KeyboardHook
{
public static event EventHandler<KeyPressedEventArgs> KeyPressed;
private const int WH_KEYBOARD = 13;
private const int WM_KEYDOWN = 0x0100;
private static KeyboardProcess keyboardProc = HookCallback;
private static IntPtr hookID = IntPtr.Zero;
public static void CreateHook()
{
hookID = SetHook(keyboardProc);
}
public static void DisposeHook()
{
UnhookWindowsHookEx(hookID);
}
private static IntPtr SetHook(KeyboardProcess keyboardProc)
{
using (Process currentProcess = Process.GetCurrentProcess())
using (ProcessModule currentProcessModule = currentProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD, keyboardProc, GetModuleHandle(currentProcessModule.ModuleName), 0);
}
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (KeyPressed != null)
KeyPressed(null, new KeyPressedEventArgs((Keys)vkCode));
}
return CallNextHookEx(hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, KeyboardProcess lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
}
public class KeyPressedEventArgs : EventArgs
{
public Keys KeyCode { get; set; }
public KeyPressedEventArgs(Keys Key)
{
KeyCode = Key;
}
}
コンソールアプリケーションを介した実装:
class Program
{
static void Main(string[] args)
{
KeyboardHook.CreateHook();
KeyboardHook.KeyPressed += KeyboardHook_KeyPressed;
Application.Run();
KeyboardHook.DisposeHook();
}
static void KeyboardHook_KeyPressed(object sender, KeyPressedEventArgs e)
{
Console.WriteLine(e.KeyCode.ToString());
}
}
ああ、あなたは昔ながらのゲーム用語で「Autofire」を探していますか?
独自のキーボードフックアプリを作成する代わりに(楽しみ/スリル/エクササイズのために作成している場合を除き)、キーボード/マウスの自動化に非常に適したAutoItまたはAutoHotkeyを検討することをお勧めします。
たとえば、このスレッドを参照してください... http://www.autohotkey.com/board/topic/40598-autofire-keyboard/
プロセスだけにフックする方法を見つけました。あなたはそれを必要とするかもしれません。
int ProcessId = GetProcessesByName("Your_app_here").FirstOrDefault().Id;
private IntPtr SetHook(KeyboardHookHandler proc)
{
return SetWindowsHookEx(13, proc, GetModuleHandle(Process.GetProcessById(ProcessId).MainModule.ModuleName), GetWindowThreadProcessId(GetModuleHandle(Process.GetProcessById(ProcessId).MainModule.ModuleName), out int MainThreadId));
}
これらのメソッドをインポートすることを忘れないでください。
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, KeyboardHookHandler lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);