Skip to main content

win32-window-monitor

Monitor global window events on Windows O.S. using the SetWinEventHook WIN32 SDK API:

  • Reports the event’s window HWND and PID (process identifier) to a Python callback.

  • Provides helper functions to easily retrieve the PID and executable path from the callback parameters.

Use cases

  • Tracks the focused window and its process

  • Tracks windows that capture the mouse or keyboard input

  • Tracks which process is causing your fullscreen game to lose focus (Kevin Turner’s initial motivation for the gist)

  • … (there are lots of UI Automation related events that could be useful)

Since the standard HWND and PID are readily available, you can utilize existing Python modules to interact with either the window or the process.

log_focused_window script

win32_window_monitor/main.py shows how to use the API to produce the example output below. After installing the win32-window-monitor package, the script log_focused_window is installed (in venv\Scripts\log_focused_window.exe, which is added to the PATH when activating the venv).

pip install win32-window-monitor
log_focused_window

which produces the following output:

101307546:0.00  Capture         W:0x1014c       P:7440          T:7592          Windows\explorer.exe    Running applications
101307687:0.14  Foreground      W:0x903ce       P:2508          T:1988          net\firefox.exe blep/win32_window_monitor: Monitor change of the focused window on Windows O.S.. Reports the focused window HWND, pid and executable to a Python callback. — Mozilla Firefox
101307687:0.00  Focus           W:0x903ce       P:2508          T:1988          net\firefox.exe blep/win32_window_monitor: Monitor change of the focused window on Windows O.S.. Reports the focused window HWND, pid and executable to a Python callback. — Mozilla Firefox
101312015:4.33  Show            W:0xc080c       P:7440          T:7592          Windows\explorer.exe
101312015:0.00  Show            W:0x10150       P:7440          T:7592          Windows\explorer.exe
101312031:0.02  Show            W:0x1065e       P:12428         T:11660         Notion\Notion.exe       Chrome Legacy Window
101312312:0.28  Capture         W:0x1014c       P:7440          T:7592          Windows\explorer.exe    Running applications
101312468:0.16  Foreground      W:0x20642       P:12428         T:11660         Notion\Notion.exe       Python: automated CI/Release/doc/Wheel
101312484:0.02  Focus           W:0x20642       P:12428         T:11660         Notion\Notion.exe       Python: automated CI/Release/doc/Wheel
101312484:0.00  Show            W:0x20642       P:12428         T:11660         Notion\Notion.exe       Python: automated CI/Release/doc/Wheel
101314312:1.83  Capture         W:0x1014c       P:7440          T:7592          Windows\explorer.exe    Running applications
101314421:0.11  Foreground      W:0x440820      P:16088         T:7192          System32\conhost.exe    C:\Windows\System32\cmd.exe - python  -m win32_window_monitor.main
101314437:0.02  Focus           W:0x440820      P:16088         T:7192          System32\conhost.exe    C:\Windows\System32\cmd.exe - python  -m win32_window_monitor.main

Columns content:

  • event time_ms : elapsed seconds since last event

  • event

  • W: HWND, the window handle

  • P: process id

  • T: thread id

  • short process path

  • window title

Actions made to produce those events:

  • Bring Firefox window to focus by clicking on it in the Taskbar. Events with explorer.exe are interactions with the Taskbar.

  • Bring Notion app to focus by clicking on it in the Taskbar.

  • Bring back cmd.exe to focus by clicking on it in the Taskbar.

Usage example

IMPORTANT: To track the current foreground window, you need at least HookEvent.SYSTEM_FOREGROUND and HookEvent.SYSTEM_MINIMIZEEND (HookEvent.SYSTEM_FOREGROUND is not sent when restoring a minimized window).

# win32_window_monitor/main_usage_example.py
from win32_window_monitor import *
from ctypes import wintypes


def on_event(win_event_hook_handle: HWINEVENTHOOK, event_id: int, hwnd: wintypes.HWND,
             id_object: wintypes.LONG, id_child: wintypes.LONG,
             event_thread_id: wintypes.DWORD,
             event_time_ms: wintypes.DWORD):
    # Called from the thread running the Windows message loop.
    # HookEvent provides a nice str, and unlike enum.Enum accepts any integer value.
    event_id = HookEvent(event_id)
    title = get_window_title(hwnd)
    process_id = get_hwnd_process_id(event_thread_id, hwnd)
    exe_path = get_process_filename(process_id) if process_id else '?'
    print(f'{event_time_ms} {event_id} P{process_id} {exe_path} {title}')


def main():
    # - init_com(): Initialize Windows COM (CoInitialize)
    # - post_quit_message_on_break_signal: Signal handlers to exit the
    # application when CTRL+C or CTRL+Break are pressed.
    with init_com(), post_quit_message_on_break_signal():
        # We must keep the event_hook_handle alive. Failure to do that may
        # cause a crash as the "trampoline" function generated by ctypes for
        # the event hook would be deleted.
        event_hook_handle = set_win_event_hook(on_event, HookEvent.SYSTEM_FOREGROUND)

        # Run the Windows message loop until the WM_QUIT message is received
        # (sent by signal handlers above). If you have a graphic UI (TkInter, Qt...), it is
        # likely that your application already has a Windows message loop that
        # should be used instead.
        run_message_loop()

        unhook_win_event(event_hook_handle)


if __name__ == '__main__':
    main()

Acknowledgments

This project core is heavily based on the work of others:

Metadata

Release files for win32-window-monitor 0.3.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for win32-window-monitor 0.3.3
File Size Uploaded
win32_window_monitor-0.3.3.tar.gz 21.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for win32-window-monitor 0.3.3
File Interpreter ABI Platform
win32_window_monitor-0.3.3-py3-none-any.whl Python 3 none any Details

Total release size: 35.7 kB

Release files / win32_window_monitor-0.3.3.tar.gz

Download URL win32_window_monitor-0.3.3.tar.gz
Size 21.1 kB
Tags Source
SHA-256 checksum
How to use checksums
0c9998f55a9aa8c49cd08d7fbf92fd62e9524459ba2dc693b95cf9e67c655d22
BLAKE2b-256 checksum
How to use checksums
3656390a8e90bb4de6f882d512c3a3e22d4a90c0184bfc2480b708d3a0d92665
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/4.0.2 CPython/3.11.6

Release files / win32_window_monitor-0.3.3-py3-none-any.whl

Download URL win32_window_monitor-0.3.3-py3-none-any.whl
Size 14.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c55a3bf5cd21588f04233461231b297834ff8b70d77e66fb85678eecf4b841bb
BLAKE2b-256 checksum
How to use checksums
e0f49756441d2aa48b75b0cafd83eab286759ea1a21033cb80a859676b3e9198
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/4.0.2 CPython/3.11.6

Release history Release notifications | RSS feed

This release

0.3.3 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page