如何使用 LowLevelKeyboardHook 挂钩 Win + Tab
Posted
技术标签:
【中文标题】如何使用 LowLevelKeyboardHook 挂钩 Win + Tab【英文标题】:How to hook Win + Tab using LowLevelKeyboardHook 【发布时间】:2014-11-28 02:35:17 【问题描述】:简而言之:在 Win + Tab 之后阻止 Win 使 Windows 认为 Win 仍然关闭, 所以然后按下 S 并按下 Win 键将打开搜索超级按钮,而不是只输入“s”...直到用户按下 Win 再次。 不 阻止它意味着将显示 Windows 开始菜单。我陷入了一个难题!
我使用 Alt + Tab 使用 LowLevelKeyboardHook
或 Win + Some Ubounded Key 使用RegisterHotKey
。只有使用LowLevelKeyboardHook
的Win 键才会出现问题。
在下面的示例中,当检测到 Win + Tab 组合时,我将接管 Win 向上事件。这会导致每次击键的行为都如同 Win 键仍然按下一样。
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
if (nCode != HC_ACTION)
return CallNextHookEx(_hookID, nCode, wParam, lParam);
var keyInfo = (Kbdllhookstruct)Marshal.PtrToStructure(lParam, typeof(Kbdllhookstruct));
if (keyInfo.VkCode == VK_LWIN)
if (wParam == (IntPtr)WM_KEYDOWN)
_isWinDown = true;
else
_isWinDown = false;
if (_isWinTabDetected)
_isWinTabDetected = false;
return (IntPtr)1;
else if (keyInfo.VkCode == VK_TAB && _isWinDown)
_isWinTabDetected = true;
if (wParam == (IntPtr)WM_KEYDOWN)
return (IntPtr)1;
else
_isWinTabDetected = true;
Console.WriteLine("WIN + TAB Pressed");
return (IntPtr)1;
return CallNextHookEx(_hookID, nCode, wParam, lParam);
你可以在这里找到完整的代码(注意它应该在一个空的 WinForms 项目中替换你的 Program.cs
来运行):https://gist.github.com/christianrondeau/bdd03a3dc32a7a718d62 - 按 Win + Tab 并且每次按下快捷方式时,Form
标题都会更新。
注意 intent 挂钩到这个特定组合是提供 Alt + Tab 替代方案而不替换 Alt kbd> + Tab 本身。提供使用 Win + Tab 启动自定义代码的能力的答案也将被接受。
这是我的想法,但我找不到相关文档。所有人都有可能成功回答我的问题。
告诉 Windows 在不实际触发的情况下“取消”Win 阻止 Windows 启动一次“开始”菜单 直接挂钩 Windows 的 Win + 事件,而不是手动挂钩击键(如果存在,这将是我的首选到目前为止)【问题讨论】:
【参考方案1】:系统需要知道您释放了 Windows 键。 我检查了我自己的钩子没有这个问题的区别,你和我的唯一区别是这一行:
if (_isWinTabDetected)
_isWinTabDetected = false;
return (IntPtr)1; //THIS LINE
【讨论】:
此解决方案不起作用,因为当 Windows 在没有快捷方式的情况下收到 Win 时,它会启动 Windows 开始菜单。您在示例中看不到的唯一原因是因为我使用了MessageBox
,而且似乎MessageBox
将取消Windows 菜单。我将更改示例以在Form1
中写一些东西...【参考方案2】:
这似乎完全符合您的要求(如果您愿意,可以省略 RWin)。
当您的应用失去焦点时,请体谅并取消注册此 KB 挂钩!
[DllImport("user32.dll")]
static extern short GetAsyncKeyState(System.Windows.Forms.Keys vKey);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
if (nCode == HC_ACTION)
var keyInfo = (Kbdllhookstruct) Marshal.PtrToStructure(lParam, typeof (Kbdllhookstruct));
if ((int) wParam == WM_KEYDOWN
&& keyInfo.VkCode == VK_TAB
&& (GetAsyncKeyState(Keys.LWin) < 0 || GetAsyncKeyState(Keys.RWin) < 0))
_mainForm.Text = "Win + Tab was pressed " + (++_winTabPressCounter) + " times";
return (IntPtr) 1;
return CallNextHookEx(_hookID, nCode, wParam, lParam);
在发现这种技术之前,我尝试了几件事。 这篇文章是最有帮助的https://***.com/a/317550/55721
【讨论】:
简而言之:按下 Win 键,而不是向上钩住 Win 键,并且不要阻止其他击键 :) 我删除了if (wParam == (IntPtr)WM_KEYDOWN) return (IntPtr)1;
和 if (keyInfo.VkCode == VK_LWIN)
中的另一个 return (IntPtr)1;
块,这也有效,尽管我认为您的代码更简单、更干净。我已经被困了 9 个月,所以我衷心感谢您花时间研究这个! (显然,解决方案很简单......)
嗯,我没有尝试你的建议。我考虑过,但假设捕获 winkey 会干扰其他 winkey 功能,如 winkey+R。你的方法允许吗?
是的。换句话说,当 Tab Down 发生时,我“记录”了 Win Down 而不是检查 Win Down 状态。这只会使相同行为的代码更难阅读,所以......你的更好!以上是关于如何使用 LowLevelKeyboardHook 挂钩 Win + Tab的主要内容,如果未能解决你的问题,请参考以下文章
如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]