Điều này là không thể nếu không có sự thao túng rộng rãi của các phần bên trong Windows và bạn cần phải vượt qua nó.
Có những khoảnh khắc trong việc sử dụng máy tính hàng ngày khi điều thực sự quan trọng là bạn thực hiện một hành động trước khi hệ điều hành cho phép bạn thực hiện một hành động khác. Để làm điều đó, nó cần phải khóa sự tập trung của bạn vào một số cửa sổ nhất định. Trong Windows, quyền kiểm soát hành vi này phần lớn được dành cho các nhà phát triển các chương trình riêng lẻ mà bạn sử dụng.
Không phải mọi nhà phát triển đều đưa ra quyết định đúng đắn khi nói đến chủ đề này.
Tôi biết rằng điều này rất bực bội và khó chịu, nhưng bạn không thể có bánh của bạn và cũng ăn nó. Có thể có nhiều trường hợp trong suốt cuộc sống hàng ngày của bạn, nơi bạn hoàn toàn ổn với việc lấy nét được chuyển đến một thành phần UI nhất định hoặc một ứng dụng yêu cầu tiêu điểm vẫn bị khóa trên đó. Nhưng hầu hết các ứng dụng có phần bằng nhau khi quyết định ai là người dẫn đầu ngay bây giờ và hệ thống không bao giờ có thể hoàn hảo.
Cách đây một thời gian, tôi đã nghiên cứu sâu rộng về việc giải quyết vấn đề này một lần và mãi mãi (và thất bại). Kết quả nghiên cứu của tôi có thể được tìm thấy trên trang dự án phiền toái .
Dự án cũng bao gồm một ứng dụng liên tục cố gắng lấy tiêu điểm bằng cách gọi:
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;
Như chúng ta có thể thấy từ đoạn trích này, nghiên cứu của tôi cũng tập trung vào các khía cạnh khác của hành vi giao diện người dùng mà tôi không thích.
Cách tôi cố gắng giải quyết vấn đề này là tải một DLL vào mọi quy trình mới và nối các lệnh gọi API khiến một cửa sổ khác được kích hoạt.
Phần cuối cùng là phần dễ nhất, nhờ các thư viện kết nối API tuyệt vời ngoài kia. Tôi đã sử dụng thư viện mhook rất tuyệt vời :
#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;
}
Từ các thử nghiệm của tôi hồi đó, điều này đã làm việc rất tốt. Ngoại trừ phần tải DLL vào mọi quy trình mới. Như người ta có thể tưởng tượng, đó là không có gì để xem nhẹ. Tôi đã sử dụng cách tiếp cận AppInit_DLLs trước đó (đơn giản là không đủ).
Về cơ bản, điều này làm việc tuyệt vời. Nhưng tôi không bao giờ tìm thấy thời gian để viết một cái gì đó đúng tiêm DLL của tôi vào quy trình mới. Và thời gian đầu tư vào việc này phần lớn làm lu mờ sự khó chịu mà việc đánh cắp tiêu điểm gây ra cho tôi.
Ngoài vấn đề tiêm DLL, còn có một phương pháp đánh cắp tiêu điểm mà tôi không đề cập đến trong quá trình triển khai trên Google Code. Một đồng nghiệp thực sự đã làm một số nghiên cứu bổ sung và đề cập đến phương pháp đó. Vấn đề đã được thảo luận trên SO: https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-loses-f Focus