การป้องกันไม่ให้แอปพลิเคชันขโมยโฟกัส


191

มีวิธีแก้ไขปัญหาเพื่อป้องกันไม่ให้แอปพลิเคชันขโมยโฟกัสจากหน้าต่างที่ใช้งานอยู่หรือไม่?

สิ่งนี้น่ารำคาญเป็นพิเศษเมื่อฉันเริ่มแอปพลิเคชันสลับไปทำอย่างอื่นและแอปพลิเคชันใหม่เริ่มรับข้อความครึ่งประโยค


9
@Ivo Windows 7 ในกรณีของฉัน แต่ฉันคิดว่าสำหรับ SuperUser หน้าต่างทุกรุ่นจะมีความเกี่ยวข้อง
svandragt

3
ผู้ดำเนินรายการได้รวมคำถามนี้: superuser.com/questions/199821/…กับคำถามปัจจุบัน นี่เป็นสิ่งที่ผิดคำตอบสำหรับคำถามปัจจุบันไม่ได้ใช้กับ windows 7 ดังนั้นจึงไม่ควรรวมเข้าด้วยกัน จนถึงตอนนี้ฉันไม่พบวิธีแก้ไขปัญหานี้ใน Windows 7
Alex Angelico

17
นี่เป็นหนึ่งในสัตว์เลี้ยงอันดับหนึ่งของฉันที่มี GUI ทุกตัวที่ฉันเคยใช้ คุณกำลังพิมพ์และบลาสต์กล่องโต้ตอบที่เบลอบางอย่างจะขโมยโฟกัสและครึ่งหนึ่งของการกดแป้นของคุณจะไปที่อื่น คุณคิดว่าผู้พัฒนาระบบหน้าต่างจะต้องเข้าใจสิ่งนี้เมื่อสิบปีก่อน หากมีกิจกรรมในหน้าต่างหน่วงเวลาการเปิดรับหน้าต่างใหม่ เช่นไม่ปรากฏอะไรขึ้นบน GUI จนกระทั่งสามหรือสี่วินาทีนับตั้งแต่การคลิกปุ่มสุดท้ายหรือการกดแป้นในหน้าต่างที่โฟกัสอยู่ในปัจจุบัน Doh!
Kaz

24
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.มันยิ่งน่ารำคาญยิ่งขึ้นเมื่อกล่องโต้ตอบปรากฏขึ้นและคุณก็ไม่ได้ตั้งใจทิ้งข้อความไว้โดยไม่ได้เห็นข้อความเพราะคุณกดSpaceหรือEnterขณะพิมพ์ประโยค
Synetech

3
นี่เป็นวิธีที่น่ารำคาญกว่าจริงๆฉันจะบอกว่ามันเสี่ยงต่อความปลอดภัย ไม่มีอะไรที่จะหยุดแอปพลิเคชันที่จะโผล่ขึ้นมาเมื่อคุณอยู่ในระหว่างการพิมพ์รหัสผ่านและรับข้อมูลของคุณ
Chris Peacock

คำตอบ:


51

สิ่งนี้เป็นไปไม่ได้หากไม่มีการจัดการภายใน 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


คุณคิดว่าโซลูชันของคุณสามารถเชื่อมต่อกับ Java ได้หรือไม่ ฉันค้นหาและถามคำถาม แต่ไม่พบอะไรเลย บางทีฉันสามารถนำเข้าไลบรารีฮุกของตัวเองใน java โดยใช้jne?
Tomáš Zato

@ TomášZato: ไม่มีความคิด ฉันไม่ได้ใช้รหัสนี้อย่างแข็งขัน
Der Hochstapler

ฉันพยายามที่จะรวบรวมมันเป็น C ++ อย่างน้อย (แล้วฉีด / ลบ DLL รวบรวมจาก Java) แต่นั่นก็ไม่ได้เป็นไปด้วยดีเช่นกัน ฉันไม่ต้องการพูดถึงเรื่องนี้ในความคิดเห็น แต่ถ้าคุณสามารถช่วยฉันในการทำให้มันใช้งานได้จริงฉันก็จะสุภาพมาก! ฉันสร้างห้องแชทถ้าฉันทำงานอย่างนั้นฉันจะโพสต์ความคิดเห็นวิธีการทำที่นี่: chat.stackexchange.com/rooms/21637/…
Tomáš Zato

23

ใน Windows 7 ForegroundLockTimeoutรายการรีจิสทรีจะไม่ถูกตรวจสอบอีกต่อไปคุณสามารถตรวจสอบได้ด้วย Process Monitor อันที่จริงแล้วใน Windows 7 พวกเขาไม่อนุญาตให้คุณเปลี่ยนหน้าต่างพื้นหน้า ไปและอ่านรายละเอียดเกี่ยวกับมันมาตั้งแต่ Windows 2000

อย่างไรก็ตามเอกสารนั้นเป็นข้อมูลที่แย่มากและพวกมันจะไล่ล่าซึ่งกันและกันและหาทางแก้ไข

ดังนั้นมีบางสิ่งบางอย่างที่เกิดขึ้นกับSetForegroundWindowรถหรือฟังก์ชั่น API ที่คล้ายกันคือ ...

วิธีเดียวที่จะทำสิ่งนี้ได้อย่างถูกต้องคือการสร้างแอปพลิเคชันขนาดเล็กซึ่งเรียกเป็นระยะ ๆLockSetForegroundWindowปิดการใช้งานการโทรไปยังฟังก์ชัน buggy API ของเราอย่างแท้จริง

หากยังไม่พอ (มีการโทร API แบบ buggy อีกครั้ง) คุณสามารถดำเนินการต่อไปและทำการตรวจสอบ APIเพื่อดูว่าเกิดอะไรขึ้นจากนั้นคุณเพียงแค่ขอให้มีการโทรแบบ API ในทุกขั้นตอนหลังจากที่คุณสามารถกำจัดสายใด ๆเบื้องหน้า อย่างไรก็ตามแดกดันนี้เป็นกำลังใจโดย Microsoft ...


3
ใครบ้างมีกรณีใช้ซ้ำใน Windows 7? เนื่องจากผู้คนค่อนข้างพบกับสิ่งตรงกันข้าม (ตัวอย่างเช่นฉันมักจะพบว่า Windows ต้องการให้ซ่อนอยู่หลังหน้าต่างปัจจุบันของฉัน) และฉันยังไม่เห็นสิ่งนี้เกิดขึ้นใน Windows 7 มันจะค่อนข้างน่ารำคาญที่จะเขียนโปรแกรม แต่ไม่สามารถ ทดสอบมัน นอกจากนี้เนื่องจาก Microsoft ระบุว่าสิ่งนี้ไม่ควรเกิดขึ้นกับ Windows 7 อีกต่อไปในคนที่ดีที่สุดพบว่าสามารถเปลี่ยนโฟกัสของแป้นพิมพ์ได้โดยบังเอิญการเรียก API นี้จะแก้ไขได้ แต่ฉันไม่รู้วิธีทดสอบว่าใช้งานได้จริงหรือไม่ .
Tamara Wijsman

1
ตัวติดตั้ง (ตาม InnoSetup) เปิดตัวกระบวนการอื่น ๆ และการตั้งค่าอื่น ๆ (ซ่อน) ที่เป็นไปได้ แต่ฉันไม่ทราบว่าเป็นผู้สร้างการติดตั้งแบบใด
Daniel Beck

6
@TomWijsman: เปิด regedit ค้นหาข้อความสุ่มที่จะไม่พบ ไปที่แอพอื่นแล้วเริ่มพิมพ์ เมื่อการค้นหาเสร็จสิ้น regedit จะขโมยโฟกัส
endolith

1
@endolith: ไม่สามารถทำซ้ำได้โดยใช้ Windows 8 Replase Preview ที่นี่ คุณใช้ระบบปฏิบัติการอะไร? ในกรณีของฉันมันแค่ไฮไลท์แอปพลิเคชันที่ด้านล่าง แต่ไม่ขัดจังหวะการเรียกดูเลย ...
Tamara Wijsman

21
ใช่ Win7 Pro 64 บิต และการขโมยโฟกัสนั้นยิ่งแย่กว่านั้นสำหรับกระบวนการที่ยกระดับเนื่องจากพวกมันจะจับการกด <Enter> ของคุณเมื่อไม่ควรและคุณบอกให้ท่อดูดระบบของคุณโดยไม่ตั้งใจ ไม่มีสิ่งใดที่จะสามารถขโมยโฟกัสได้
endolith

18

มีตัวเลือกในTweakUIซึ่งทำสิ่งนี้ มันป้องกันไม่ให้นักพัฒนาซอฟต์แวร์ที่น่าสงสัยส่วนใหญ่ใช้กลอุบายเพื่อบังคับให้แอพของพวกเขาโฟกัส

มันเป็นสงครามอาวุธต่อเนื่องดังนั้นฉันไม่รู้ว่ามันเหมาะกับทุกสิ่งหรือไม่

ปรับปรุง : ตามEndangeredMassa , TweakUI ไม่ทำงานบน Windows 7


2
tweakui เข้ากันได้กับ windows 7 หรือไม่
frankster

@frankster ไม่มีความคิดขอโทษด้วยฉันคิดว่าคงไม่ใช่ ดาวน์โหลดและทดลองใช้ รายงานกลับถ้าคุณทำเพื่อให้ทุกคนรู้
Simon P Stevens

5
แม้แต่การใช้การตั้งค่ารีจิสทรีที่ชุด TweakUI ไม่ทำงานบน Win7
EndangeredMassa

@EndangeredMassa คีย์รีจิสตรีคืออะไร
n611x007

2
รีจิสทรีคีย์คือ HKEY_CURRENT_USER \ Control Panel \ Desktop \ ForegroundLockTimeout (เป็นมิลลิวินาที) และใช่มันไม่ทำงานใน Windows 7 อีกต่อไป
foo

14

ฉันเชื่อว่าความสับสนบางอย่างอาจมีอยู่เนื่องจากมี "วิธีการขโมยโฟกัส" สองวิธี: (1) หน้าต่างที่มาด้านหน้าและ (2) หน้าต่างรับการกดแป้น

ปัญหาที่อ้างถึงในที่นี้น่าจะเป็นปัญหาที่สองซึ่งหน้าต่างเรียกร้องการโฟกัสโดยนำตัวเองไปยังส่วนหน้า - โดยไม่ต้องมีการร้องขอหรือการอนุญาตจากผู้ใช้

การสนทนาจะต้องแยกที่นี่ระหว่าง XP และ 7

Windows XP

ใน XP มีแฮ็ครีจิสทรีที่ทำให้ XP ทำงานเหมือนกับ Windows 7 ในการป้องกันไม่ให้แอปพลิเคชันขโมยโฟกัส:

  1. ใช้ regedit HKEY_CURRENT_USER\Control Panel\Desktopเพื่อไปที่:
  2. ดับเบิลคลิกที่และตั้งค่าในฐานสิบหกForegroundLockTimeout30d40
  3. กดตกลงแล้วออกจาก regedit
  4. รีบูทพีซีของคุณเพื่อให้การเปลี่ยนแปลงมีผล

วินโดว 7

(การสนทนาด้านล่างส่วนใหญ่ใช้กับ XP เช่นกัน)

โปรดเข้าใจว่าไม่มีทางที่ Windows สามารถปิดกั้นแอปพลิเคชันทั้งหมดจากการขโมยโฟกัสและยังคงใช้งานได้ ตัวอย่างเช่นหากในระหว่างการคัดลอกไฟล์โปรแกรมป้องกันไวรัสของคุณตรวจพบภัยคุกคามที่เป็นไปได้และต้องการป๊อปอัปหน้าต่างขอให้คุณดำเนินการหากหน้าต่างนี้ถูกบล็อกคุณจะไม่เข้าใจว่าทำไมการคัดลอกจึงไม่ยุติลง

ใน Windows 7 มีเพียงหนึ่งการปรับเปลี่ยนที่เป็นไปได้กับลักษณะการทำงานของ Windows เองซึ่งเป็นการใช้แฮ็กรีจิสตรีที่เน้นการติดตามเมาส์แบบ MS-Windowsซึ่งการโฟกัสและ / หรือการเปิดใช้งานจะไปยังหน้าต่างภายใต้เคอร์เซอร์เสมอ สามารถเพิ่มการหน่วงเวลาเพื่อหลีกเลี่ยงแอปพลิเคชันที่โผล่ขึ้นมาบนเดสก์ท็อป
ดูบทความนี้: Windows 7 - เมาส์เลื่อนทำให้หน้าต่างที่ใช้งาน - เปิดใช้งาน

มิฉะนั้นต้องตรวจพบและทำให้เป็นกลางโปรแกรมผิด: ถ้านี่เป็นแอพพลิเคชั่นเดียวกันที่ได้รับโฟกัสอยู่เสมอแอปพลิเคชั่นนี้จะได้รับการตั้งโปรแกรมให้ทำการโฟกัสและป้องกันสิ่งนี้อาจทำได้โดยการปิดการใช้งาน ใช้การตั้งค่าบางอย่างที่จัดทำโดยแอปพลิเคชันนั้นเพื่อหลีกเลี่ยงพฤติกรรมนี้

คุณสามารถใช้สคริปต์ VBS ที่รวมอยู่ในรหัส VB ​​ซึ่งระบุว่าใครขโมยโฟกัสซึ่งผู้เขียนเคยระบุผู้กระทำผิดว่าเป็นตัวอัปเดต "การโทรกลับบ้าน" สำหรับซอฟต์แวร์เครื่องพิมพ์

มาตรการที่สิ้นหวังเมื่อสิ่งอื่นล้มเหลวและหากคุณระบุแอปพลิเคชันที่โปรแกรมไม่ดีนี้คือการย่อให้เล็กสุดและหวังว่าจะไม่นำตัวเองมาอยู่ข้างหน้า แบบฟอร์มที่แข็งแกร่งของการลดคือการถาดโดยใช้หนึ่งในผลิตภัณฑ์ฟรีที่ระบุไว้ใน ที่ดีที่สุดฟรีโปรแกรม Minimizer

แนวคิดสุดท้ายในลำดับความสิ้นหวังคือการทำให้เดสก์ท็อปของคุณแตกหักโดยการใช้ผลิตภัณฑ์เช่นเดสก์ท็อปหรือDexpotและทำงานในเดสก์ท็อปอื่นนอกเหนือจากค่าเริ่มต้น

[แก้ไข]

ในฐานะที่เป็น Microsoft ได้ออกคลังเก็บถาวรนี่คือรหัส VB ​​ข้างต้นทำซ้ำ:

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

48
"ถ้าหน้าต่างนี้ถูกบล็อกคุณจะไม่เข้าใจว่าทำไมการคัดลอกจึงไม่ยุติลง" นั่นไม่จริง พฤติกรรมที่ถูกต้องคือการแจ้งให้ผู้ใช้ทราบด้วยไอคอนแถบงานกะพริบ (หรืออาจมีบอลลูนแจ้งเตือนแบบป๊อปอัพหรือแจ้งเตือนเครื่องปิ้งขนมปังหรือบางอย่าง) การขัดจังหวะผู้ใช้งานด้วยหน้าต่างที่ขัดขวางการกดแป้นของพวกเขาหมายความว่าพวกเขาบอกให้ซอฟต์แวร์ป้องกันไวรัสทำการกระทำหนึ่งอย่างหรืออย่างอื่นโดยการสุ่ม ไม่ใช่วิธีที่ดีในการทำสิ่งต่าง ๆ อย่างแน่นอน
endolith

1
"ถ้าหน้าต่างนี้ถูกบล็อกคุณจะไม่เข้าใจว่าทำไมการคัดลอกจึงไม่ยุติลง" นั่นไม่จริง พฤติกรรมที่ถูกต้องคือการแจ้งให้ผู้ใช้ทราบด้วยไอคอนแถบงานกะพริบ ... มีหลายครั้งที่ฉันคลิกปุ่มหรือบางสิ่งในโปรแกรมที่กำลังทำงานซึ่งทำให้ไดอะล็อกใหม่ถูกสร้างขึ้น (เช่นเปิดไฟล์ ) แต่หลังจากนั้น ฉันสลับไปยังโปรแกรมอื่นก่อนที่จะสร้างกล่องโต้ตอบ เป็นผลให้กล่องโต้ตอบถูกซ่อนและโปรแกรมอื่นไม่สามารถเปลี่ยนเป็นและไม่สามารถยกเลิกการโต้ตอบ ไม่ว่าปุ่มทาสก์บาร์หรือการAlt-Tabทำงาน บังคับเฉพาะไดอะล็อกที่ด้านหน้า
Synetech

1
@Synetech: บางครั้งทางออกเดียวของกล่องโต้ตอบที่ไม่ใช่ด้านหน้าคือการฆ่างาน อัลกอริธึมการโฟกัสใน Windows นั้นน่ากลัวจริงๆ
harrymc

2
@harrymc ฉันไม่ต้องหันไปฆ่าแอปใดแอพหนึ่ง ฉันเพิ่งเรียกใช้โปรแกรมจัดการหน้าต่าง ( WinSpy ++ทำการหลอกลวงได้ดีมาก) และซ่อนหน้าต่างไว้ด้านหน้าจากนั้นฉันสามารถปิดกล่องโต้ตอบค้างด้านหลังจากนั้นแสดงหน้าต่างที่ซ่อนอยู่อีกครั้ง มันไม่สะดวก แต่ดีกว่าฆ่ากระบวนการใดกระบวนการหนึ่ง
Synetech

1
@harrymc ไม่จริง ๆ ; การฆ่าแอพและการสูญเสียสิ่งต่าง ๆ นั้นทำให้เกิดไอน้ำมากขึ้นและถ้ามันเป็นไดอะล็อกแบบโมดัล (ที่ล็อคหน้าต่างหลักและไม่มีปุ่มแถบงาน) จากนั้นมันจะไม่ปรากฏในAlt+Tabรายการและจากประสบการณ์ของฉันหน้าต่างที่ กล่องโต้ตอบโมดัลเปิดไม่เสมอ (ไม่เลยหรือไม่) แสดงกล่องโต้ตอบโมดัลAlt+Tabโดยเฉพาะหากกล่องโต้ตอบไม่เคยเปลี่ยนเพื่อให้ได้โฟกัส :-|
Synetech

2

Ghacks มีทางออกที่เป็นไปได้:

มันเกิดขึ้นวันละหลายครั้งที่บางแอปพลิเคชันขโมยโฟกัสของหน้าต่างที่ใช้งานอยู่โดยเปิดขึ้นมา สิ่งนี้สามารถเกิดขึ้นได้จากหลายสาเหตุเมื่อฉันแยกไฟล์หรือการถ่ายโอนเสร็จสิ้นตัวอย่างเช่น ไม่สำคัญว่าเมื่อเกิดเหตุการณ์นี้ขึ้น แต่บางครั้งฉันเขียนบทความและไม่เพียง แต่หมายความว่าฉันต้องพิมพ์คำบางคำอีกครั้ง แต่ต้องสูญเสียสมาธิและต้องคลิกเพื่อให้ได้โฟกัส

ความคิดเห็นที่ Proเว็บไซต์ที่มีเคล็ดลับเกี่ยวกับวิธีการป้องกันไม่ให้เกิดขึ้น วิธีที่ง่ายที่สุดในการป้องกันการขโมยโฟกัสคือใช้ Tweak UI ซึ่งมีการตั้งค่าที่เรียกว่า "ป้องกันแอปพลิเคชันจากการขโมยโฟกัส" การเลือกตัวเลือกนี้จะป้องกันไม่ให้แอปพลิเคชันอื่น ๆ ปรากฏขึ้นอย่างฉับพลันและขโมยโฟกัสของหน้าต่างที่คุณกำลังทำงานอยู่

ใช้งานได้เฉพาะเมื่อแอปพลิเคชันนั้นย่อเล็กสุดมาก่อน แทนที่จะขโมยโฟกัสมันจะกระพริบจำนวนครั้งที่สามารถกำหนดได้ในเมนูเดียวกันในTweak UI หากคุณไม่ต้องการใช้ Tweak UI คุณสามารถเปลี่ยนการตั้งค่าใน Windows Registry

นำทางไปยังคีย์รีจิสทรี HKEY_CURRENT_USER> แผงควบคุม> เดสก์ท็อปและเปลี่ยนค่า ForegroundLockTimeout เป็น 30d40 (เลขฐานสิบหก) หรือ 200000 (ฐานสิบ) ForeGroundFlashCount ที่สำคัญกำหนดจำนวนกะพริบของหน้าต่างเพื่อแจ้งเตือนผู้ใช้ที่ 0 หมายถึงไม่ จำกัด


20
สิ่งนี้ใช้ไม่ได้กับระบบปฏิบัติการใด ๆ หลังจาก XP ค่ารีจิสตรี้นั้นถูกตั้งค่าไว้ที่นั้น (โดยค่าเริ่มต้นฉันเชื่อว่า) และใช้งานไม่ได้
EndangeredMassa

1
เพียงแค่ที่สองที่ฉันใช้ Windows 7 (64 บิต) พบว่ามีการขโมยโฟกัส (VS 2012 เมื่อมีการใช้งานในที่สุดตัวอย่าง f'r) และข้อเสนอแนะรีจิสทรีข้างต้นมีอยู่แล้วในสถานที่ การยืนยันทางเทคนิคในคำตอบนี้: superuser.com/a/403554/972
Michael Paulukonis

2

โดยได้รับแรงบันดาลใจจากคำตอบของ Der Hochstaplerฉันตัดสินใจเขียน DLL injector ซึ่งทำงานได้ทั้งกระบวนการ 64 และ 32 บิตและป้องกันการขโมยโฟกัสบน Windows 7 หรือใหม่กว่า: https://blade.sk/stay-focused/

วิธีการทำงานคือการเฝ้าดูหน้าต่างที่สร้างขึ้นใหม่ (โดยใช้SetWinEventHook) และอัด DLL ที่คล้ายกันมากกับ Der Hochstapler's หนึ่งเข้าไปในกระบวนการของหน้าต่างหากยังไม่ปรากฏ มันยกเลิกการโหลด DLLs และเรียกคืนการทำงานดั้งเดิมเมื่อออกจากระบบ

จากการทดสอบของฉันมันใช้งานได้ดีมากจนถึงตอนนี้ อย่างไรก็ตามดูเหมือนว่าปัญหาจะลึกซึ้งยิ่งกว่าแอปที่โทรSetForegroundWindowมา ตัวอย่างเช่นเมื่อมีการสร้างหน้าต่างใหม่มันจะถูกนำเข้าสู่เบื้องหน้าโดยอัตโนมัติซึ่งรบกวนผู้ใช้ที่พิมพ์ลงในหน้าต่างอื่น

หากต้องการจัดการกับวิธีการอื่นในการขโมยโฟกัสจำเป็นต้องทำการทดสอบเพิ่มเติมและฉันขอขอบคุณข้อเสนอแนะเกี่ยวกับสถานการณ์ที่กำลังเกิดขึ้น


0

ฉันหาวิธีที่จะหยุดแถบงานไม่ให้กระพริบหน้าต่างเป้าหมายที่เปิดใช้งานใหม่หลังจากที่คุณเปิดใช้งานโดยทางโปรแกรมให้ขยายใหญ่สุดและโฟกัสหน้าต่างหลักของกระบวนการนั้นจากกระบวนการอื่น ก่อนอื่นมีข้อ จำกัด มากมายเกี่ยวกับการอนุญาตให้ดำเนินการนี้

"ระบบ จำกัด กระบวนการที่สามารถตั้งค่าหน้าต่างพื้นหน้ากระบวนการสามารถตั้งค่าหน้าต่างเบื้องหน้าเฉพาะเมื่อเงื่อนไขข้อใดข้อหนึ่งต่อไปนี้เป็นจริง:

  • กระบวนการนี้เป็นกระบวนการพื้นหน้า
  • กระบวนการเริ่มต้นโดยกระบวนการพื้นหน้า
  • กระบวนการได้รับเหตุการณ์ป้อนข้อมูลล่าสุด
  • ไม่มีกระบวนการทำงานเบื้องหน้า
  • กระบวนการพื้นหน้ากำลังถูกดีบั๊ก
  • ส่วนหน้าไม่ได้ล็อค (ดูที่ LockSetForegroundWindow)
  • การหมดเวลาการล็อกส่วนหน้าหมดอายุแล้ว (ดู SPI_GETFOREGROUNDLOCKTIMEOUT ใน SystemParametersInfo)
  • ไม่มีเมนูใช้งาน

https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-allowsetforegroundwindow

ดังนั้นหากกระบวนการควบคุมอยู่ในเบื้องหน้าจึงสามารถเปิดใช้งานกระบวนการอื่นชั่วคราวเพื่อขโมยเบื้องหน้าโดยการเรียกAllowSetForegroundWindowด้วยรหัสกระบวนการของกระบวนการเป้าหมาย จากนั้นหลังจากนั้นกระบวนการเป้าหมายสามารถเรียกSetForegroundWindowเองโดยใช้หมายเลขอ้างอิงหน้าต่างของตัวเองและมันจะทำงาน

เห็นได้ชัดว่าสิ่งนี้ต้องการการประสานงานระหว่างสองกระบวนการ แต่มันใช้งานได้และหากคุณทำเช่นนี้เพื่อใช้แอปอินสแตนซ์เดียวซึ่งเปลี่ยนเส้นทางการคลิก Explorer ทั้งหมดไปสู่อินสแตนซ์ของแอปที่มีอยู่ มีไพพ์ที่ชื่อ (เช่น) เพื่อประสานงานต่าง ๆ อยู่ดี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.