web-dev-qa-db-fra.com

Obtenir la fenêtre active en utilisant Python

Je voudrais afficher la fenêtre active à l'écran en utilisant python.

Par exemple, l'interface de gestion du routeur où vous entrez le nom d'utilisateur et le mot de passe en tant qu'administrateur

Cette interface d'administration est ce que je veux capturer en utilisant python pour automatiser la saisie du nom d'utilisateur et du mot de passe.

De quelles importations aurais-je besoin pour ce faire?

24
Vinod K

Sur Windows, vous pouvez utiliser le python pour les extensions Windows ( http://sourceforge.net/projects/pywin32/ ):

from win32gui import GetWindowText, GetForegroundWindow
print GetWindowText(GetForegroundWindow())

Le code ci-dessous est pour python 3:

from win32gui import GetWindowText, GetForegroundWindow
print(GetWindowText(GetForegroundWindow()))

(Trouvé ceci sur http://scott.sherrillmix.com/blog/programmer/active-window-logger/ )

23
William Saunders

Le script suivant devrait fonctionner sur Linux, Windows et Mac. Il n'est actuellement testé que sur Linux (Ubuntu Mate Ubuntu 15.10).

Conditions préalables

Pour Linux :

Installez wnck (Sudo apt-get install python-wnck sur Ubuntu, voir libwnck .)

Pour Windows :

Assure-toi win32gui est disponible

Pour Mac :

Assurez-vous que AppKit est disponible

Le scénario

#!/usr/bin/env python

"""Find the currently active window."""

import logging
import sys

logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                    level=logging.DEBUG,
                    stream=sys.stdout)


def get_active_window():
    """
    Get the currently active window.

    Returns
    -------
    string :
        Name of the currently active window.
    """
    import sys
    active_window_name = None
    if sys.platform in ['linux', 'linux2']:
        # Alternatives: http://unix.stackexchange.com/q/38867/4784
        try:
            import wnck
        except ImportError:
            logging.info("wnck not installed")
            wnck = None
        if wnck is not None:
            screen = wnck.screen_get_default()
            screen.force_update()
            window = screen.get_active_window()
            if window is not None:
                pid = window.get_pid()
                with open("/proc/{pid}/cmdline".format(pid=pid)) as f:
                    active_window_name = f.read()
        else:
            try:
                from gi.repository import Gtk, Wnck
                gi = "Installed"
            except ImportError:
                logging.info("gi.repository not installed")
                gi = None
            if gi is not None:
                Gtk.init([])  # necessary if not using a Gtk.main() loop
                screen = Wnck.Screen.get_default()
                screen.force_update()  # recommended per Wnck documentation
                active_window = screen.get_active_window()
                pid = active_window.get_pid()
                with open("/proc/{pid}/cmdline".format(pid=pid)) as f:
                    active_window_name = f.read()
    Elif sys.platform in ['Windows', 'win32', 'cygwin']:
        # http://stackoverflow.com/a/608814/562769
        import win32gui
        window = win32gui.GetForegroundWindow()
        active_window_name = win32gui.GetWindowText(window)
    Elif sys.platform in ['Mac', 'darwin', 'os2', 'os2emx']:
        # http://stackoverflow.com/a/373310/562769
        from AppKit import NSWorkspace
        active_window_name = (NSWorkspace.sharedWorkspace()
                              .activeApplication()['NSApplicationName'])
    else:
        print("sys.platform={platform} is unknown. Please report."
              .format(platform=sys.platform))
        print(sys.version)
    return active_window_name

print("Active window: %s" % str(get_active_window()))
14
Martin Thoma

Il n'est vraiment pas nécessaire d'importer de dépendance externe pour des tâches comme celle-ci. Python est livré avec une interface de fonction étrangère assez soignée - ctypes , qui permet d'appeler nativement les bibliothèques partagées C. Il inclut même des liaisons spécifiques pour la plupart DLL Win32 courantes.

Par exemple. pour obtenir le PID de la fenêtre précédente:

import ctypes
from ctypes import wintypes

user32 = ctypes.windll.user32

h_wnd = user32.GetForegroundWindow()
pid = wintypes.DWORD()
user32.GetWindowThreadProcessId(h_wnd, ctypes.byref(pid))
print(pid.value)
6
Nuno André

Pour les utilisateurs de Linux: Toutes les réponses fournies nécessitaient des modules supplémentaires comme "wx" qui avaient de nombreuses erreurs d'installation ("pip" a échoué à la construction), mais j'ai pu modifier cette solution assez facilement -> source d'origine . Il y avait des bugs dans l'original ( Python TypeError sur regex )

import sys
import os
import subprocess
import re

def get_active_window_title():
    root = subprocess.Popen(['xprop', '-root', '_NET_ACTIVE_WINDOW'], stdout=subprocess.PIPE)
    stdout, stderr = root.communicate()

    m = re.search(b'^_NET_ACTIVE_WINDOW.* ([\w]+)$', stdout)
    if m != None:
        window_id = m.group(1)
        window = subprocess.Popen(['xprop', '-id', window_id, 'WM_NAME'], stdout=subprocess.PIPE)
        stdout, stderr = window.communicate()
    else:
        return None

    match = re.match(b"WM_NAME\(\w+\) = (?P<name>.+)$", stdout)
    if match != None:
        return match.group("name").strip(b'"')

    return None

if __name__ == "__main__":
    print(get_active_window_title())

L'avantage est qu'il fonctionne sans modules supplémentaires. Si vous voulez qu'il fonctionne sur plusieurs plates-formes, il suffit de changer la chaîne de commande et l'expression régulière pour obtenir les données que vous souhaitez en fonction de la plate-forme (avec la détection de plate-forme standard if/else indiquée ci-dessus sys.platform ).

Sur une note latérale: l'importation wnck ne fonctionne qu'avec python2.x lorsqu'il est installé avec "Sudo apt-get install python-wnck", puisque j'utilisais python3.x la seule option était pypie que je n'ai pas testée. J'espère que ceci aide quelqu'un d'autre.

6
James Nelson

Merci à la réponse de Nuno André, qui a montré comment utiliser les ctypes pour interagir avec les API Windows. J'ai écrit un exemple d'implémentation en utilisant ses conseils.

La bibliothèque ctypes est incluse avec Python depuis la v2.5, ce qui signifie que presque tous les utilisateurs l'ont. Et c'est une interface beaucoup plus propre que les bibliothèques anciennes et mortes comme win32gui (dernière mise à jour en 2017 au moment de la rédaction de cet article).

La documentation est ici: https://docs.python.org/3/library/ctypes.html (Vous devez lire son aide à l'utilisation si vous voulez écrire votre propre code, sinon vous pouvez provoquer des plantages d'erreur de segmentation , hehe.)

Fondamentalement, ctypes inclut des liaisons pour les DLL Windows les plus courantes. Voici comment récupérer le titre de la fenêtre de premier plan en Python pur, sans avoir besoin de bibliothèques externes! Juste les ctypes intégrés! :-)

La chose la plus cool à propos des ctypes est que vous pouvez Google any API Windows pour tout ce dont vous avez besoin, et si vous voulez l'utiliser, vous pouvez le faire via ctypes !

Code Python 3:

from typing import Optional
from ctypes import wintypes, windll, create_unicode_buffer

def getForegroundWindowTitle() -> Optional[str]:
    hWnd = windll.user32.GetForegroundWindow()
    length = windll.user32.GetWindowTextLengthW(hWnd)
    buf = create_unicode_buffer(length + 1)
    windll.user32.GetWindowTextW(hWnd, buf, length + 1)

    # 1-liner alternative: return buf.value if buf.value else None
    if buf.value:
        return buf.value
    else:
        return None

Les performances sont extrêmement bonnes: 0.01 MILLISECONDS sur mon ordinateur (0.00001 secondes).

Fonctionnera également sur Python 2 avec des modifications très mineures. Si vous êtes sur Python 2, je pense que vous n'avez qu'à supprimer les annotations de type (from typing import Optional et -> Optional[str]). :-)

Prendre plaisir!

Explications techniques Win32:

La variable length est la longueur des caractères réels en UTF-16 (Windows Wide "Unicode") CARACTÈRES. (Ce n'est PAS le nombre d'octets.) Nous devons ajouter + 1 pour ajouter de l'espace pour le terminateur nul à la fin des chaînes de style C. Si nous ne le faisons pas, nous n'aurions pas assez d'espace dans le tampon pour ajuster le caractère réel final du texte réel, et Windows tronquerait la chaîne retournée (il le fait pour s'assurer qu'il correspond à la chaîne finale super importante Null -terminateur).

Le create_unicode_buffer la fonction alloue de la place pour autant de PERSONNAGES UTF-16.

La plupart (ou tous? Lisez toujours les documents MSDN de Microsoft!) Les API Windows liées au texte Unicode prennent la longueur du tampon en CARACTÈRES, PAS en octets.

Regardez également attentivement les appels de fonction. Certains se terminent par W (tels que GetWindowTextLengthW). Cela signifie "chaîne large", qui est le nom Windows pour les chaînes Unicode. Il est très important que vous fassiez ces appels W pour obtenir les chaînes Unicode appropriées (avec prise en charge des caractères internationaux).

PS: Windows utilise Unicode depuis longtemps. Je sais pertinemment que Windows 10 est entièrement Unicode et ne veut que les appels de fonction W. Je ne connais pas la date limite exacte lorsque les anciennes versions de Windows utilisaient des formats de chaîne multi-octets autre, mais je pense que c'était avant Windows Vista, et qui s'en soucie? Les anciennes versions de Windows (même 7 et 8.1) sont mortes et non prises en charge par Microsoft.

Encore une fois ... profitez-en! :-)

4
Mitch McMabers

Je voulais juste ajouter au cas où cela aiderait, j'ai une fonction pour mon programme (c'est un logiciel pour l'éclairage de mon PC, j'ai cette simple fonction de quelques lignes:

def isRunning(process_name):
   foregroundWindow = GetWindowText(GetForegroundWindow())
   return process_name in foregroundWindow
0
Amy Gamble