从任何过程中获取密钥

时间:2012-12-21 22:42:29

标签: c# keyboard console-application user32

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

4 个答案:

答案 0 :(得分:4)

您正在寻找的是全局键盘钩子。您可以找到更多信息和示例on MSDN

答案 1 :(得分:3)

如果您不是特别关心按最简单的方法按键的过程是调用GetAsyncKeyState。它相当有限,因为它没有挂钩键盘,需要你连续调用它。在我看来,最好的方法是挂钩键盘。

使用SetWindowsHookEx,您实际上可以明确指定与钩子过程相关联的线程的标识符,以便您可以为特定进程挂钩(请参阅 dwThreadId )。 / p>

这是一个你可以使用的课程(最初在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());
    }
}

答案 2 :(得分:2)

哦,所以你在老派游戏术语中寻找“Autofire”?

不是编写自己的键盘钩子应用程序(除非你是为了娱乐/它的快感/练习),你可能想要看看AutoIt或AutoHotkey,它们都非常适合键盘/鼠标自动化。

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

答案 3 :(得分: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);