【问题标题】:How can I capture modifier (ctrl, alt, shift) key presses as a single key press in a C# console app?如何在 C# 控制台应用程序中将修饰符(ctrl、alt、shift)按键捕获为单个按键?
【发布时间】:2018-06-05 06:42:08
【问题描述】:

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

【问题讨论】:

    标签: c# .net console-application


    【解决方案1】:

    this link 提供了一个解决方案。我对上述代码进行了一些编辑,以回答您的问题。

    要运行此代码:

    1. 创建Console Application
    2. 添加对System.Windows.Forms.dll 程序集的引用
    3. 粘贴此代码并进行测试。

    代码:

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

    【讨论】:

    • 谢谢,这工作(有点)。由于某种原因,它仍然没有捕获 ALT 按键,但它至少获得了 SHIFT 和 CTRL。我会弄乱它一些,看看我能不能把它捡起来。
    【解决方案2】:

    您在控制台应用程序中吗?这是 WinForm 代码:​​

    复制自here。试试这个:

    private void YourControl_KeyDown(object sender, KeyEventArgs e)
    { 
        if (e.KeyCode  == Keys.Menu)
        {
            //YourCode
            e.Handled = true;
        }
    }
    
    private void YourControl_KeyUp(object sender, KeyEventArgs e)
    { 
        if (e.KeyData == Keys.Menu)
        {
            //YourCode
            e.Handled = true;
        }
    }
    

    也许还有 Control 和 Shift 的修饰符?如果没有,恐怕您需要使用计时器并反复检查状态,或者全局键盘挂钩可能会捕获它。

    修饰键不会引发标准 KeyPress 事件。

    【讨论】:

      猜你喜欢
      • 2023-03-18
      • 1970-01-01
      • 2018-06-30
      • 2012-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-09
      相关资源
      最近更新 更多