How to reliably steal/regain focus for MFC/desktop app on Windows 8.1/10?
好吧,我明白了:窃取焦点是邪恶的。或者至少是 99.9% 的时间。但我确实需要在 Windows 8 上可靠地窃取焦点,而到目前为止,我被一大群坚持窃取焦点总是邪恶的人所挫败。
场景:我们在运行 Windows 8.1(即将成为 Windows 10)的普通 PC 上运行自定义应用程序。屏幕、键盘和鼠标位于离地面大约 5m 的一些楼梯上,叉车操作员确实不应该爬上这些楼梯。他们拥有的一个输入设备是延长电缆上的数字键盘,位于他们的水平。他们需要做的所有事情都可以通过该键盘完成......只要某些恶意程序没有窃取我们应用程序的焦点,或者某个远程用户没有注销并离开另一个应用程序的焦点。
该应用程序本质上是一个最大化的桌面应用程序 - 它填满屏幕(但严格来说不是"全屏"或"最顶部"应用程序),因此允许其他应用程序在需要时出现在其前面.但是当鼠标空闲时,我们希望这个应用程序在所有其他应用程序前面恢复其"正常"位置,以便它获得焦点并且数字键盘输入将可靠地工作。
在 Windows 7 上,使用 SetForegroundWindow()(由 AllowSetForegroundWindow() 启用可以正常工作 - 应用程序可以回到前面并恢复焦点。在 Windows 8 上,SetForegroundWindow() 只会导致任务栏图标闪烁,但应用程序没有重新获得焦点,迫使我们的用户爬楼梯......全键盘和鼠标太诱人了,他们不应该按下他们不应该按下的按钮,并且通常会出现混乱。
所以请先生:一旦鼠标空闲 1 分钟,我们的(MFC,桌面)应用程序能否夺回焦点,因为它或多或少是唯一应该正常运行的应用程序。如果允许,我们如何可靠地窃取它?
- 作为一个想法,启动一个不相关的最顶层窗口,将键盘命令中继到您认为应该获取它们的窗口;它会在鼠标移动时消失,并在鼠标空闲 1 分钟后重生吗?我不知道这是否可行;我最后一次做这种黑客是为了在 ProgressQuest 上作弊的 windows XP(我相信我们负责产生臭名昭著的大厅)
-
必须提出一个问题——在您的应用程序是从网络魔术神经外科叉车手术刀操作员那里窃取焦点的邪恶程序之前,您的应用程序需要多少产品周期?
-
@omatai您可以尝试在所述Windows 8.1机器上将 HKEY_CURRENT_USER\\Control Panel\\Desktop\\ForegroundLockTimeout 设置为 0 。
-
您可以尝试在这里询问:social.technet.microsoft.com/forums/en-us/home 或超级用户。但是一个不同的问题:即"我怎样才能使 Windows 8.1/10 安装在焦点窃取方面表现得像 Windows XP"这个问题在这里是合适的,我只是认为你可能会更幸运地询问如何解决这个问题一个用户,然后从那里向后工作。
-
我敢打赌这是一个 X/Y 问题:叉车操作员可能正在使用条形码扫描仪,通过键盘提供输入?出于这个原因,这几乎总是糟糕的设计选择。扫描仪是否有其他接口,如串口?它确实更容易,更易于维护,与其他软件更兼容(即使您的应用程序有 99% 的时间都在使用,但仍然只有 1%)。我必须同意你试图避免的 - 不要这样做。
-
@zzxyz 如何以编程方式将焦点传递给我选择的应用程序是一个编程问题。这也可能是一个 su 问题。他有一个过去可以工作的 API,现在不再工作了。
-
@Yakk-AdamNevraumont - 我完全同意你所说的,并没有试图暗示这个问题在这里是错误的。我试图帮助扩大潜在答案的范围,因为我有一种预感——可能是错的——更多的人知道如何通过管理而不是编程解决这个问题(需要继续像以前一样运行的旧应用程序等)
-
@Steve - 这不是 X/Y 问题。没有条形码扫描仪。叉车操作员在他移动的臭垃圾上找不到条形码,如果他尝试过。他真的只是想要一个简单的开关来从一个垃圾箱填充到另一个垃圾箱,但我们给了他一个数字键盘,因为我们可以预见未来需要的附加功能有限。该解决方案在 Win XP 和 Win 7 上运行良好;它不再适用于 Win 8。我们可以让它工作吗?这就是问题所在。
-
您知道,有消费级(可能还有工业级)USB 设备带有一个按钮,您可以做任何您想做的事情,包括向您的程序发送某种信号......
-
太好了:如果我可以做任何我想做的事,我想抢走焦点:-) 我该怎么做?
-
最干净的选择是完全不依赖输入焦点。大概,您知道您的应用程序应该响应的硬件设备。您可以设置原始输入,过滤到特定的硬件设备,并让消息处理程序调用所需的应用程序操作。使用 RIDEV_INPUTSINK 标志允许调用者接收输入,即使调用者不在前台。
-
@yak:您不能以您建议的方式可靠地中继输入:重播输入与重新处理输入不同。
-
@IInspectable 这可能是真的,但是您的链接谈到重播而不是中继。
-
@yak:您如何建议在不重播的情况下中继输入?一旦你的最顶层窗口处理了输入,你就没有第二次机会来处理它了。
在数字小键盘 (RegisterHotKey) 上配置热键。
按下注册的热键给你Raymond Chen的前台激活之爱
After you call the RegisterHotKey function to register a hotkey, the
window manager will send you a WM_HOTKEY message when the user presses
that hotkey, and along with it, you will get the foreground love. If
you call SetForegroundWindow from inside your hotkey handler, the
foreground window will change according to your instructions.
-
这看起来令人鼓舞,特别是如果一个人可以合成一个热键并发送它......这感觉像是一种合法的作弊形式。太忙了,现在没时间尝试,也可以通过什么都不做得到一个可以接受的解决方案......
-
铬项目似乎也在使用这种技术:cs.chromium.org/chromium/src/ui/base/win/
可能的解决方案(有很大的限制):什么都不做;等等。
我们的一位服务技术人员观察到,在第三次或第四次尝试使用 AllowSetForegroundWindow() 和 SetForegroundWindow() 重新获得焦点时,Windows 8 最终允许我们的应用程序重新获得焦点。目前尚不清楚使这项工作的条件是什么,或者它是否可靠地工作,但我们现在已经观察到我们的应用程序从 Chrome 下方、另一个(自行开发的)MFC 应用程序下方以及第三方应用程序下方重新获得焦点- 所有桌面应用程序。在将焦点交还给我们的(桌面)应用程序之前,每种情况都需要大约 3-4 分钟。
但是,我们没有目睹它从 Metro 应用程序下方重新获得焦点,我们也没有预料到它(例如,按下 Windows 键并让系统停留在"开始"屏幕上)。
在我们(??受限)的情况下,我们愿意冒险保证我们的用户不会启动会遮盖我们桌面应用程序的 Metro 应用程序,至少在不恢复我们的应用程序的情况下不会,因为他们的业务依赖于它。我们主要担心的是,我们的一位忙碌的服务技术人员会远程登录,分心,并且不小心将我们的桌面实用程序之一留在焦点上。等待 3-4 分钟似乎是解决此特定情况的方法。
我会这样尝试:
在您的应用程序中设置一个计时器。定期检查 GetForegroundWindow 。
如果 GetForgroundWindow 不属于您的进程 (GetWindowThreadProcessId)
如果一个不同的进程在前台窗口上使用 AttachThreadInput 并将您的输入队列附加到另一个进程的输入队列。
现在使用 SetForegoundWindow 并再次分离线程输入。
现在您可以根据需要使用 SetFocus 来控制程序的输入焦点。
- 恕我直言,是的。取决于此"用户帐户控制:仅提升安装在安全位置的 UIAccess 应用程序"安全策略设置。更多信息:docs.microsoft.com/en-us/windows/security/threat-protection/