Question Empêcher les applications de voler le focus


Existe-t-il des solutions pour empêcher les applications de détourner l'attention de la fenêtre active?

Cela est particulièrement agaçant lorsque je lance une application, changez pour faire autre chose et la nouvelle application commence à recevoir une demi-phrase de texte.


174
2017-08-05 08:48


origine


@Ivo Windows 7 dans mon cas, mais je pense que pour SuperUser toutes les versions de Windows seraient pertinentes - svandragt
Le modérateur a fusionné cette question: superuser.com/questions/199821/... avec l'actuel. C'est faux, la réponse à la question actuelle ne s'applique pas à Windows 7, elle ne devrait donc pas être fusionnée. Jusqu'à présent, je n'ai pas trouvé de solution à ce problème dans Windows 7 - Alex Angelico
C'est l'un de mes premiers animaux de compagnie avec chaque GUI que j'ai jamais utilisé. Vous êtes en train de taper et de blamer, une boîte de dialogue bourdonne vole le focus et la moitié de vos frappes de touches vont ailleurs. Vous pensez que les concepteurs de systèmes de fenêtrage auraient compris cela il y a des décennies. S'il y a de l'activité dans une fenêtre, retardez l'exposition de la nouvelle fenêtre. Par exemple. Ne rien faire apparaître sur l'interface graphique pendant trois ou quatre secondes après le dernier clic sur le bouton ou la frappe dans la fenêtre en cours. Doh! - Kaz
J'ai trouvé quand j'ai mon disque dur externe (fabriqué par Seagate) ou mon ipod nano (ahem, apple) connecté à ma machine Windows 7, il semblerait que le "bureau" volerait le focus à peu près toutes les 30 secondes Je naviguais, que ce soit la musique iTunes, les résultats de recherche Chrome ou les emails Firefox. J'ai désactivé la fonctionnalité de lecture automatique, ce qui a aidé pendant un certain temps, mais le problème est revenu même après la désactivation de la lecture automatique. Je suppose que je dois garder mes disques durs externes HD et flash déconnectés pour la plupart, ce qui craint les thats où toute ma musique est :( C'est un bug vraiment ennuyeux qui me donne envie de S
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.C'est encore plus agaçant quand une boîte de dialogue apparaît et que vous la rejetez involontairement sans même voir le message parce que vous avez appuyé sur Space ou Enter en tapant une phrase. - Synetech


Réponses:


Il y a quelque temps, j'ai fait des recherches approfondies pour résoudre ce problème une fois pour toutes (et j'ai échoué). Le résultat de mes recherches se trouve sur le page de projet de contrariété.

Le projet comprend également une application qui tente à plusieurs reprises de saisir le focus en appelant:

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;

Comme nous pouvons le constater à partir de cet extrait, mes recherches ont également porté sur d’autres aspects du comportement de l’interface utilisateur que je n’aime pas.

La façon dont j'ai essayé de résoudre ce problème consistait à charger une DLL dans chaque nouveau processus et à connecter les appels API qui provoquent l'activation d'une autre fenêtre.
La dernière partie est la plus facile, grâce aux géniales bibliothèques d'accroche de l'API. J'ai utilisé le très grand bibliothèque de 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;
}

D'après mes tests à l'époque, cela fonctionnait très bien. Sauf pour le chargement de la DLL dans chaque nouveau processus. Comme on pourrait l'imaginer, ce n'est rien à prendre à la légère. J'ai utilisé le AppInit_DLLs approche alors (ce qui est tout simplement insuffisant).

Fondamentalement, cela fonctionne très bien. Mais je n'ai jamais trouvé le temps d'écrire quelque chose qui correctement injecte ma DLL dans de nouveaux processus. Et le temps investi dans cette tâche occulte largement la gêne que le vol de cible me cause.

En plus du problème d'injection de DLL, il existe également une méthode de vol de focus que je n'ai pas abordée dans l'implémentation de Google Code. Un collègue a fait des recherches supplémentaires et a couvert cette méthode. Le problème a été discuté sur SO: https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus


45
2018-03-24 09:56



Pensez-vous que cette solution pourrait être portée sur Java? J'ai cherché et posé des questions mais je n'ai rien trouvé. Peut-être que je pourrais importer la bibliothèque de hook elle-même en utilisant Java jne? - Tomáš Zato
@ TomášZato: Aucune idée. Je n'utilise pas activement ce code moi-même. - Der Hochstapler
J'essaie de le compiler au moins en C ++ (puis injecte / supprime la DLL compilée de Java). Mais ça ne va pas trop bien non plus. Je ne veux pas en discuter ici dans les commentaires, mais si vous pouviez réellement m'aider à le faire fonctionner, je serais très gracieux! J'ai créé un salon de discussion, si je réussis à le faire fonctionner, je posterai un commentaire sur comment le faire ici: chat.stackexchange.com/rooms/21637/ - Tomáš Zato


Dans Windows 7, le ForegroundLockTimeout l'entrée de registre n'est plus cochée, vous pouvez le vérifier avec Process Monitor. En fait, dans Windows 7, ils vous empêchent de modifier la fenêtre de premier plan. Aller lire à propos de ses détails, il existe même depuis Windows 2000.

cependant, la documentation suce et ils se poursuivent et trouvent des moyens autour de cela.

Donc, il y a quelque chose de buggy avec SetForegroundWindow, ou des fonctions API similaires ...

La seule façon de le faire correctement est de faire une petite application qui appelle périodiquement LockSetForegroundWindow, désactivant virtuellement tous les appels à notre fonction API boguée.

Si cela ne suffit pas (un autre appel d'API buggy?), Vous pouvez aller encore plus loin et faire Surveillance API pour voir ce qui se passe, et puis vous simplement raccorder les appels d'API sur chaque processus après quoi vous pouvez vous débarrasser de tout les appels qui gâchent le premier plan. Cependant, ironiquement, cela est découragé par Microsoft ...


22
2018-03-22 09:52



Quelqu'un at-il un cas d'utilisation reproductible de cela dans Windows 7? Étant donné que les gens font plutôt l'expérience du contraire (par exemple, je trouve souvent que Windows exige d'être caché derrière ma fenêtre actuelle) et que je n'ai pas encore vu cela se produire dans Windows 7, il serait très ennuyeux d'écrire une application Essaye-le. De plus, comme Microsoft le dit, cela ne devrait plus se produire avec Windows 7. Au mieux, les gens ont découvert qu’il ne pouvait changer le focus du clavier que par accident, cet appel d’API résoudrait ce problème mais je ne sais pas comment le tester. . - Tom Wijsman
L'installateur (basé sur InnoSetup) lance d'autres processus et d'autres configurations (cachées) possibles, mais je ne sais pas sur quel créateur de configuration ils sont basés. - Daniel Beck♦
@ TomWijsman: Ouvrez regedit, recherchez un texte aléatoire qui ne sera pas trouvé. Allez dans une autre application et commencez à taper. Lorsque la recherche est terminée, regedit volera le focus. - endolith
@endolith: Non reproductible, en utilisant cependant Windows 8 Replase Preview. Quel système d'exploitation utilisez-vous? Dans mon cas, il ne fait que souligner l'application en bas mais n'interrompt pas ma navigation du tout ... - Tom Wijsman
Oui, Win7 Pro 64 bits. Et le vol de mise au point est encore pire pour les processus élevés, car ils capturent votre appui sur <Entrée> alors qu'ils ne le devraient pas et vous lui dites d'arroser accidentellement votre système. Rien ne devrait déjà être capable de voler le focus. - endolith


Il y a une option dans TweakUI qui fait cela. Il empêche la plupart des astuces habituelles que les développeurs de logiciels douteux utilisent pour forcer la concentration sur leur application.

C'est une guerre des armes en cours, donc je ne sais pas si cela fonctionne pour tout.

Mettre à jour: Selon En dangerMassa, TweakUI ne fonctionne pas sous Windows 7.


18
2017-08-05 09:12



tweakui est-il compatible avec Windows 7? - frankster
@ frankster. Aucune idée, désolé, je suppose que ce n'est probablement pas le cas. Téléchargez-le et essayez-le. Faites votre rapport si vous le faites, tout le monde le sait. - Simon P Stevens
Même en utilisant le paramètre de registre défini par TweakUI ne fonctionne pas sur Win7. - EndangeredMassa
@EndangeredMassa quelle clé de registre est-ce? - n611x007
La clé de registre est HKEY_CURRENT_USER \ Control Panel \ Desktop \ ForegroundLockTimeout (en millisecondes). Et oui, cela ne fonctionne plus dans Windows 7. - foo


Je crois qu'une certaine confusion peut exister, car il y a deux manières de "voler le focus": (1) une fenêtre venant au premier plan et (2) la fenêtre recevant les frappes.

Le problème évoqué ici est probablement le deuxième, où un Windows revendique le focus en se mettant au premier plan - sans la demande ou la permission de l'utilisateur.

La discussion doit diviser ici entre XP et 7.

Windows XP

Dans XP il y a un piratage de registre qui fait que XP fonctionne comme Windows 7 pour empêcher les applications de se concentrer:

  1. Utilisez regedit pour aller à: HKEY_CURRENT_USER\Control Panel\Desktop.
  2. Double-cliquez sur ForegroundLockTimeout et définir sa valeur en hexadécimal à 30d40.
  3. Appuyez sur OK et quittez regedit.
  4. Redémarrez votre PC pour que les modifications prennent effet.

Windows 7

(La discussion ci-dessous s'applique surtout à XP.)

Veuillez comprendre que Windows ne peut en aucun cas empêcher totalement les applications de se concentrer et rester fonctionnelles. Par exemple, si lors de la copie de fichiers, votre antivirus a détecté une menace éventuelle et souhaite afficher une fenêtre vous demandant quelle action effectuer, si cette fenêtre est bloquée alors vous ne comprendriez jamais pourquoi la copie ne se termine jamais.

Dans Windows 7, il n’existe qu’une seule modification possible du comportement de Windows lui-même, à savoir: utiliser le Les hacks du Registre MS-Windows focus-follow-mouse, où la mise au point et / ou l'activation se fait toujours dans les fenêtres sous le curseur. Un délai peut être ajouté pour éviter que des applications apparaissent sur le bureau.
Voir cet article: Windows 7 - Le survol de la souris active la fenêtre - Activer.

Autrement, il faut détecter et neutraliser le programme coupable: Si c'est toujours la même application qui obtient le focus, alors cette application est programmé pour prendre le focus et empêcher cela en désactivant le démarrage de l'ordinateur ou en utilisant certains paramètres fournis par cette application pour éviter ce comportement.

Vous pouvez utiliser le script VBS inclus dans Code VB qui identifie les personnes qui volent le focus, que l'auteur avait l'habitude d'identifier le coupable en tant que "call home" pour un logiciel d'impression.

Une mesure désespérée quand tout le reste échoue, et si vous avez identifié cette application mal programmée, est de le minimiser et d’espérer que cela ne se fera pas au premier plan. Une forme plus forte de minimisation est à la barre en utilisant l'un des produits gratuits répertoriés dans Meilleur Minimiseur d'Application Libre.

La dernière idée dans l'ordre du désespoir est de fracturer virtuellement votre bureau en utilisant un produit tel que Ordinateurs de bureau ou Dexpot, et faites votre travail sur un autre bureau que celui par défaut.

[MODIFIER]

Comme Microsoft a retiré la galerie d'archives, voici le code VB ci-dessus reproduit:

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
2018-06-09 09:22



"Si cette fenêtre est bloquée, vous ne comprendrez jamais pourquoi la copie ne se termine jamais" Ce n'est pas vrai. Le comportement correct consiste à notifier à l'utilisateur une icône représentant une barre de tâches clignotante (ou une notification contextuelle ou une notification de grille-pain ou autre). Interrompre l'utilisateur avec une fenêtre qui intercepte ses frappes signifie qu'il demande au logiciel antivirus de prendre une action ou une autre au hasard. Certainement pas un bon moyen de faire les choses. - endolith
"Si cette fenêtre est bloquée, vous ne comprendrez jamais pourquoi la copie ne se termine jamais" Ce n'est pas vrai. Le comportement correct consiste à notifier à l'utilisateur une icône de barre de tâches clignotante ...   Il y a eu des moments où j'ai cliqué sur un bouton ou quelque chose dans un programme en cours d'exécution qui provoque la création d'une nouvelle boîte de dialogue modale (par exemple, fichier ouvert), mais je passe ensuite à un autre programme avant que la boîte de dialogue ne soit créée. Par conséquent, la boîte de dialogue est masquée et l'autre programme ne peut pas être basculé et la boîte de dialogue ne peut pas être ignorée. Ni son bouton de barre des tâches ni Alt-Tab travaux; ne force que le dialogue à l'avant. - Synetech
@ Synetech: Parfois, la seule solution à la boîte de dialogue non frontale est de tuer la tâche. Les algorithmes de focus dans Windows sont vraiment moche. - harrymc
@harrymc, je n'ai jamais besoin de tuer une des applications. Je viens de lancer mon programme de manipulation de fenêtre (WinSpy ++ fait le tour juste super et cacher la fenêtre en avant, alors je peux fermer la boîte de dialogue bloquée, puis ré-afficher la fenêtre cachée. Ce n'est pas pratique, mais c'est mieux que de tuer l'un des processus. - Synetech
@harrymc, pas vraiment; le fait de tuer une application et de perdre des choses fait plus de bruit, et si c'est un dialogue modal (qui verrouille la fenêtre parente et qui n'a pas de bouton de barre des tâches), alors elle n'apparaîtra pas dans le Alt+Tab liste, et, selon mon expérience, une fenêtre avec une boîte de dialogue modale ouverte ne montre pas toujours (jamais?) le dialogue modal avec Alt+Tab, surtout si le dialogue n'a jamais eu de changement pour se concentrer. :-| - Synetech


Ghacks a un solution possible:

Cela arrive plusieurs fois par jour   certaines applications volent le focus de   la fenêtre active en surgissant. Ce   peut se produire pour un certain nombre de raisons,   quand j'extrais des fichiers ou un transfert   se termine par exemple. Ce ne est pas   importe la plupart du temps quand cela   arrive mais parfois j'écris un   article et cela ne signifie pas seulement que   Je dois taper à nouveau quelques mots mais   aussi que j'ai perdu la concentration et   cliquer pour retrouver le focus.

le Pro Reviewer le site web a un conseil sur   comment empêcher cela.   Le moyen le plus simple d'empêcher la mise au point   voler est d'utiliser Tweak UI qui a   un paramètre appelé "Prevent   applications de voler le focus ".   La vérification de cette option empêche que   d'autres applications apparaissent soudainement et   voler le focus de la fenêtre que vous êtes   travaille actuellement dans

Cela ne fonctionne que lorsque l'application   a été minimisé avant. Au lieu de   voler le focus, il va clignoter un   nombre de fois qui peut être défini   dans le même menu en Tweak UI. Si vous   ne veux pas utiliser Tweak UI, vous pouvez   changer le paramètre dans Windows   Enregistrement.

Accédez à la clé de registre   HKEY_CURRENT_USER> Panneau de configuration>   Desktop et changer le   Valeur ForegroundLockTimeout à 30d40   (Hexadécimal) ou 200000 (décimal). le   La clé ForeGroundFlashCount définit le   quantité de flashs d'une fenêtre pour alerter   l'utilisateur où 0 signifie illimité.


2
2017-08-05 09:13



Cela ne fonctionne sur aucun système d'exploitation après XP. Cette valeur de registre est déjà définie sur cette valeur (par défaut, je crois) et ne fonctionne de toute façon pas. - EndangeredMassa
Juste pour confirmer que je suis sur Windows 7 (64-bit), en train de voler des focus (VS 2012 quand finalement actif, par exemple), et la suggestion de registre ci-dessus est déjà en place. Confirmation technique dans cette réponse: superuser.com/a/403554/972 - Michael Paulukonis