Preventing applications from stealing focus
Are there any solutions to prevent applications stealing focus from the active window?
This is especially annoying when I'm starting an application, switch to do something else and the new application starts receiving half a sentence of text.
Solution 1:
This is not possible without extensive manipulation of Windows internals and you need to get over it.
There are moments in daily computer use when it is really important that you make one action before the operating system allows you to do another. To do that, it needs to lock your focus on certain windows. In Windows, control over this behavior is largely left to the developers of the individual programs that you use.
Not every developer makes the right decisions when it comes to this topic.
I know that this is very frustrating and annoying, but you can't have your cake and eat it too. There are probably many cases throughout your daily life where you're perfectly fine with the focus being moved to a certain UI element or an application requesting that the focus remains locked on it. But most applications are somewhat equal when it comes to deciding who is the lead right now and the system can never be perfect.
A while ago I did extensive research on solving this issue once and for all (and failed). The result of my research can be found on the annoyance project page.
The project also includes an application that repeatedly tries to grab focus by calling:
switch( message ) {
case WM_TIMER:
if( hWnd != NULL ) {
// Start off easy
// SetForegroundWindow will not move the window to the foreground,
// but it will invoke FlashWindow internally and, thus, show the
// taskbar.
SetForegroundWindow( hWnd );
// Our application is awesome! It must have your focus!
SetActiveWindow( hWnd );
// Flash that button!
FlashWindow( hWnd, TRUE );
}
break;
As we can see from this snippet, my research was also focused on other aspects of user interface behavior I don't like.
The way I tried to solve this was to load a DLL into every new process and hook the API calls that cause another windows to be activated.
The last part is the easy one, thanks to awesome API hooking libraries out there. I used the very great mhook library:
#include "stdafx.h"
#include "mhook-2.2/mhook-lib/mhook.h"
typedef NTSTATUS( WINAPI* PNT_QUERY_SYSTEM_INFORMATION ) (
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__inout PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
);
// Originals
PNT_QUERY_SYSTEM_INFORMATION OriginalFlashWindow =
(PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress(
::GetModuleHandle( L"user32" ), "FlashWindow" );
PNT_QUERY_SYSTEM_INFORMATION OriginalFlashWindowEx =
(PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress(
::GetModuleHandle( L"user32" ), "FlashWindowEx" );
PNT_QUERY_SYSTEM_INFORMATION OriginalSetForegroundWindow =
(PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress(
::GetModuleHandle( L"user32" ), "SetForegroundWindow" );
// Hooks
BOOL WINAPI
HookedFlashWindow(
__in HWND hWnd,
__in BOOL bInvert
) {
return 0;
}
BOOL WINAPI
HookedFlashWindowEx(
__in PFLASHWINFO pfwi
) {
return 0;
}
BOOL WINAPI
HookedSetForegroundWindow(
__in HWND hWnd
) {
// Pretend window was brought to foreground
return 1;
}
BOOL APIENTRY
DllMain(
HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
) {
switch( ul_reason_for_call ) {
case DLL_PROCESS_ATTACH:
Mhook_SetHook( (PVOID*)&OriginalFlashWindow, HookedFlashWindow );
Mhook_SetHook( (PVOID*)&OriginalFlashWindowEx, HookedFlashWindowEx );
Mhook_SetHook( (PVOID*)&OriginalSetForegroundWindow, HookedSetForegroundWindow );
break;
case DLL_PROCESS_DETACH:
Mhook_Unhook( (PVOID*)&OriginalFlashWindow );
Mhook_Unhook( (PVOID*)&OriginalFlashWindowEx );
Mhook_Unhook( (PVOID*)&OriginalSetForegroundWindow );
break;
}
return TRUE;
}
From my tests back then, this worked great. Except for the part of loading the DLL into every new process. As one might imagine, that's nothing to take too lightly. I used the AppInit_DLLs approach back then (which is simply not sufficient).
Basically, this works great. But I never found the time to write something that properly injects my DLL into new processes. And the time invested in this largely overshadows the annoyance the focus stealing causes me.
In addition to the DLL injection problem, there is also a focus-stealing method which I didn't cover in the implementation on Google Code. A co-worker actually did some additional research and covered that method. The problem was discussed on SO: https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus
Solution 2:
In Windows 7, the ForegroundLockTimeout
registry entry is no longer checked, you can verify this with Process Monitor. In fact, in Windows 7 they disallow you from changing the foreground window. Go and read about its details, it has even been there since Windows 2000.
However, the documentation sucks and they chase each other and find ways around that.
So, there is something buggy going on with SetForegroundWindow
, or similar API functions...
The only way to really do this properly is to make a small application which periodically calls LockSetForegroundWindow
, virtually disabling any calls to our buggy API function.
If that's not enough (another buggy API call?) you can go even further and do some API monitoring to see what's going on, and then you simply hook the API calls on every process after which you can get rid of any calls that mess up the foreground. However, ironically, this is discouraged by Microsoft...
Solution 3:
There is an option in TweakUI which does this. It prevents most of the usual tricks dubious software developers employ to force focus on their app.
It's an ongoing arms war though, so I don't know if it works for everything.
Update: According to EndangeredMassa, TweakUI does not work on Windows 7.
Solution 4:
I believe that some confusion may exist, as there are two ways of "stealing focus" : (1) a window coming to the foreground, and (2) the window receiving keystrokes.
The problem referred to here is probably the second one, where a windows claims the focus by bringing itself to the foreground - without the user's request or permission.
The discussion must split here between XP and 7.
Windows XP
In XP there is a registry hack that makes XP work the same as Windows 7 in preventing applications from stealing focus :
- Use regedit to go to:
HKEY_CURRENT_USER\Control Panel\Desktop
. - Double-click on
ForegroundLockTimeout
and set its value in hexadecimal to30d40
. - Press OK and exit regedit.
- Reboot your PC for the changes to take effect.
Windows 7
(The discussion below mostly applies to XP as well.)
Please understand that there is no way in which Windows can totally block applications from stealing the focus and remain functional. For example, if during a file-copy your anti-virus detected a possible threat and would like to pop-up a window asking you for the action to take, if this window is blocked then you would never understand why the copy never terminates.
In Windows 7 there is only one modification possible to the behavior of Windows itself, which is
to use the MS-Windows focus-follows-mouse Registry hacks, where the focus and/or activation goes always to the windows under the cursor. A delay can be added to avoid applications popping up all over the desktop.
See this article : Windows 7 - Mouse Hover Makes Window Active - Enable.
Otherwise, one must detect and neutralize the guilty program : If this is always the same application that is getting the focus, then this application is programmed to take the focus and preventing this may be done by either disabling it from starting with the computer, or use some setting supplied by that application to avoid this behavior.
You could use the VBS script included in VB Code which identifies who's stealing focus, which the author used to identify the culprit as a "call home" updater for a printer software.
A desperate measure when all else fails, and if you have identified this badly-programmed application, is to minimize it and hope that will not then bring itself to the front. A stronger form of minimization is to the tray by using one of the free products listed in Best Free Application Minimizer.
Last idea in the order of desperation is to fracture your desktop virtually by using a product such as Desktops or Dexpot, and do your work in another desktop than the default.
[EDIT]
As Microsoft has retired the Archive Gallery, here is the above VB code reproduced :
Declare Auto Function GetForegroundWindow Lib "user32.dll" () As Integer
Declare Auto Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As Integer, ByRef procid As Integer) As UInteger
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.RichTextBox1.AppendText("Starting up at " & Now & vbCrLf)
End Sub
Private Sub GoingAway(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Deactivate, Me.LostFocus
Dim hwnd As Integer = GetForegroundWindow()
' Note that process_id will be used as a ByRef argument
' and will be changed by GetWindowThreadProcessId
Dim process_id As Integer = 1
GetWindowThreadProcessId(hwnd, process_id)
If (process_id <> 1) Then
Dim appExePath As String = Process.GetProcessById(process_id).MainModule.FileName()
Me.RichTextBox1.AppendText("Lost focus at " & Now & " due to " & appExePath & vbCrLf)
Else
Me.RichTextBox1.AppendText("Lost focus due to unknown cause.")
End If
End Sub
Solution 5:
Inspired by Der Hochstapler's answer, I decided to write a DLL injector, that works with both 64 and 32-bit processes and prevents focus stealing on Windows 7 or newer: https://blade.sk/stay-focused/
The way it works is it watches for newly created windows (using SetWinEventHook
) and injects DLL very similar to Der Hochstapler's one into the window's process if not present already. It unloads the DLLs and restores the original functionality on exit.
From my testing, it works very well so far. However, the issue seems to go deeper than just apps calling SetForegroundWindow
. For instance when a new window is created, it's automatically brought into foreground, which also interferes with a user typing into another window.
To deal with other methods of focus stealing, more testing is required and I'd appreciate any feedback on scenarios where it's happening.
edit: Source code now available.