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

时间:2010-05-25 15:39:57

标签: c# winapi windows-7 autohotkey keyboard-hook

我正在研究一个名为UAWKS(非官方Apple无线键盘支持)的项目,该项目可帮助Windows用户使用Apple的蓝牙键盘。 UAWKS的主要目标之一是使用 Ctrl 交换 Cmd 键(在Windows中表现为 Winkey ),允许用户执行<用于复制的kbd> Cmd + C ,用于新选项卡的 Cmd + T

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

  • 无论低级键盘挂钩如何, Win + L 总是被Windows拦截并且通常会锁定工作站......
  • 您可以使用this registry hack禁用工作站锁定,但按 Win + L 仍然无法在AHK中反弹
  • Win + L 将Winkey保持在Keydown状态,直到下一个(额外的)Winkey Up。模拟Keyup事件似乎也不起作用!

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

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

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

3 个答案:

答案 0 :(得分:2)

我想出了一种在C#中实现这一目标的方法。可能的 Win + L 按键序列涉及四种状态(无, Win Win + L L )。每当达到 Win + L 状态时,设置一个标志(下面的“winLSet”)。每当所有的钥匙都被释放后,我们会检查这个标志并模拟按下它是否已经设定。

最后一个难题是在 Ctrl - L (无KeyDown)之前模拟WinKey的KeyUp。我在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');
        }
    }
}

对于后代:请注意,此代码使用InputSimulator和LowLevelKeyboardHook,它们不是来自.NET Framework。 LowLevelKeyboardHook是我之前写的一个类,它将全局KeyDown和KeyUp事件公开为C#事件。有类似的示例herehere,可以找到一堆here

还要注意我使用的是System.Windows.Input.Key,而不是System.Windows.Forms.Keys,这可能会让一些人感到困惑。 System.Windows.Input.Key是.NET 3.0及更高版本中新的密钥枚举,而System.Windows.Forms.Keys是Windows Forms中的旧枚举。

答案 1 :(得分:0)

如果您能够检测到键 Cmd + L ,您可以直接锁定工作站而无需转发 Winkey + ?您可以使用API​​ LockWorkstation(或rundll32.exe user32.dll,LockWorkStation

来完成此操作

答案 2 :(得分:0)

我尝试使用Windows Input Simulator库中断Windows密钥。这是我的回调:

private static unsafe IntPtr HookCallback( int nCode, IntPtr wParam, IntPtr lParam )
{
    if( nCode >= 0 && ( wParam == (IntPtr)WM_KEYDOWN ) )
    {
        var replacementKey = (KBDLLHOOKSTRUCT*)lParam;
        if( replacementKey->vkCode == (int)VirtualKeyCode.LWIN )
        {
            InputSimulator.SimulateKeyDown( VirtualKeyCode.SHIFT );
            return (IntPtr)1;
        }
    }
    return CallNextHookEx( m_HookID, nCode, wParam, lParam );
}

使用此挂钩,我的左侧Windows键在Win XP下充当shift键(已实现和预期) 按 WinKey + l 仅返回L

编辑:但是,我可以确认您的观察,此代码在Windows 7下无效:/抱歉,我无法再帮助您。