web-dev-qa-db-ja.com

Pythonを使用してアクティブウィンドウを取得する

Pythonを使用してアクティブウィンドウを画面に表示したいのですが。

たとえば、ユーザー名とパスワードをadminとして入力するルーターの管理インターフェイス

その管理インターフェイスは、ユーザー名とパスワードの入力を自動化するためにpythonを使用してキャプチャしたいものです。

これを行うには、どのようなインポートが必要ですか?

24
Vinod K

Windowsでは、python for windows extensions( http://sourceforge.net/projects/pywin32/ )を使用できます):

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

以下のコードはpython 3:

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

(これは http://scott.sherrillmix.com/blog/programmer/active-window-logger/ にあります)

23

次のスクリプトは、Linux、Windows、Macで動作するはずです。現在、Linux(Ubuntu Mate Ubuntu 15.10)でのみテストされています。

前提条件

Linuxの場合

インストールwnckSudo apt-get install python-wnck Ubuntuで libwnck を参照)

Windowsの場合

確認してください win32gui 利用可能です

Macの場合

AppKitが利用可能であることを確認してください

スクリプト

#!/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

このようなタスクでは、外部の依存関係をインポートする必要はありません。 Pythonには、かなりきちんとした外部関数インターフェイスが付属しています- ctypes これにより、C共有ライブラリをネイティブで呼び出すことができます。ほとんどの特定のバインディングも含まれています一般的なWin32 DLL。

例えば。 foregorundウィンドウのPIDを取得するには:

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é

Linuxユーザーの場合:提供されたすべての回答には、インストール時に多数のエラーが発生する(「pip」がビルドに失敗する)「wx」などの追加モジュールが必要でしたが、このソリューションを簡単に変更できました-> 元のソース 。オリジナルにバグがありました( 正規表現のPython TypeError

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())

利点は、追加のモジュールなしで機能することです。複数のプラットフォーム間で動作させる場合は、コマンドと正規表現文字列を変更して、プラットフォームに基づいて必要なデータを取得するだけです(上記の標準のif/elseプラットフォーム検出を使用sys.platform)。

余談ですが、「Sudo apt-get install python-wnck」を使用してインストールした場合、インポートwnckはpython2.xでのみ機能します。python3.xを使用していたため、テストしていないpypieしかオプションがありませんでした。これが他の誰かを助けることを願っています。

6
James Nelson

ctypesを使用してWindows APIを操作する方法を示したNunoAndréの回答に感謝します。私は彼のヒントを使用して実装例を書きました。

ctypesライブラリは、Pythonに含まれています。v2.5以降です。つまり、ほとんどすべてのユーザーがこのライブラリを持っています。そして、win32guiのような古くて使用されていないライブラリよりもクリーンなインターフェイスですこの記事の執筆時点で2017年)。

ドキュメントはこちら: https://docs.python.org/3/library/ctypes.html (独自のコードを記述したい場合は、使用方法のヘルプを読む必要があります。そうしないと、セグメンテーション違反のクラッシュが発生する可能性があります、へへ。)

基本的に、ctypesには、最も一般的なWindows DLLのバインディングが含まれています。これは、外部ライブラリを必要とせずに、純粋なPythonでフォアグラウンドウィンドウのタイトルを取得する方法です。組み込みのctypeだけです! :-)

Ctypesの最もクールな点は、必要なものすべてに対してGoogleanyWindows APIを実行できることです。それを使用したい場合は、canctypesを介して実行してください!

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

パフォーマンスは非常に良好です。私のコンピューターでは0.01 MILLISECONDS(0.00001秒)。

Python 2でも非常に小さな変更を加えて機能します。Python 2を使用している場合は、型注釈(from typing import Optionalおよび-> Optional[str])。:-)

楽しい!

Win32技術説明:

length変数は、UTF-16(Windows Wide "Unicode")のactualテキスト文字の長さです。( BYTESの数ではありません。)Cスタイルの文字列の最後にnullターミネータ用のスペースを追加するには、+ 1を追加する必要があります。そうしないと、実際のテキストの最終的な実際の文字に合わせてバッファに十分なスペースがなくなり、Windowsは返された文字列を切り捨てます(これは、非常に重要な最終文字列Nullに合うようにするためです) -ターミネーター)。

create_unicode_buffer関数は、その数のUTF-16文字にスペースを割り当てます。

ほとんど(またはすべて?常にMicrosoftのMSDNドキュメントを読んでください!)Unicodeテキストに関連するWindows APIは、バッファ長を文字としてバイトとしてではありません。

また、関数呼び出しをよく見てください。一部はWで終わります(GetWindowTextLengthWなど)。これは、Unicode文字列のWindows名である「ワイド文字列」を表します。これらのW呼び出しを実行して、適切なUnicode文字列を取得することが非常に重要です(国際文字をサポートしています)。

PS:Windowsは長い間Unicodeを使用しています。 Windows 10は完全にUnicodeであり、W関数呼び出しのみを必要とするという事実は知っています。古いバージョンのWindowsがotherマルチバイト文字列形式を使用したときの正確な締切日はわかりませんが、Windows Vistaより前であると思いますが、誰が気にかけますか?古いバージョンのWindows(7と8.1も含む)は死んでおり、Microsoftはサポートしていません。

もう一度...お楽しみください! :-)

4
Mitch McMabers

それが役立つ場合に備えて追加したかったのですが、私には自分のプログラム用の機能があります(これは私のPCの照明用のソフトウェアで、次の単純な数行の機能があります:

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