使用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#编写了自己的低级键盘钩子应用程序,并且看到了同样的问题。
有没有其他人遇到过这个问题?有没有解决方法?
我想出了一种在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
)
其实,我试图阻止工作站锁定。我可以通过注册表黑客来做到这一点,但是当你按下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下无法运行:/对不起,我无法再帮你了。
谢谢,但我实际上是在使用InputSimulator来处理我的沙盒C#应用程序。出于某种原因,Winkey在我调用InputSimulator.SimulateKeyDown(vkCode)之前就会卡住,所以效果最终变成了Winkey + vkCode。这只发生在Winkey + L上。 – 2010-05-25 16:04:23
非常感谢,谢谢! – 2010-05-25 16:10:05
我应该补充说,在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