挂接按键,同时仍保留 C# 中的原始命令

本文关键字:保留 命令 原始 | 更新日期: 2023-09-27 18:36:31

我想检测按键并在应用程序在后台运行时相应地执行某些事件。例如,当我按 W 时,我希望我的应用程序检测到这一点,在列表框中写下"W 按下",并且不会影响正在发生的任何其他进程。

找到的以下代码几乎与我上面所说的相同。唯一的问题是它完全拦截了按键。例如,如果我打开谷歌并输入"W",则该字母不会出现在谷歌搜索栏中,但会被应用程序钩住。

namespace WindowsFormsApplication1
{
   public partial class Form1 : Form
   {

     // DLL libraries used to manage hotkeys
     [DllImport("user32.dll")]
     public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
     [DllImport("user32.dll")]
     public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
     const int MYACTION_HOTKEY_ID = 1;

     public Form1()
     {
         InitializeComponent();
         // Modifier keys codes: Alt = 1, Ctrl = 2, Shift = 4, Win = 8
         // Compute the addition of each combination of the keys you want to be pressed
         // ALT+CTRL = 1 + 2 = 3 , CTRL+SHIFT = 2 + 4 = 6...
         RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, (int)Keys.W);
     }

     protected override void WndProc(ref Message m)
     {
         if (m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID)
         {
             // My hotkey has been typed
             // Do what you want here
             // ...
             lstLog.Items.Add("W pressed");
         }
         base.WndProc(ref m);
     }
  }
}

所以,简而言之。我正在寻找一种在保持原始命令的同时挂接按键的方法。在我上面的例子中,"W"应该出现在谷歌搜索栏中。

我一直在寻找这个(可能很小)问题的解决方案,并发现了很多像上面这样的关于公钥和钩子的帖子,但没有一个真正按照我想要的方式工作。所以我决定在这里发表我的第一篇文章。希望你们能帮助我。如果有任何不清楚的地方,请告诉我。

感谢

-编辑-

一些附加信息:我确实计划在玩英雄联盟、魔兽世界等游戏时使用这个程序。因此,由于可能禁止使用第三方软件,我希望它不会与这些游戏的任何进程进行交互。如果有什么我应该知道的,请告诉我。我和我的未来未被禁止的帐户提前感谢您。

挂接按键,同时仍保留 C# 中的原始命令

你不能使用RegisterHotKey,因为它不会传递键事件。

你必须使用WH_KEYBOARD_LL钩。

这是一个功能齐全的示例,快速且脏,但功能强大:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Diagnostics;

namespace StackoverflowHooks
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern IntPtr CallNextHookEx(IntPtr hHook, int nCode, IntPtr wParam, IntPtr lParam);

        [StructLayout(LayoutKind.Sequential)]
        public struct KBDLLHOOKSTRUCT
        {
            public uint vkCode;
            public uint scanCode;
            public uint flags;
            public uint time;
            IntPtr dwExtraInfo;
        }

        IntPtr hHook;
        private delegate IntPtr HookProc(int nCode, IntPtr wp, IntPtr lp);
        HookProc lpfn;
        private IntPtr KeyboardHookProc(int code, IntPtr wParam, IntPtr lParam)
        {
            KBDLLHOOKSTRUCT data = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
            MessageBox.Show("Pressed key: " + (Keys)data.vkCode);
            return CallNextHookEx(hHook, code, wParam, lParam);
        }

        public Form1()
        {
            InitializeComponent();  
            SetHook();
        }
        private void SetHook()
        {
            int id_hook = 13; //WH_KEYBOARD_LL - HOOK
            lpfn = new HookProc(this.KeyboardHookProc);
            using (ProcessModule curModule = Process.GetCurrentProcess().MainModule)
            hHook = SetWindowsHookEx(id_hook, lpfn, GetModuleHandle(curModule.ModuleName), 0);
        }
    }
}