0

我在 Form1 的顶部做了这个:

globalKeyboardHook gkh;

在加载事件中:

private void Form1_Load(object sender, EventArgs e)
{
    gkh = new globalKeyboardHook();
    gkh.HookedKeys.Add(Keys.M);
    gkh.KeyDown += new KeyEventHandler(gkh_KeyDown);
    gkh.KeyUp += new KeyEventHandler(gkh_KeyUp);
}

然后在底部:

void gkh_KeyDown(object sender, KeyEventArgs e)
{
    // e.KeyCode.ToString() is the KeyCode of the pressed key
    e.Handled = true;
    if ((e.KeyCode == System.Windows.Forms.Keys.LControlKey) || (e.KeyCode == System.Windows.Forms.Keys.RControlKey))
    {
        controlDown = true;
    }

    if (e.KeyCode == System.Windows.Forms.Keys.M && controlDown)
    {
        // Do CTRL-M action
        if (mf == null)
        {
            //mf = new MagnifierMainForm();
            mf = new MagnifierMainForm(false);
            mf.StartPosition = FormStartPosition.Manual;
            mf.Location = Control.MousePosition;
            //mf.Show();

            this.Select();
        }
        else if (mf.IsDisposed)
        {
            mf = new MagnifierMainForm(false);
            mf.StartPosition = FormStartPosition.Manual;
            mf.Location = Control.MousePosition;
            //mf.Show();
        }
        else
        {
            mf.Close();
            mf = null;
        }
    }
}

        void gkh_KeyUp(object sender, KeyEventArgs e)
        {
            controlDown = false;
        }

例如,当我运行我的应用程序并单击提示命令窗口然后单击 CTRL+M 或什至在几秒钟后不单击任何内容时,我遇到了异常:

CallbackOnCollectedDelegate 对“ScreenVideoRecorder!Utilities.globalKeyboardHook+keyboardHookProc::Invoke”类型的垃圾收集委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。将委托传递给非托管代码时,托管应用程序必须使它们保持活动状态,直到保证它们永远不会

检测到 CallbackOnCollectedDelegate 消息:对“ScreenVideoRecorder!Utilities.globalKeyboardHook+keyboardHookProc::Invoke”类型的垃圾收集委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。将委托传递给非托管代码时,托管应用程序必须使它们保持活动状态,直到保证它们永远不会被调用。

4

1 回答 1

1

我相信您正在寻找全局键盘挂钩。这是一个简单的 C# 用法示例

如果你使用globalKeyboardHook上面例子中的类,你需要做 4 件事:

首先将同名的 .cs 文件添加到您的项目中(并且由于该代码中存在错误,至少在 2007 年 5 月 30 日的版本中以以下方式对其进行修改 - 根据成员 4120854 的评论):

线下

public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);

添加这一行

private keyboardHookProc _keyboardHookProc;

并将钩子方法更改为如下所示:

public void hook()
{
    IntPtr hInstance = LoadLibrary("User32");
    _keyboardHookProc = new keyboardHookProc(hookProc);
    hhook = SetWindowsHookEx(WH_KEYBOARD_LL, _keyboardHookProc, hInstance, 0);
}

其次,在您的 Form 类中添加一个像这样的私有成员变量

globalKeyboardHook gkh = new globalKeyboardHook();

第三,在您的 Form_Load(或您想开始挂钩键的其他地方)上,将您想要的键添加到 gkh 类的 HookedKeys 集合属性并订阅 gkh 类的 KeyDown 和/或 KeyUp 事件,例如这个:

private void Form1_Load(object sender, EventArgs e) {
    gkh.HookedKeys.Add(Keys.LControlKey);
    gkh.HookedKeys.Add(Keys.RControlKey);
    gkh.HookedKeys.Add(Keys.M);
    gkh.KeyDown += new KeyEventHandler(gkh_KeyDown);
    gkh.KeyUp += new KeyEventHandler(gkh_KeyUp);
}

第四,然后您可以在 KeyUp 或 KeyDown 处理程序中执行您想要的操作,将 e.Handled 设置为 true 以停止在系统上传播键事件,如下所示:

void gkh_KeyUp(object sender, KeyEventArgs e) { // e.KeyCode.ToString() 是释放键的 KeyCode e.Handled = true; }

    void gkh_KeyDown(object sender, KeyEventArgs e) {
        // e.KeyCode.ToString() is the KeyCode of the pressed key
        e.Handled = true;
    }

要对特定的组合键执行某些操作,您需要在变量中记录键的状态,并在 KeyDown 时检查两个(或所有)键是否都已关闭。因此,对于“CTRL-M”,您将添加一个成员变量

bool controlDown = false;

然后您将此代码添加到您的 KeyDown 事件处理程序

if ((e.KeyCode == System.Windows.Forms.Keys.LControlKey) || (e.KeyCode == System.Windows.Forms.Keys.RControlKey))
{
    controlDown = true;
}

if (e.KeyCode == System.Windows.Forms.Keys.M && controlDown)
{
    // Do CTRL-M action
}

在 KeyUp 事件处理程序中,您需要添加这个

if ((e.KeyCode == System.Windows.Forms.Keys.LControlKey) || (e.KeyCode == System.Windows.Forms.Keys.RControlKey))
{
    controlDown = false;
}
于 2013-05-26T16:40:17.193 回答