如何使用 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 使用 LowLevelKeyboardHookWin + Some Ubounded Key 使用RegisterHotKey。只有使用LowLevelKeyboardHookWin 键才会出现问题。

在下面的示例中,当检测到 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的主要内容,如果未能解决你的问题,请参考以下文章

如果加入条件,我该如何解决。如果使用字符串连接,我如何使用

如何使用本机反应创建登录以及如何验证会话

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?

如何使用laravel保存所有行数据每个行名或相等

如何使用 Math.Net 连接矩阵。如何使用 Math.Net 调用特定的行或列?