Esto no es posible sin una manipulación extensiva de los componentes internos de Windows y debe superarlo.
Hay momentos en el uso diario de la computadora cuando es realmente importante que realice una acción antes de que el sistema operativo le permita hacer otra. Para hacer eso, necesita bloquear su enfoque en ciertas ventanas. En Windows, el control sobre este comportamiento se deja en gran medida a los desarrolladores de los programas individuales que utiliza.
No todos los desarrolladores toman las decisiones correctas cuando se trata de este tema.
Sé que esto es muy frustrante y molesto, pero no puedes tener tu pastel y comerlo también. Probablemente hay muchos casos a lo largo de su vida diaria en los que está perfectamente bien con el foco movido a un determinado elemento de la interfaz de usuario o una aplicación que solicita que el foco permanezca fijo en él. Pero la mayoría de las aplicaciones son algo iguales cuando se trata de decidir quién es el líder en este momento y el sistema nunca puede ser perfecto.
Hace un tiempo hice una extensa investigación para resolver este problema de una vez por todas (y fallé). El resultado de mi investigación se puede encontrar en la página del proyecto molesto .
El proyecto también incluye una aplicación que intenta repetidamente llamar la atención llamando:
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;
Como podemos ver en este fragmento, mi investigación también se centró en otros aspectos del comportamiento de la interfaz de usuario que no me gustan.
La forma en que traté de resolver esto fue cargar una DLL en cada proceso nuevo y conectar las llamadas a la API que hacen que se activen otras ventanas.
La última parte es fácil, gracias a las impresionantes bibliotecas de enganche de API que existen. Usé la gran biblioteca mhook :
#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;
}
Desde mis pruebas en ese entonces, esto funcionó muy bien. Excepto por la parte de cargar la DLL en cada proceso nuevo. Como uno podría imaginar, eso no es nada que tomar demasiado a la ligera. Solía los AppInit_DLLs acercan entonces (que simplemente no es suficiente).
Básicamente, esto funciona muy bien. Pero nunca encontré el tiempo para escribir algo que inyecte correctamente mi DLL en nuevos procesos. Y el tiempo invertido en esto eclipsa en gran medida la molestia que me causa el robo de atención.
Además del problema de inyección de DLL, también hay un método de robo de foco que no cubrí en la implementación en Google Code. Un compañero de trabajo en realidad hizo una investigación adicional y cubrió ese método. El problema se discutió en SO: https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus