使用Winkey + L可能会发生低级键盘挂钩/ SendInput? (工作站锁定在Vista和更高版本中截获)

问题描述:

我在一个名为UAWKS(非官方Apple无线键盘支持)的项目上工作,该项目可帮助Windows用户使用Apple的蓝牙键盘。一个UAWKS的主要目标是按Ctrl来交换Cmd的密钥(表现为维琪在Windows中),让用户做Cmd的 + Ç复印,Cmd的 + ŧ新标签等使用Winkey + L可能会发生低级键盘挂钩/ SendInput? (工作站锁定在Vista和更高版本中截获)

它目前使用AutoHotkey开发,在Windows XP下工作得很好。然而,在Vista和Windows 7,Cmd的 + 大号导致问题:

  • 不管低级键盘钩子, + 大号总是由Windows截获,通常锁定工作站。 ..
  • 您可以禁用工作站this registry hack锁定,但按 + 大号仍然无法AHK
  • 将反弹
  • + L将Winkey留在Keydown状态,直到下一个(附加)Winkey Up。模拟Keyup事件似乎也不起作用!

似乎 + 大号是一个特殊的弦是弄乱一切了。

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

有没有其他人遇到过这个问题?有没有解决方法?

+0

我应该补充说,在AutoHotkey.com上有论坛帖子,但解决方案不是过时就是不正确(见下文)。 此外,我的问题并不仅限于AutoHotkey。我最终希望用C#重新实现整个程序。这是一个关于Windows Vista和Windows 7如何以不同方式对待Winkey + L的问题,以及是否有人已经看到/解决过这个问题。 http://www.autohotkey.com/forum/viewtopic.php?t=27554&highlight=winkey http://www.autohotkey.com/forum/viewtopic.php?t=15513&postdays=0&postorder=asc&start=0 – 2010-05-25 15:51:27

我想出了一种在C#中执行此操作的方法。有四个状态参与可能 + 大号按键序列(无, + 大号大号)。每当赢得 + L状态,设置一个标志(下面的“winLSet”)。每当所有的钥匙都被释放后,我们检查这个标志,并且如果它已经被设定,模拟这个按下。

最后一块拼图是Ctrl键之前模拟WINKEY的KEYUP - 大号(无的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'); 
     } 
    } 
} 

为后人:请注意,此代码使用InputSimulator和LowLevelKeyboardHook,这是不是从.NET框架。 LowLevelKeyboardHook是我后来写的一个类,它将全局KeyDown和KeyUp事件公开为C#事件。有类似的例子here,here,并且可以发现一堆here

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

如果可以检测Cmd的 + 关键大号你可以先走一步,锁定工作站,而不会打扰转发维琪 + 大号?您可以使用API​​ LockWorkstation(或rundll32.exe user32.dll,LockWorkStation

+0

其实,我试图阻止工作站锁定。我可以通过注册表黑客来做到这一点,但是当你按下Winkey + L/Cmd + L时,Winkey状态仍然会变得混乱(他们是一样的;我在Cmd和Winkey上面互换地使用,对于混淆抱歉。一个叫做Cmd的苹果键盘,但Windows键盘驱动程序将其解释为Winkey。) – 2010-05-25 16:06:33

我试图使用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键充当shift键(如实施&预期)在Win XP。
冲压WinKey + l仅返回L

编辑:但是,我可以证实你的观察,即此代码在Windows 7下无法运行:/对不起,我无法再帮你了。

+0

谢谢,但我实际上是在使用InputSimulator来处理我的沙盒C#应用程序。出于某种原因,Winkey在我调用InputSimulator.SimulateKeyDown(vkCode)之前就会卡住,所以效果最终变成了Winkey + vkCode。这只发生在Winkey + L上。 – 2010-05-25 16:04:23

+0

非常感谢,谢谢! – 2010-05-25 16:10:05