it-swarm-eu.dev

Impedire alle applicazioni di rubare l'attenzione

Esistono soluzioni per impedire alle applicazioni di rubare l'attenzione dalla finestra attiva?

Questo è particolarmente fastidioso quando sto avviando un'applicazione, si passa a fare qualcos'altro e la nuova applicazione inizia a ricevere una mezza frase di testo.

189
svandragt

Questo non è possibile senza estensivomanipolazione di interni di Windows ed è necessario superarlo.

Ci sono momenti nell'uso quotidiano del computer quando è veramente importante fare un'azione prima che il sistema operativo ti permetta di fare un altro. Per fare ciò, è necessario bloccare l'attenzione su determinate finestre. In Windows, il controllo su questo comportamento è in gran parte lasciato agli sviluppatori dei singoli programmi che si utilizzano.

Non tutti gli sviluppatori prendono le decisioni giuste quando si tratta di questo argomento.

So che è molto frustrante e fastidioso, ma non puoi avere la tua torta e mangiarla anche tu. Ci sono probabilmente molti casi nella tua vita quotidiana in cui stai perfettamente bene con il focus che viene spostato su un determinato elemento dell'interfaccia utente o un'applicazione che richiede che lo stato attivo rimanga bloccato su di esso. Ma la maggior parte delle applicazioni sono in qualche modo uguali quando si tratta di decidere chi è il protagonista in questo momento e il sistema non può mai essere perfetto.

Qualche tempo fa ho fatto ricerche approfondite per risolvere questo problema una volta per tutte (e fallito). Il risultato della mia ricerca può essere trovato sulla pagina del progetto fastidio .

Il progetto include anche un'applicazione che tenta ripetutamente di catturare l'attenzione chiamando:

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;

Come possiamo vedere da questo frammento, la mia ricerca si è concentrata anche su altri aspetti del comportamento dell'interfaccia utente che non mi piacciono.

Il modo in cui ho provato a risolverlo è stato caricare un DLL in ogni nuovo processo e agganciare le chiamate API che provocano l'attivazione di un'altra finestra.
L'ultima parte è facile, grazie alle fantastiche librerie di aggancio API disponibili. Ho usato la grandissima libreria 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;
}

Dai miei test allora, questo ha funzionato alla grande. Tranne la parte di caricamento del DLL in ogni nuovo processo. Come si potrebbe immaginare, non è niente da prendere alla leggera. Ho usato l'approccio AppInit_DLLs allora (che semplicemente non è sufficiente).

Fondamentalmente, questo funziona alla grande. Ma non ho mai trovato il tempo di scrivere qualcosa che correttamente inietta il mio DLL in nuovi processi. E il tempo investito in questo in gran parte offusca il fastidio che il fuoco di rubare mi causa.

Oltre al problema di iniezione di DLL, esiste anche un metodo di autotuning che non ho trattato nell'implementazione su Google Code. Un collaboratore in realtà ha fatto qualche ricerca aggiuntiva e ha coperto tale metodo. Il problema è stato discusso in SO: https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus

50
Der Hochstapler

In Windows 7, la voce di registro ForegroundLockTimeoutnon viene più controllata, è possibile verificarla con Process Monitor. In realtà, in Windows 7 non ti consentono di modificare la finestra in primo piano. Vai a leggere sui suoi dettagli , è addirittura passato da Windows 2000.

Tuttavia, la documentazione fa schifo e si inseguono e trovano modi per farlo .

Quindi, c'è qualcosa di buggato con SetForegroundWindowNAME_ , o funzioni API simili ...

L'unico modo per farlo correttamente è creare una piccola applicazione che periodicamente richiami LockSetForegroundWindowNAME_ , disabilitando virtualmente tutte le chiamate alla nostra API buggy.

Se questo non è abbastanza (un'altra chiamata API buggy?) Puoi andare ancora oltre e fare un po ' Monitoraggio API per vedere cosa sta succedendo, e quindi semplicemente agganciare le chiamate API su ogni processo dopo di che puoi sbarazzarsi di any chiamate che incasinano il primo piano. Tuttavia, ironicamente, questo è scoraggiato da Microsoft ...

23
Tom Wijsman

C'è un'opzione in TweakUI che fa questo. Impedisce la maggior parte dei soliti trucchi che gli sviluppatori di software dubbia impiegano per concentrarsi sulla propria app.

È comunque una guerra armata in corso, quindi non so se funzioni per tutto.

Aggiornamento : Secondo EndangeredMassa , TweakUI non funziona su Windows 7.

18
Simon P Stevens

Credo che possa esistere una certa confusione, poiché ci sono due modi per "rubare lo stato attivo": (1) una finestra che viene in primo piano e (2) la finestra che riceve i tasti.

Il problema a cui si fa riferimento qui è probabilmente il secondo, in cui una finestra rivendica l'attenzione portandosi in primo piano - senza la richiesta o il permesso dell'utente.

La discussione deve essere suddivisa tra XP e 7.

Windows XP

In XP c'è un hack del registro che rende XP funzionante come Windows 7 nel impedire alle applicazioni di rubare lo stato attivo:

  1. Usa regedit per andare a: HKEY_CURRENT_USER\Control Panel\Desktop.
  2. Fai doppio clic su ForegroundLockTimeout e imposta il suo valore in esadecimale su 30d40.
  3. Premere OK e uscire da regedit.
  4. Riavviare il PC per rendere effettive le modifiche.

Windows 7

(La discussione di seguito si applica principalmente a XP.)

Si prega di comprendere che non c'è modo in cui Windows può bloccare completamente le applicazioni dal rubare l'attenzione e rimanere funzionale. Ad esempio, se durante una copia di un file l'anti-virus rileva una possibile minaccia e desidera visualizzare una finestra che richiede l'azione da intraprendere, se questa finestra è bloccata, non si capirà mai perché la copia non termina mai.

In Windows 7 c'è una sola modifica possibile al comportamento di Windows stesso, che consiste nell'usare il MS-Windows focus-follows-mouse Registry hack , dove il focus e/o l'attivazione vanno sempre alle finestre sotto il cursore. È possibile aggiungere un ritardo per evitare che le applicazioni si aprano su tutto il desktop.
Vedi questo articolo: Windows 7 - Mouse Hover rende la finestra attiva - Abilita .

Altrimenti, è necessario rilevare e neutralizzare il programma di colpevolezza: se questa è sempre la stessa applicazione che viene messa a fuoco, allora questa applicazione è programmata per focalizzare l'attenzione e impedire che ciò avvenga disabilitando l'avvio dal computer, oppure utilizzare alcune impostazioni fornite da tale applicazione per evitare questo comportamento.

È possibile utilizzare lo script VBS incluso in VB Codice che identifica chi sta rubando lo stato attivo , che l'autore ha utilizzato per identificare il colpevole come un programma di aggiornamento "call home" per un software di stampa.

Una misura disperata quando tutto il resto fallisce, e se hai identificato questa applicazione mal programmata, è di minimizzarla e spero che non si porti in prima linea. Una forma più forte di minimizzazione è per il vassoio utilizzando uno dei prodotti gratuiti elencati in Miglior minimizzatore di applicazioni gratuite .

L'ultima idea nell'ordine della disperazione è di rompere virtualmente il tuo desktop usando un prodotto come Desktop o Dexpot , e fai il tuo lavoro su un altro desktop diverso da quello predefinito.

[MODIFICARE]

Poiché Microsoft ha ritirato la Galleria di archivio, ecco il codice VB sopra riprodotto:

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
14
harrymc

Ispirato da Risposta di Der Hochstapler , ho deciso di scrivere un _ injector DLL, che funziona con entrambi i processi a 64 e 32 bit e impedisce il furto del focus su Windows 7 o successivi: https: // blade.sk/stay-focused/

Il modo in cui funziona è che controlla le finestre appena create (usando SetWinEventHook) e inietta DLL molto simile a quella di Der Hochstapler nel processo della finestra se non già presente. Scarica le DLL e ripristina la funzionalità originale all'uscita.

Dai miei test, funziona molto bene finora. Tuttavia, il problema sembra andare più in profondità delle app che chiamano SetForegroundWindow. Ad esempio, quando viene creata una nuova finestra, questa viene automaticamente messa in primo piano, il che interferisce anche con un utente che digita in un'altra finestra.

Per affrontare altri metodi di rubare il focus, sono necessari più test e apprezzerei qualsiasi feedback sugli scenari in cui si sta verificando.

2
blade

Ghacks ha una possibile soluzione:

Accade più volte al giorno che alcune applicazioni rubano il focus della finestra attiva spuntando. Questo può accadere per una serie di motivi, quando estrai i file o il trasferimento finisce, per esempio. Non importa la maggior parte del tempo in cui ciò accade, ma a volte sto scrivendo un articolo e ciò non significa solo che devo digitare nuovamente alcune parole, ma anche che ho perso la concentrazione e devo fare clic per riguadagnare l'attenzione.

Il Pro Reviewer website ha un suggerimento su come evitare che ciò accada. Il modo più semplice per evitare di rubare il focus è usare Tweak UI, che ha un'impostazione che si chiama "Impedisci alle applicazioni di rubare lo stato attivo". Selezionando questa opzione si evita che altre applicazioni si aprano improvvisamente e rubino il focus della finestra in cui si sta attualmente lavorando.

Funziona solo quando l'applicazione è stata ridotta a icona in precedenza. Invece di rubare la messa a fuoco lampeggerà un numero di volte che può essere definito nello stesso menu in Tweak UI . Se non si desidera utilizzare Tweak UI, è possibile modificare le impostazioni nel registro di Windows.

Passare alla chiave di registro HKEY_CURRENT_USER> Pannello di controllo> Desktop e modificare il valore ForegroundLockTimeout su 30d40 (esadecimale) o 200000 (decimale). Il tasto ForeGroundFlashCount definisce la quantità di lampi di una finestra per avvisare l'utente dove 0 significa illimitato.

2
Ivo Flipse