使用 Winkey+L 的低级键盘挂钩/SendInput 可能吗?(工作站锁定在Vista及更高版本中被拦截) [英] Low-level Keyboard Hooks/SendInput with Winkey+L possible? (workstation lockout is intercepted in Vista and higher)

查看:27
本文介绍了使用 Winkey+L 的低级键盘挂钩/SendInput 可能吗?(工作站锁定在Vista及更高版本中被拦截)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从事一个名为 UAWKS(非官方 Apple 无线键盘支持)的项目,该项目有助于Windows 用户使用 Apple 的蓝牙键盘.UAWKS 的主要目标之一是将 Cmd 键(在 Windows 中表现为 Winkey)与 Ctrl 交换,允许用户执行 Cmd+C 用于复制,Cmd+T 用于新标签等

I work on a project called UAWKS (Unofficial Apple Wireless Keyboard Support) that helps Windows users use Apple's bluetooth keyboard. One of the main goals of UAWKS is to swap the Cmd key (which behaves as Winkey in Windows) with Ctrl, allowing users to do Cmd+C for copy, Cmd+T for new tab, etc.

它目前是使用 AutoHotkey 开发的,它在 Windows XP 下运行良好.但是,在 Vista 和 Windows 7 上,Cmd+L 会导致问题:

It is currently developed using AutoHotkey, which worked pretty well under Windows XP. However, on Vista and Windows 7, Cmd+L causes problems:

  • 无论低级键盘钩子如何,Win+L 总是被 Windows 拦截并正常锁定工作站...
  • 您可以使用禁用工作站锁定这个注册表破解,但是按Win+L仍然无法在AHK中反弹
  • Win+L 会使 Winkey 处于 Keydown 状态,直到下一个(额外的)Winkey Up.模拟 Keyup 事件似乎也不起作用!
  • Regardless of low-level keyboard hooks, Win+L is always intercepted by Windows and normally locks the workstation...
  • You can disable workstation locking with this registry hack, but pressing Win+L still can't be rebound in AHK
  • Pressing Win+L leaves Winkey in the Keydown state until the next (additional) Winkey Up. Simulating a Keyup event doesn't seem to work either!

似乎Win+L是一个特殊的和弦,把其他一切都搞砸了.

It seems that Win+L is a special chord that messes everything else up.

我查看了 AHK 源代码,他们尝试在 keyboard_mouse.cpp 中的 SendKey() 中解决这个问题(v1.0.48.05 中的第 883 行附近),但它没有不行.我用 C# 编写了自己的低级键盘钩子应用程序,我看到了同样的问题.

I've looked through the AHK source code, and they try to address this problem in SendKey() in keyboard_mouse.cpp (near line 883 in v1.0.48.05), but it doesn't work. I wrote up my own low-level keyboard hook application in C#, and I see the same problem.

有没有其他人遇到过这种情况?有解决方法吗?

Has anyone else run into this? Is there a workaround?

推荐答案

我想出了一种在 C# 中执行此操作的方法.可能的 Win+L 按键序列涉及四种状态(无、WinWin+LL).每当达到 Win+L 状态时,设置一个标志(下面的winLSet").每当释放所有按键时,我们都会检查此标志并模拟按下(如果已设置).

I figured out a way to do this in C#. There are four states involved in a possible Win+L keypress sequence (None, Win, Win+L, L). Whenever the Win+L state is reached, set a flag ("winLSet" below). Whenever all of the keys have been released, we check for this flag and simulate the press if it's been set.

最后一块拼图是在Ctrl-L(没有KeyDown)之前模拟WinKey 的KeyUp.我在 AutoHotkey 中尝试过类似的方法,但从未奏效,但在这里似乎完美无缺.

The final piece of the puzzle is to simulate the WinKey's KeyUp before the Ctrl-L (no KeyDown). I've tried similar approaches in AutoHotkey and it never worked, but it seems to work perfectly here.

代码如下.如果您打算使用此代码,请参阅底部的说明.

The code is below. Please see explanatory notes at the bottom if you plan to use this code.

public partial class MainWindow : Window
{
    LowLevelKeyboardHook hook;

    bool winKeyDown;
    bool lKeyDown;
    bool winLSet;

    public MainWindow()
    {
        InitializeComponent();

        hook = new LowLevelKeyboardHook();

        hook.KeyDown += OnKeyDown;
        hook.KeyUp += OnKeyUp;
    }

    void OnKeyDown(object sender, LowLevelKeyEventArgs e)
    {
        e.EventHandled = true;

        switch (e.Key)
        {
            case Key.L:
                lKeyDown = true;
                UpdateWinLState();
                e.EventHandled = winKeyDown;
                break;

            case Key.LWin:
                winKeyDown = true;
                UpdateWinLState();
                InputSimulator.SimulateKeyDown(VirtualKeyCode.LCONTROL);
                break;

            case Key.LeftCtrl:
                InputSimulator.SimulateKeyDown(VirtualKeyCode.LWIN);
                break;

            default:
                e.EventHandled = false;
                break;
        }
    }

    void OnKeyUp(object sender, LowLevelKeyEventArgs e)
    {
        e.EventHandled = true;

        switch (e.Key)
        {
            case Key.L:
                lKeyDown = false;
                UpdateWinLState();
                e.EventHandled = winKeyDown;
                break;

            case Key.LWin:
                winKeyDown = false;
                UpdateWinLState();
                InputSimulator.SimulateKeyUp(VirtualKeyCode.LCONTROL);
                break;

            case Key.LeftCtrl:
                InputSimulator.SimulateKeyUp(VirtualKeyCode.LWIN);
                break;

            default:
                e.EventHandled = false;
                break;
        }
    }

    void UpdateWinLState()
    {
        if (winKeyDown && lKeyDown)
        {
            winLSet = true;
        }
        else if (!winKeyDown && !lKeyDown && winLSet)
        {
            winLSet = false;

            InputSimulator.SimulateKeyUp(VirtualKeyCode.LWIN);

            InputSimulator.SimulateModifiedKeyStroke(
                VirtualKeyCode.LCONTROL,
                (VirtualKeyCode)'L');
        }
    }
}

对于后代:请注意,此代码使用 InputSimulator 和 LowLevelKeyboardHook,它们不是来自 .NET 框架.LowLevelKeyboardHook 是我不久前写的一个类,它将全局 KeyDown 和 KeyUp 事件公开为 C# 事件.有类似的例子这里此处,可以找到一堆这里.

For posterity: please note that this code uses InputSimulator and LowLevelKeyboardHook, which are not from the .NET Framework. LowLevelKeyboardHook is a class I wrote a while back that exposes global KeyDown and KeyUp events as C# events. There are similar examples here, here, and a bunch can be found here.

另请注意,我使用的是 System.Windows.Input.Key,而不是 System.Windows.Forms.Keys,这可能会使某些人感到困惑.System.Windows.Input.Key 是 .NET 3.0 及更高版本中的新键枚举,而 System.Windows.Forms.Keys 是 Windows Forms 中的旧枚举.

Also notice that I'm using System.Windows.Input.Key, not System.Windows.Forms.Keys, which could confuse some people. System.Windows.Input.Key is the new enumeration of keys in .NET 3.0 and above, while System.Windows.Forms.Keys is the old enumeration from Windows Forms.

这篇关于使用 Winkey+L 的低级键盘挂钩/SendInput 可能吗?(工作站锁定在Vista及更高版本中被拦截)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆