简体   繁体   English

捕获键盘快捷键并转发

[英]Capture keyboard shortcuts and forward

What I need to do : 我需要做什么 :

I need to capture all shortcut key presses such as Ctrl + S from a specific application. 我需要捕获所有快捷键按下,例如来自特定应用程序的Ctrl + S. Any key combo, even if it's not a shortcut for that application. 任何关键组合,即使它不是该应用程序的快捷方式。

Then my midway application that capture these keys need to validate those key combination and check if another of our apps that are running can respond to that key, and if it can send the command to it. 然后我的中途应用程序捕获这些密钥需要验证这些密钥组合,并检查我们正在运行的另一个应用程序是否可以响应该密钥,以及是否可以将命令发送给它。

What I have so far : 到目前为止我所拥有的:

Since we wrote the other apps we can easily send the keys to be processed that's not a problem. 由于我们编写了其他应用程序,因此我们可以轻松发送要处理的密钥,这不是问题。 I can get the window handle of the application. 我可以得到应用程序的窗口句柄。 I need to capture the shortcut keys. 我需要捕获快捷键。 This app I know it's build in C++. 这个应用程序我知道它是用C ++构建的。 I am looking to find a way to capture an equivalent of the following event in Winforms : 我想找到一种方法来捕获Winforms中等效的以下事件:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)

Right now everything is working as expected on the forward key part. 现在一切都在前进关键部分按预期工作。 I am only missing the capture of keys on that handle. 我只是错过了该句柄上的键的捕获。 I really don't want to have to adventure myself in hooking the whole keyboard and detect whether the key stroke is done in my apps or not and do I need to cancel the key or continue the process. 我真的不想冒险自己勾住整个键盘并检测是否在我的应用程序中完成击键,我是否需要取消键或继续该过程。 I would prefer also getting key combination events only. 我也希望只获得关键组合事件。 I would prefer not receiving all letter the guy press when he type in a textbox or anything. 当他输入文本框或其他任何东西时,我宁愿不接收那个家伙的所有信件。 I'm really looking for anything starting with CTRL , ALT , SHIFT or any combination of them 我真的在寻找任何以CTRLALTSHIFT或它们的任意组合开头的东西

Example of what I want to do : 我想做的例子:

uncontrolled application : Notepad.exe my midway app : ShortcutHandler.exe my target applications : A.exe, B.exe 不受控制的应用程序:Notepad.exe我的中途应用程序:ShortcutHandler.exe我的目标应用程序:A.exe,B.exe

ShortcutHandler.exe will listen to Notepad.Exe shortcuts then forward them to A.exe and B.exe ShortcutHandler.exe将侦听Notepad.Exe快捷方式,然后将它们转发到A.exe和B.exe

Situation : 情况:

1 - in Notepad.exe press CTRL+H for replace
2 - ShortcutHandler.exe detect CTRL+H pressed on Notepad.exe
3 - ShortcutHandler.exe Analyse CTRL+H and knows it need to do some task
4 - ShortcutHandler.exe call Save on A.exe in reaction to CTRL+H in Notepad.exe
5 - ShortcutHandler.exe call Print report in B.exe in reaction to CTRL+H in Notepad.exe

Some time ago I have to do something like you, so I found this article: A Simple C# Keyboard Hook , and with this I was able to do what I need it. 前段时间我必须做一些像你这样的事情,所以我找到了这篇文章: 一个简单的C#Keyboard Hook ,有了这个我能够做我需要的东西。

But this is a complex code and as you said so, you don't want do get all key down. 但这是一个复杂的代码,正如你所说,你不希望得到所有关键。 For my program I created a KeyboardHook class that make easy to work with the code obtained of previous article. 对于我的程序,我创建了一个KeyboardHook类,可以轻松使用上一篇文章中获得的代码。

So there is a snippet code of what you can do with the KeyboardHook class: 所以你可以用KeyboardHook类做一个代码片段:

// Put this on the begin of your form (like the constructor on FormLoad).
var hook = new KeyboardHook();

hook.KeyDown += (sender, e) => 
{
    // e.Control is a bool property if true Control is press.
    // e.Shift is a bool property if true Shift is press.
    // e.Key has a key that was press.

    // This if ignores anything that don't begin with Control or Shift.
    if(!e.Control && !e.Shift) return;

    // your code below:

    if(e.Control && e.Key == Keys.H)
    {
        // do your code here.
        // like: Analyse CTRL+H and knows it need to do some task.
    }
};

hook.Start(); // Until here goes in the begin of your form.


// Put this on the end of your form (like in the Dispose or FormClose).
hook.Release();
hook.Dispose();

PS: If you put this on your ShortcutHandler app the app will still get the keys. PS:如果你把它放在你的ShortcutHandler应用程序上,应用程序仍会获得密钥。

And below is the KeyboardHook code: 以下是KeyboardHook代码:

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

public class KeyboardHook : IDisposable
{
    #region Fields

    private bool _lControlKeyIsDown;
    private bool _rControlKeyIsDown;
    private bool _lShiftKeyIsDown;
    private bool _rShiftKeyIsDown;

    #endregion

    #region Properties

    private bool ControlIsDown
    {
       get { return _lControlKeyIsDown || _rControlKeyIsDown; }
    }

    private bool ShiftIsDown
    {
        get { return _lShiftKeyIsDown || _rShiftKeyIsDown; }
    }

    #endregion

    #region Constructors

    public KeyboardHook()
    {
        _proc = HookCallback;
    }

    #endregion

    #region Events

    public event HookKeyDownHandler KeyDown;

    #endregion

    #region Methods

    public void Start()
    {
        _hookID = SetHook(_proc);
    }

    private static IntPtr SetHook(LowLevelKeyboardProc proc)
    {
        using (var curProcess = Process.GetCurrentProcess())
        using (var curModule = curProcess.MainModule)
        {
            return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
        }
    }

    private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0)
        {
            var vkCode = Marshal.ReadInt32(lParam);
            var key = (Keys)vkCode;

            if (wParam == (IntPtr)WM_KEYDOWN)
            {
                switch (key)
                {
                    case Keys.LControlKey:
                        _lControlKeyIsDown = true;
                        break;
                    case Keys.RControlKey:
                        _rControlKeyIsDown = true;
                        break;
                    case Keys.LShiftKey:
                        _lShiftKeyIsDown = true;
                        break;
                    case Keys.RShiftKey:
                        _rShiftKeyIsDown = true;
                        break;
                    default:
                        if (KeyDown != null)
                        {
                            var args = new HookKeyDownEventArgs((Keys)vkCode, ShiftIsDown, ControlIsDown);
                            KeyDown(this, args);
                        }
                        break;
                }
            }
            if (wParam == (IntPtr)WM_KEYUP)
            {
                switch (key)
                {
                    case Keys.LControlKey:
                        _lControlKeyIsDown = false;
                        break;
                    case Keys.RControlKey:
                        _rControlKeyIsDown = false;
                        break;
                    case Keys.LShiftKey:
                        _lShiftKeyIsDown = false;
                        break;
                    case Keys.RShiftKey:
                        _rShiftKeyIsDown = false;
                        break;
                }
            }
        }

        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }

    public void Release()
    {
        UnhookWindowsHookEx(_hookID);
    }

    public void Dispose()
    {
        Release();
    }

    #endregion

    #region Interoperability

    private const int WH_KEYBOARD_LL = 13;
    private const int WM_KEYDOWN = 0x0100;
    private const int WM_KEYUP = 0x0101;
    private readonly LowLevelKeyboardProc _proc;
    private IntPtr _hookID = IntPtr.Zero;

    private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr 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);

    #endregion
}

public class HookKeyDownEventArgs : EventArgs
{
    #region Fields

    private readonly Keys _key;
    private readonly bool _shift;
    private readonly bool _control;

    #endregion

    #region Properties

    public Keys Key
    {
        get { return _key; }
    }

    public bool Shift
    {
        get { return _shift; }
    }

    public bool Control
    {
        get { return _control; }
    }

    #endregion

    #region Constructors

    public HookKeyDownEventArgs(Keys key, bool shift, bool control)
    {
        _key = key;
        _shift = shift;
        _control = control;
    }

    #endregion
}

public delegate void HookKeyDownHandler(object sender, HookKeyDownEventArgs e);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM