สิ่งนี้เป็นไปไม่ได้หากไม่มีการจัดการภายใน Windows อย่างกว้างขวางและคุณต้องแก้ไขให้ถูกต้อง
มีช่วงเวลาที่คอมพิวเตอร์ใช้ประจำวันเมื่อจำเป็นอย่างยิ่งที่คุณต้องทำสิ่งใดสิ่งหนึ่งก่อนที่ระบบปฏิบัติการจะอนุญาตให้คุณทำสิ่งอื่นได้ ในการทำเช่นนั้นจำเป็นต้องล็อคโฟกัสของคุณในบางหน้าต่าง ใน Windows การควบคุมพฤติกรรมนี้ส่วนใหญ่จะเป็นของนักพัฒนาของแต่ละโปรแกรมที่คุณใช้
ไม่ใช่นักพัฒนาซอฟต์แวร์ทุกคนตัดสินใจอย่างถูกต้องเมื่อพูดถึงหัวข้อนี้
ฉันรู้ว่านี่เป็นสิ่งที่น่าหงุดหงิดและน่ารำคาญมาก แต่คุณไม่มีเค้กและกินมันเกินไป อาจมีหลายกรณีที่เกิดขึ้นในชีวิตประจำวันของคุณซึ่งคุณสามารถปรับโฟกัสได้อย่างสมบูรณ์แบบด้วยการย้ายโฟกัสไปยังองค์ประกอบ UI ที่แน่นอนหรือแอปพลิเคชันที่ขอให้โฟกัสยังคงล็อคอยู่ แต่แอพพลิเคชั่นส่วนใหญ่ค่อนข้างเท่ากันเมื่อต้องตัดสินใจว่าใครเป็นผู้นำในตอนนี้และระบบจะไม่สมบูรณ์แบบ
ไม่นานมานี้ฉันได้ทำการวิจัยอย่างกว้างขวางเกี่ยวกับการแก้ไขปัญหานี้ครั้งเดียวและสำหรับทั้งหมด (และล้มเหลว) ผลของการวิจัยที่สามารถพบได้บนหน้าโครงการแกล้ง
โครงการนี้ยังรวมถึงแอปพลิเคชันที่พยายามดึงโฟกัสโดยการโทรซ้ำ ๆ :
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;
อย่างที่เราเห็นได้จากตัวอย่างนี้งานวิจัยของฉันก็เน้นไปที่ด้านอื่น ๆ ของพฤติกรรมส่วนต่อประสานผู้ใช้ที่ฉันไม่ชอบ
วิธีที่ฉันพยายามแก้ปัญหานี้คือการโหลด DLL ลงในทุกกระบวนการใหม่และขอให้เรียก API ที่ทำให้หน้าต่างอื่นเปิดใช้งาน
ส่วนสุดท้ายคือส่วนที่ง่ายขอบคุณ API ที่ยอดเยี่ยมที่เชื่อมต่อกับไลบรารีที่นั่น ฉันใช้ห้องสมุด 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;
}
จากการทดสอบของฉันในตอนนั้นมันใช้งานได้ดีมาก ยกเว้นส่วนของการโหลด DLL ลงในทุกกระบวนการใหม่ อย่างที่ใคร ๆ ก็คาดไม่ถึง ฉันใช้วิธีการAppInit_DLLแล้ว (ซึ่งไม่เพียงพอ)
โดยพื้นฐานแล้วมันใช้งานได้ดี แต่ฉันไม่เคยพบเวลาที่จะเขียนสิ่งที่จะฉีด DLL ของฉันเข้าสู่กระบวนการใหม่อย่างถูกต้อง และเวลาที่ลงทุนในเรื่องนี้ทำให้ผมรำคาญใจมากที่การขโมยโฟกัสทำให้ผม
นอกจากปัญหาการฉีด DLL แล้วยังมีวิธีการโฟกัสแบบขโมยซึ่งฉันไม่ได้กล่าวถึงในการใช้งาน Google Code เพื่อนร่วมงานได้ทำการวิจัยเพิ่มเติมและครอบคลุมวิธีการนั้น มีการพูดถึงปัญหาใน SO: https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus