可以使用Winkey + L的低级键盘挂钩/ SendInput?(工作站锁定在Vista及更高版本中被截获)

Bri*_*sen 6 c# winapi autohotkey keyboard-hook windows-7

我正在开展一个名为UAWKS(非官方Apple无线键盘支持)的项目,帮助Windows用户使用Apple的蓝牙键盘.UAWKS的主要目标之一是交换Cmd密钥(其行为与WinkeyWindows一样)Ctrl,允许用户执行Cmd+ C复制,Cmd+ T选择新选项卡等.

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

  • 无论低级键盘挂钩,Win+ L总是被Windows拦截并且通常锁定工作站......
  • 您可以使用此注册表黑客禁用工作站锁定,但按下Win+ L仍然无法在AHK中反弹
  • 在Keydown状态下按Win+ 键L离开Winkey,直到下一个(额外的)Winkey Up.模拟Keyup事件似乎也不起作用!

似乎Win+ L是一个特殊的和弦,其他一切混乱.

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

有没有其他人遇到这个?有解决方法吗?

Bri*_*sen 2

我想出了一种用 C# 来做到这一点的方法。Win可能的+按键序列涉及四种状态L(无、WinWin+ LL)。每当达到Win+状态时,设置一个标志(下面的“winLSet”)。L每当所有按键被释放时,我们都会检查此标志并模拟按下(如果已设置)。

最后一个难题是在Ctrl-之前模拟 WinKey 的 KeyUp L(无 KeyDown)。我在 AutoHotkey 中尝试过类似的方法,但它从未起作用,但它似乎在这里完美工作。

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

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');
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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