Nie jest to możliwe bez obszernej manipulacji wewnętrznymi elementami systemu Windows i trzeba się z tym pogodzić.
Są chwile w codziennym korzystaniu z komputera, kiedy naprawdę ważne jest, aby wykonać jedną akcję, zanim system operacyjny pozwoli na wykonanie innej. Aby to zrobić, musisz zablokować koncentrację na niektórych oknach. W systemie Windows kontrola nad tym zachowaniem jest w dużej mierze pozostawiona twórcom poszczególnych używanych programów.
Nie każdy programista podejmuje właściwe decyzje, jeśli chodzi o ten temat.
Wiem, że jest to bardzo frustrujące i denerwujące, ale nie możesz też zjeść ciasta. Prawdopodobnie w twoim codziennym życiu jest wiele przypadków, w których wszystko jest w porządku, gdy fokus jest przenoszony do określonego elementu interfejsu użytkownika lub aplikacji żądającej, aby fokus pozostał na nim zablokowany. Ale większość aplikacji jest nieco równa, jeśli chodzi o decydowanie, kto jest teraz liderem, a system nigdy nie będzie doskonały.
Jakiś czas temu przeprowadziłem szeroko zakrojone badania nad rozwiązaniem tego problemu raz na zawsze (i nie udało się). Wyniki moich badań można znaleźć na stronie projektu irytującego .
Projekt obejmuje również aplikację, która wielokrotnie próbuje skupić się, wywołując:
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;
Jak widać z tego fragmentu, moje badania skupiły się również na innych aspektach zachowania interfejsu użytkownika, które mi się nie podobają.
Próbowałem rozwiązać ten problem, ładując bibliotekę DLL do każdego nowego procesu i przechwytując wywołania API, które powodują aktywację kolejnych okien.
Ostatnia część jest łatwa dzięki niesamowitym bibliotekom przechwytującym API. Użyłem bardzo dobrej biblioteki 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;
}
Z moich ówczesnych testów to działało świetnie. Z wyjątkiem części ładowania biblioteki DLL do każdego nowego procesu. Jak można sobie wyobrazić, nie można tego lekceważyć. Użyłem wtedy metody AppInit_DLLs (co po prostu nie jest wystarczające).
Zasadniczo działa to świetnie. Ale nigdy nie znalazłem czasu, aby napisać coś, co odpowiednio wstrzykuje moją bibliotekę DLL do nowych procesów. A czas zainwestowany w to w dużej mierze przesłania irytację, którą wywołuje u mnie kradzież ogniskowej.
Oprócz problemu z wstrzykiwaniem biblioteki DLL istnieje również metoda kradzieży ostrości, której nie omawiałem przy implementacji kodu Google. Współpracownik faktycznie przeprowadził dodatkowe badania i omówił tę metodę. Problem został omówiony na SO: https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus