【问题标题】:Global hotkeys, allows user to hold down modifier keys全局热键,允许用户按住修饰键
【发布时间】:2014-09-22 15:48:45
【问题描述】:

我正在使用此处给出的代码的修改版本: https://stackoverflow.com/a/3654821/3179989

如果用户按下 Ctrl+B,热键将激活。

如果用户按下 Ctrl+B,它会激活,但继续按住 Ctrl 然后按下 B再次,它确实处于活动状态。

有没有办法让热键的行为更像 Windows 中的 copy/paste

例如,按住 Ctrl 并点击 V 将粘贴多次。

编辑:

问题是由于我在按下热键时添加了SendKeys.Send()。上面的原始代码不包含这个问题。现在的问题是如何在不丢失此功能的情况下发送密钥?

【问题讨论】:

  • 这是一个环境问题,您机器上的某些其他程序导致了这个问题。使用Taskmgr.exe,Processes选项卡,开始一一查杀进程,找出问题的根源。
  • 我发现问题发生的原因是因为我在按下热键时使用了 SendKeys.Send()。出于某种原因,这会产生这种行为

标签: c# hotkeys


【解决方案1】:

编辑:

回答你的新问题:)

如果您编写自己的全局挂钩,则可以指定这些类型的情况。

我相信您遇到的问题是,如果您发送 CTRL+V,它会发送 KeyDownKeyUp 用于控制,这使得热键程序假定您不再按住它。 您需要通过在密钥发送期间不更改切换来明确处理这种情况。

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (!SENDING_KEYS) //If we're sending keys, ignore everything below
        {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) //KeyDown
            {
                int vkCode = Marshal.ReadInt32(lParam);
                string theKey = ((Keys)vkCode).ToString();
                Console.Write(theKey);
                if (theKey.Contains("ControlKey"))
                {
                    //Our Program still thinks CTRL is down even if we send it using SendKeys
                    CONTROL_DOWN = true; 
                }
                else if (CONTROL_DOWN && theKey == "B")
                {
                    Console.WriteLine("\n***HOTKEY PRESSED***"); //Our hotkey has been pressed
                    SENDING_KEYS = true; //Now we will be sending keys
                    SendKeys.Send("^v"); //Send the keys (CTRL+V) - Paste
                    SENDING_KEYS = false; //Now we are done sending the keys
                    return (IntPtr)1; //Block our hotkey from being sent anywhere
                }
                else if (theKey == "Escape")
                {
                    UnhookWindowsHookEx(_hookID);
                    Environment.Exit(0);
                }
            }
            else if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP) //KeyUP
            {
                int vkCode = Marshal.ReadInt32(lParam);
                string theKey = ((Keys)vkCode).ToString();
                if (theKey.Contains("ControlKey"))
                {
                    //During send keys, this will not be triggered
                    CONTROL_DOWN = false; 
                }
            }
        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }

原答案:

您可以创建自己的全局 Keyhook。

这是一个使用 Windows 窗体的示例:

这是控制台中的示例:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace ConsoleKeyhook
{
    class Hooky
    {
        [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 const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_KEYUP = 0x0101;
        private static LowLevelKeyboardProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;
        private static bool CONTROL_DOWN = false;

        public static void Main()
        {
            _hookID = SetHook(_proc);
            Application.Run();
        }

        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) //KeyDown
            {
                int vkCode = Marshal.ReadInt32(lParam);
                string theKey = ((Keys)vkCode).ToString();
                Console.Write(theKey);
                if (theKey.Contains("ControlKey"))
                {
                    CONTROL_DOWN = true;
                }
                else if (CONTROL_DOWN && theKey == "B")
                {
                    Console.WriteLine("\n***HOTKEY PRESSED***");
                }
                else if (theKey == "Escape")
                {
                    UnhookWindowsHookEx(_hookID);
                    Environment.Exit(0);
                }
            }
            else if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP) //KeyUP
            {
                int vkCode = Marshal.ReadInt32(lParam);
                string theKey = ((Keys)vkCode).ToString();
                if (theKey.Contains("ControlKey"))
                {
                    CONTROL_DOWN = false;
                }
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }
    }
}

【讨论】:

    猜你喜欢
    • 2018-05-01
    • 2011-06-30
    • 1970-01-01
    • 2011-02-15
    • 2021-01-27
    • 2017-12-20
    • 2016-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多