Console.ReadKey仅在按下“普通”键时捕获输入,然后将修饰符(如果有)附加为键信息的一部分。如何将单个修改键注册为输入?

最佳答案

this link提供了一种解决方案。我对提到的代码做了一些编辑,以回答您的问题。

要运行此代码:

  • 创建一个Console Application
  • 添加对System.Windows.Forms.dll组件的引用
  • 粘贴此代码并进行测试。

  • 代码:
    using System;
    using System.Diagnostics;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    class Program
    {
        class InterceptKeys
        {
            // https://blogs.msdn.microsoft.com/toub/2006/05/03/low-level-keyboard-hook-in-c/
            private const int WH_KEYBOARD_LL = 13;
            private const int WM_KEYDOWN = 0x0100;
            private static LowLevelKeyboardProc _proc = HookCallback;
            private static IntPtr _hookID = IntPtr.Zero;
            private static IntPtr SetHook(LowLevelKeyboardProc proc)
            {
                using (Process curProcess = Process.GetCurrentProcess())
                using (ProcessModule curModule = curProcess.MainModule)
                {
                    return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                        GetModuleHandle(curModule.ModuleName), 0);
                }
            }
    
            private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
    
            private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
            {
                if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
                {
                    int vkCode = Marshal.ReadInt32(lParam);
                    OnKeyDown?.Invoke(new KeyEventArgs((Keys)vkCode));
                }
                return CallNextHookEx(_hookID, nCode, wParam, lParam);
            }
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool UnhookWindowsHookEx(IntPtr hhk);
    
            [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);
    
            private static event OnKeyDownDelegate OnKeyDown = null;
            public delegate void OnKeyDownDelegate(KeyEventArgs e);
            public static void SetupHook(OnKeyDownDelegate OnKeyDown)
            {
                InterceptKeys.OnKeyDown = OnKeyDown;
                System.Threading.Tasks.Task.Run(() =>
                {
                    _hookID = SetHook(_proc);
                    Application.Run();
                    UnhookWindowsHookEx(_hookID);
                });
            }
    
            public static void ReleaseHook()
            {
                Application.Exit();
            }
        }
    
        static void KeyDown(KeyEventArgs e)
        {
            Console.WriteLine("Hook: "+ e.KeyCode);
        }
    
        static void Main()
        {
            InterceptKeys.SetupHook(KeyDown);
            while (true)
            {
                ConsoleKey key = Console.ReadKey(true).Key;
                Console.WriteLine("ReadKey: "+ key);
    
                if (key == ConsoleKey.Escape)
                    break;
            }
            InterceptKeys.ReleaseHook();
        }
    }
    

    10-08 11:41