Windows 7: comment faire passer une fenêtre à l’avant, quelle que soit la fenêtre ciblée?

Je suis en train de mettre en œuvre un programme de remplacement de type application-switcher par remplacement de la barre des tâches. Il fait des choses uniques avec OpenGL, et avec les raccourcis clavier, de cette manière, la fenêtre n’a pas toujours le focus. Je voudrais l’implémenter de telle sorte que je puisse mettre une fenêtre arbitraire au premier plan, un peu comme une barre des tâches ou un programme ALT-TAB.

Cependant, mon code provoque simplement le clignotement de l’icône de l’application dans la barre des tâches. La documentation de l’API Windows indique que c’est ce qui est censé se produire, mais je cherche un moyen de contourner ce problème.

J’ai adapté mon code à partir des exemples suivants, qui indiquent que l’attachement au thread de premier plan devrait vous permettre de définir la fenêtre de premier plan. Voici les sites:

http://www.voidnish.com/Articles/ShowArticle.aspx?code=dlgboxsortingcks

http://invers2008.blogspot.com/2008/10/mfc-how-to-steal-focus-on-2kxp.html

Mon code ressemble à ceci. Notez qu’il utilise les wrappers win32 pour python (self.hwnd est le handle de la fenêtre que je veux mettre au premier plan):

fgwin = win32gui.GetForegroundWindow() fg = win32process.GetWindowThreadProcessId(fgwin)[0] current = win32api.GetCurrentThreadId() if current != fg: win32process.AttachThreadInput(fg, current, True) win32gui.SetForegroundWindow(self.hwnd) win32process.AttachThreadInput(fg, win32api.GetCurrentThreadId(), False) 

Toutefois, à moins que ma fenêtre ne soit la fenêtre de premier plan (ce qui n’est généralement pas le cas), l’icône du programme clignote.

Est-ce que je fais le fil attaché mal? Y a-t-il une autre façon de contourner ce problème? J’imagine qu’il doit y en avoir, car il existe de nombreux commutateurs d’applications qui semblent pouvoir le faire correctement.

J’écris ceci en python, mais s’il existe une solution dans un autre langage, je vais utiliser des wrappers ou faire tout ce qui est nécessaire pour que cela fonctionne.

Merci d’avance!

EDIT: Je serais ouvert à un moyen de le faire fonctionner uniquement sur mon ordinateur particulier, c.-à-d. Un moyen d’activer, sur ma machine, un moyen de mettre l’accent sur n’importe quelle application.

RESOLU: Ce que vous devez faire est de désactiver le locking du premier plan. Il s’avère que c’était aussi simple que cela:

 win32gui.SystemParametersInfo(win32con.SPI_SETFOREGROUNDLOCKTIMEOUT, 0, win32con.SPIF_SENDWININICHANGE | win32con.SPIF_UPDATEINIFILE) 

J’ai eu du code qui fonctionne depuis des années, remontant à Windows 95. En double-cliquant sur l’icône de la barre d’état système des applications, j’ai toujours utilisé des fonctions API Win32 telles que BringWindowToTop et SetForegroundWindow. Tout cela a cessé de fonctionner comme prévu sur Windows 7, où ma fenêtre de saisie se retrouverait derrière d’autres fenêtres et l’icône de la fenêtre clignoterait sur la barre d’état. Le «travail autour de» que je suis venu avec c’était ceci; et il semble fonctionner sur toutes les versions de Windows.

 //-- show the window as you normally would, and bring window to foreground. // for example; ::ShowWindow(hWnd,SW_SHOW); ::BringWindowToTop(hWnd); ::SetForegroundWindow(hWnd); //-- on Windows 7, this workaround brings window to top ::SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0, SWP_NOMOVE | SWP_NOSIZE); ::SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); ::SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0,SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); 

Je n’aime pas ces suggestions d’utilisation de win32gui parce que vous ne pouvez pas facilement installer cela via pip . Alors voici ma solution:

Tout d’abord, installez pywinauto via pip . Si vous êtes sur Python 2.7.9 ou une version plus récente sur la twig 2, ou Python 3.4.0 ou une version plus récente de la twig 3, pip est déjà installé. Pour tout le monde, mettez à jour Python pour l’obtenir (ou vous pouvez le télécharger et l’installer manuellement en exécutant ce script , si vous devez exécuter une version antérieure de Python).

Il suffit de lancer ceci depuis la ligne de commande (pas depuis Python):

 pip install pywinauto 

Ensuite, importez ce dont vous avez besoin de pywinauto :

 from pywinauto.findwindows import find_window from pywinauto.win32functions import SetForegroundWindow 

Enfin, ce n’est qu’une seule ligne:

 SetForegroundWindow(find_window(title='taskeng.exe')) 

Selon nspire, j’ai essayé sa solution avec python 2.7 et W8, et cela fonctionne comme un charme, même si la fenêtre est réduite *.

 win32gui.ShowWindow(HWND, win32con.SW_RESTORE) win32gui.SetWindowPos(HWND,win32con.HWND_NOTOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE + win32con.SWP_NOSIZE) win32gui.SetWindowPos(HWND,win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE + win32con.SWP_NOSIZE) win32gui.SetWindowPos(HWND,win32con.HWND_NOTOPMOST, 0, 0, 0, 0, win32con.SWP_SHOWWINDOW + win32con.SWP_NOMOVE + win32con.SWP_NOSIZE) 
  • A l’origine, c’était si la fenêtre n’était pas minimisée , mais grâce au commentaire de win32gui.ShowWindow(HWND, win32con.SW_RESTORE) , cela fonctionne maintenant dans toutes les situations.

Si vous implémentez des raccourcis, utilisez RegisterHotKey . Comme le dit Raymond Chen (article de blog compagnon à celui déjà lié par Chris), “Presser un raccourci clavier enregistré vous donne l’amour d’activation au premier plan” .

La documentation de la fonction SetForegroundWindow explique qu’il s’agit en fait du comportement prévu. les processus ne devraient pas pouvoir “voler” le focus. Cependant, il est possible d’ajuster votre code pour qu’il fonctionne de toute façon.

Jetez un œil à la section remarque de LockSetForegroundWindow : elle explique

Le système active automatiquement les appels à SetForegroundWindow si l’utilisateur appuie sur la touche ALT [..]

Vous pouvez exploiter ce comportement en faisant simuler votre programme en appuyant sur la touche Alt en utilisant la fonction SendInput avant d’appeler SetForegroundWindow .