2

我在网上看到了很多解决方案,但没有一个完全符合我的要求。当我的应用程序在后台运行时,在给定进程(不是我的控制台应用程序)中按下任何键的最佳/最简单方法是什么。我不需要修饰符或任何东西。

4

4 回答 4

4

If you don't particularly care which process the keys are being pressed in the easiest method would be to call GetAsyncKeyState. It's rather limited though as it does not hook the keyboard and requires you to call it continuously. The best approach in my opinion is to hook the keyboard.

Using SetWindowsHookEx you can actually explicitly specify the identifier of the thread with which the hook procedure is to be associated so you can hook keys for a specific process (see dwThreadId).

Here's a class that you can use (originally found on a Micrsoft blog but I cannot seem to find the authors name at the moment!)

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;
    }
}

Implementation via Console Application:

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());
    }
}
于 2012-12-21T23:00:20.063 回答
4

您正在寻找的东西称为全局键盘挂钩。您可以在 MSDN 上找到更多信息和示例。

于 2012-12-21T22:54:33.720 回答
2

哦,所以您正在寻找老式游戏术语中的“自动开火”?

与其编写自己的键盘钩子应用程序(除非你是为了好玩/刺激它/锻炼),你可能想看看 AutoIt 或 AutoHotkey,它们都非常适合键盘/鼠标自动化。

例如,请参阅此线程... http://www.autohotkey.com/board/topic/40598-autofire-keyboard/

于 2012-12-21T23:01:13.707 回答
0

我找到了一种只挂钩一个进程的方法。你可能需要它。

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);
于 2018-11-14T02:15:25.123 回答