【问题标题】:How can I deal with depressed Windows logo key when using `SendInput`?使用“SendInput”时如何处理按下的 Windows 徽标键?
【发布时间】:2010-05-26 16:40:32
【问题描述】:

我的应用程序使用SendInput 在其他应用程序中合成击键。这几乎可以工作,除了由于我无法更改的情况,发送输入时左 Windows 键将始终被物理按下。这意味着,例如,如果发送的击键是“d”键,则 Windows 会将击键视为其 Win+D 快捷方式并显示桌面,而“d”击键永远不会到达其预期目标。

文档中提到了这个问题,但令人沮丧的是如何解决这个问题(强调我的):

此函数不会重置键盘的当前状态。调用该函数时已按下的任何键都可能会干扰该函数生成的事件。为避免此问题,请使用GetAsyncKeyState 函数检查键盘的状态并根据需要更正

我应该如何“根据需要更正”?

我尝试使用SetKeyboardState 关闭VK_LWIN 键的键盘状态,首先将我的线程附加到我将击键发送到的窗口线程(使用AttachThreadInput),但是这似乎根本不会影响行为。

我还尝试在使用SendInput 发送的输入的开头插入KEYEVENTF_KEYUP 事件,但这会导致开始菜单弹出并获取焦点,这显然是不可接受的。

在调用 SendInput 时处理按下的 Windows 徽标键的正确方法是什么?

编辑:

根据@Brian's answer,我可以通过安装一个捕获win-key keydown 事件的低级keyhook 来防止win 键干扰我的代码。

但是,这会产生不希望的效果,即 Windows 键现在已完全禁用。我可以设想一些解决方案,我记下我的 keyhook 中所有键的状态,并在按下其他键时模拟 windows 键的按下,这取决于它们是否是我的键模拟,但这对我来说听起来像是一个黑客。或者,我可以使用我的 keyhook 来模拟重要的 Windows 键盘快捷键。

但是文档暗示它应该以更直接的方式工作。 Brian 的解决方案是首先防止 win 键进入按下状态。但是文档指出您应该能够检查它是否被按下,如果是则更正它。

真的可以做到吗?

【问题讨论】:

  • 我喜欢把我郁闷的钥匙拿出来吃冰淇淋,这通常会让他们感觉更好。

标签: c++ windows winapi


【解决方案1】:

I basically solved this exact problem yesterday :) 我的代码是用 C# 编写的,但它主要由通过 p/invoke 调用的 win32 API 组成,因此它应该直接转换为 C++。

解决方案是使用Low-Level Keyboard Hook 拦截初始 Windows 键 KeyDown 事件(并告诉操作系统您已处理它,这样它就不会传递给其他应用程序和/或操作系统)。然后,根据操作系统,在输入之前模拟 Windows 键 KeyUp 事件。听起来你已经完成了一半,你只需要拦截初始的 KeyDown。

我的解决方案针对的是 Windows Vista 和 Windows 7,因此如果您使用的是 XP 或更低版本,则可能不需要发送 KeyUp。这就是我将很快测试的内容,它可能适用于两者;但是,Vista 和 7 比 XP 更积极地拦截 windows 键,因此我怀疑。

【讨论】:

  • @Brian。谢谢。我正在 Windows 7 上开发。如果我​​使用低级键盘挂钩拦截 KeyDown,那么我的代码可以正常工作(无需模拟 KeyUp)。但是,这意味着 Windows 键被完全禁用,理想情况下我希望 Windows 键的功能不受影响。此外,文档指出您应该在调用 SendInput 之前立即“根据需要进行更正”。你认为这实际上是不可能的吗?
  • 你可以只在你需要的特定情况下拦截Windows键,否则让它通过。然后您保留正常功能。要让它通过,请使用 CallNextHookEx (msdn.microsoft.com/en-us/library/ms644974(v=VS.85).aspx) 结束您的处理程序过程
  • @Brian,但是当按下 Windows 键时,我不知道它是否会成为我需要的特定情况之一。我只有在我决定打电话给SendInput 时才发现这一点,那是在 Windows 键已经被按住之后。
  • 您必须通过 KeyDown/KeyUp 周期跟踪您关心的键的状态。如果您阅读了我的原始答案,那么我正是使用 WinKey+L 组合来执行此操作的。 WinKey 仍然适用于所有其他组合,并且按预期的功能是您在没有组合的情况下按下并释放它(打开“开始”菜单)。唯一的缺点是“WinKey down”消息被延迟,但只有在“WinKey up”被拦截后才会发送。幸运的是,“WinKey down”对于大多数用途来说并不是一个非常重要的事件。
  • 但是你的要求和我的不同。您正在交换 Win 和 Ctrl 键。如果按住实际的 Windows 键并按 D 会发生什么?在这种情况下,您将捕获 Windows 按键并模拟 Ctrl+D 事件。我需要 some win 按键才能正常工作,但要重新映射 other 按键。您正在将它们中的 all 重新映射到 Ctrl 按下。 (反之亦然)或者我错过了您的原始答案?
【解决方案2】:

没有更“直接的方式”让程序在不修改注册表的情况下执行此操作。理想的解决方案是跟踪表中的按键(std::map、Dictionary 等)。 MS 这样做的目的是防止病毒/恶意软件控制键盘并防止用户使用重要的键盘组合,例如 WinKey-L 和 Ctrl-Alt-Delete。

但是,如果键盘挂钩不适合您,您可以在注册表中重新映射键盘扫描代码。这并不理想,因为它很难逆转(特别是如果您犯了错误,或者您的程序崩溃,或者用户卸载了应用程序但注册表黑客未还原)。但它确实有效。以下是一些参考资料:

http://www.howtogeek.com/howto/windows-vista/map-any-key-to-any-key-on-windows-xp-vista/

http://www.howtogeek.com/howto/windows-vista/disable-caps-lock-key-in-windows-vista/

http://www.usnetizen.com/fix_capslock.php

【讨论】:

  • 我看不出重新映射键盘扫描代码对我有什么帮助。我希望 Win 键不影响我使用 SendInput 模拟的输入,但我仍然希望它正常工作。
【解决方案3】:

通过插入KEYEVENTF_KEYUP 事件“更正”修饰键的状态可能会产生副作用,但可以通过插入额外事件来避免。

当 Win 键被按下和释放时触发开始菜单,除了当有一个干预键事件或如果它被按下与另一个修饰符组合。因此,不要只插入 Win-up,而是插入 Ctrl-downWin-upCtrl-up

除了开始菜单,释放修饰键可能还有其他副作用:

  • 释放 Alt 可以激活活动窗口的菜单(即使它似乎没有菜单)。
  • 释放 Alt 或 Shift 可以激活 Alt+Shift 语言热键。
  • 松开 Ctrl 或 Shift 可以激活 Ctrl+Shift 语言热键。
  • 释放任何修饰键可以激活 Office 热键(在 Windows 1903 及更高版本中,按住并释放 Ctrl+Alt+Shift+Win 会打开 Office 应用程序)。

首先插入带有几乎任何其他虚拟键码的按键和按键(或者可能只是没有事先按键的按键)通常会阻止这些热键中的任何一个激活。可以使用未定义或保留的键码,例如 0xE8,但仍有被其他程序使用的风险。

【讨论】:

    猜你喜欢
    • 2020-07-08
    • 1970-01-01
    • 2013-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    相关资源
    最近更新 更多