问题
OK, I get it: focus stealing is evil. Or at least it is 99.9% of the time. But I really need to steal the focus reliably on Windows 8, and so far I'm thwarted by the hordes of people insisting focus stealing is always evil.
Scenario: we run a custom application on an ordinary PC running Windows 8.1 (soon to be Windows 10). The screen, keyboard and mouse sit roughly 5m off the ground up some stairs that the forklift operator really shouldn't climb. The one input device they have is a numeric keypad on an extender cable down at their level. Everything they need to do they can do from that keypad... so long as some evil program hasn't stolen our application's focus, or some remote user hasn't logged out and left another application with focus.
The application is essentially a maximised desktop application - it fills the screen (but is not strictly a "full screen" or "topmost" application), and therefore allows other applications to appear in front of it when required. But when the mouse goes idle, we want this application to resume its "normal" position in front of all other applications so that it gets focus and the numeric keypad input will work reliably.
On Windows 7, using SetForegroundWindow()
(enabled by AllowSetForegroundWindow()
works fine - the application can be brought back to the front and resume focus. On Windows 8, SetForegroundWindow()
only results in the taskbar icon flashing, but the application does not regain focus, forcing our user to climb the stairs... where the full keyboard and mouse is too tempting for them not to press buttons they shouldn't, and chaos typically ensues.
So please sir: can our (MFC, desktop) application steal back the focus once the mouse has gone idle for 1 minute, because it is more or less the only application that should normally be running anyway. If that is permitted, how do we steal it reliably?
回答1:
Configure hotkeys on numeric keypad (RegisterHotKey
).
Pressing a registered hotkey gives you the foreground activation love by 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.
回答2:
Possible solution (with major limitations): do nothing extra; wait.
One of our service technicians observed that on the third or fourth attempt to regain focus using AllowSetForegroundWindow()
and SetForegroundWindow()
as had been working on Windows 7, Windows 8 finally allowed our application to regain focus. It is not clear what the conditions are that make this work, or if it works reliably, but we have now observed our application regaining focus from beneath Chrome, from beneath another (self-developed) MFC application, and from beneath a third party application - all desktop applications. Approximately 3-4 minutes needed to elapse in each case before focus was surrendered back to our (desktop) application.
However, we have not witnessed it regain focus from beneath metro applications, and nor do we expect it (e.g. hit the Windows key and leave the system lingering on the Start screen).
In our (restricted) situation, we are willing to take the gamble that our users will not launch a metro application that obscures our desktop application, at least not without restoring our application, since their business relies on it. Our main concern is that one of our busy service technicians will log in remotely, get distracted, and carelessly leave one of our desktop utilities with the focus. Waiting 3-4 minutes appears to be a solution to this specific scenario.
回答3:
I would try it in this way:
- Setup a timer in you application. That checks
GetForegroundWindow
on a regular basis. - If
GetForgroundWindow
does not belong to your process (GetWindowThreadProcessId
) - If a different process onws the foreground window use
AttachThreadInput
and attach your input queue to the input queue of the other process. - Now use
SetForegoundWindow
and detach the thread input again. - Now you can use
SetFocus
as needed to control the input focus of your program.
来源:https://stackoverflow.com/questions/52285448/how-to-reliably-steal-regain-focus-for-mfc-desktop-app-on-windows-8-1-10