Python UIAutomation for Windows - comprehensive library for automating Windows applications using Microsoft's UIAutomation framework
Comprehensive Windows API wrapper providing low-level system operations for window management, process control, and system utilities. The Win32API class offers access to essential Windows functions through a Python interface.
Central class providing static methods for Windows API operations.
class Win32API:
"""Comprehensive wrapper for Windows API functions."""
# Window Management
@staticmethod
def SetForegroundWindow(handle: int) -> bool:
"""
Bring window to foreground.
Args:
handle: Window handle (HWND)
Returns:
bool: True if successful
"""
@staticmethod
def ShowWindow(handle: int, state: int) -> bool:
"""
Set window display state.
Args:
handle: Window handle (HWND)
state: ShowWindow constant (SW_HIDE, SW_SHOW, etc.)
Returns:
bool: True if successful
"""
@staticmethod
def MoveWindow(handle: int, x: int, y: int, width: int, height: int, repaint: bool = True) -> bool:
"""
Move and resize a window.
Args:
handle: Window handle (HWND)
x: New X position
y: New Y position
width: New width
height: New height
repaint: Whether to repaint the window
Returns:
bool: True if successful
"""
@staticmethod
def GetWindowRect(handle: int) -> tuple[int, int, int, int]:
"""
Get window rectangle coordinates.
Args:
handle: Window handle (HWND)
Returns:
tuple: (left, top, right, bottom) coordinates
"""
@staticmethod
def GetWindowText(handle: int) -> str:
"""
Get window title text.
Args:
handle: Window handle (HWND)
Returns:
str: Window title text
"""
@staticmethod
def FindWindow(className: str = None, windowName: str = None) -> int:
"""
Find window by class name and/or window name.
Args:
className: Window class name (optional)
windowName: Window title (optional)
Returns:
int: Window handle (HWND) or 0 if not found
"""
@staticmethod
def EnumWindows() -> list[int]:
"""
Enumerate all top-level windows.
Returns:
list: List of window handles (HWNDs)
"""class Win32API:
@staticmethod
def MouseClick(x: int, y: int, button: int = 1) -> None:
"""
Click mouse at coordinates.
Args:
x: Screen X coordinate
y: Screen Y coordinate
button: Mouse button (1=left, 2=right, 3=middle)
"""
@staticmethod
def MouseRightClick(x: int, y: int) -> None:
"""Right-click at coordinates."""
@staticmethod
def MouseDoubleClick(x: int, y: int) -> None:
"""Double-click at coordinates."""
@staticmethod
def MouseMoveTo(x: int, y: int) -> None:
"""Move mouse to coordinates."""
@staticmethod
def MouseDragDrop(x1: int, y1: int, x2: int, y2: int) -> None:
"""Drag from (x1,y1) to (x2,y2)."""
@staticmethod
def GetCursorPos() -> tuple[int, int]:
"""
Get current cursor position.
Returns:
tuple: (x, y) cursor coordinates
"""
@staticmethod
def SetCursorPos(x: int, y: int) -> bool:
"""
Set cursor position.
Args:
x: Screen X coordinate
y: Screen Y coordinate
Returns:
bool: True if successful
"""class Win32API:
@staticmethod
def SendKey(key: int, modifiers: int = 0) -> None:
"""
Send key with modifiers.
Args:
key: Virtual key code
modifiers: Modifier key flags
"""
@staticmethod
def SendKeys(keys: str) -> None:
"""
Send sequence of keys.
Args:
keys: Key sequence string
"""
@staticmethod
def KeyDown(key: int) -> None:
"""Press key down."""
@staticmethod
def KeyUp(key: int) -> None:
"""Release key."""
@staticmethod
def GetKeyState(key: int) -> int:
"""
Get key state.
Args:
key: Virtual key code
Returns:
int: Key state flags
"""
@staticmethod
def GetAsyncKeyState(key: int) -> int:
"""
Get asynchronous key state.
Args:
key: Virtual key code
Returns:
int: Key state flags
"""class Win32API:
@staticmethod
def GetScreenSize() -> tuple[int, int]:
"""
Get screen dimensions.
Returns:
tuple: (width, height) in pixels
"""
@staticmethod
def GetPixelColor(x: int, y: int) -> int:
"""
Get pixel color from screen.
Args:
x: Screen X coordinate
y: Screen Y coordinate
Returns:
int: Color value
"""
@staticmethod
def GetSystemMetrics(index: int) -> int:
"""
Get system metrics.
Args:
index: System metrics index
Returns:
int: Metric value
"""
@staticmethod
def GetComputerName() -> str:
"""
Get computer name.
Returns:
str: Computer name
"""
@staticmethod
def GetUserName() -> str:
"""
Get current user name.
Returns:
str: User name
"""class Win32API:
@staticmethod
def GetCurrentProcessId() -> int:
"""
Get current process ID.
Returns:
int: Process ID
"""
@staticmethod
def GetWindowThreadProcessId(handle: int) -> tuple[int, int]:
"""
Get thread and process ID for window.
Args:
handle: Window handle (HWND)
Returns:
tuple: (thread_id, process_id)
"""
@staticmethod
def TerminateProcess(processId: int) -> bool:
"""
Terminate process by ID.
Args:
processId: Process ID to terminate
Returns:
bool: True if successful
"""
@staticmethod
def CreateProcess(commandLine: str) -> int:
"""
Create new process.
Args:
commandLine: Command line to execute
Returns:
int: Process ID or 0 if failed
"""class Win32API:
@staticmethod
def MessageBox(text: str, title: str = "", type: int = 0) -> int:
"""
Display message box.
Args:
text: Message text
title: Dialog title
type: Message box type (MB_OK, MB_YESNO, etc.)
Returns:
int: User response (IDOK, IDYES, etc.)
"""
@staticmethod
def InputBox(prompt: str, title: str = "", default: str = "") -> str:
"""
Display input dialog.
Args:
prompt: Input prompt
title: Dialog title
default: Default input value
Returns:
str: User input or empty string if cancelled
"""class Win32API:
@staticmethod
def GetCurrentDirectory() -> str:
"""
Get current working directory.
Returns:
str: Current directory path
"""
@staticmethod
def SetCurrentDirectory(path: str) -> bool:
"""
Set current working directory.
Args:
path: Directory path
Returns:
bool: True if successful
"""
@staticmethod
def GetTempPath() -> str:
"""
Get temporary files directory.
Returns:
str: Temp directory path
"""
@staticmethod
def GetSpecialFolderPath(folder: int) -> str:
"""
Get special folder path.
Args:
folder: Special folder constant
Returns:
str: Folder path
"""class ShowWindow:
"""Constants for ShowWindow function."""
SW_HIDE: int = 0
SW_SHOWNORMAL: int = 1
SW_SHOWMINIMIZED: int = 2
SW_SHOWMAXIMIZED: int = 3
SW_SHOWNOACTIVATE: int = 4
SW_SHOW: int = 5
SW_MINIMIZE: int = 6
SW_SHOWMINNOACTIVE: int = 7
SW_SHOWNA: int = 8
SW_RESTORE: int = 9
SW_SHOWDEFAULT: int = 10class MB:
"""Message box type constants."""
MB_OK: int = 0
MB_OKCANCEL: int = 1
MB_ABORTRETRYIGNORE: int = 2
MB_YESNOCANCEL: int = 3
MB_YESNO: int = 4
MB_RETRYCANCEL: int = 5
MB_ICONHAND: int = 16
MB_ICONQUESTION: int = 32
MB_ICONEXCLAMATION: int = 48
MB_ICONASTERISK: int = 64class MessageBoxResult:
"""Message box return value constants."""
IDOK: int = 1
IDCANCEL: int = 2
IDABORT: int = 3
IDRETRY: int = 4
IDIGNORE: int = 5
IDYES: int = 6
IDNO: int = 7class Win32API:
# Special key name to virtual key code mapping
SpecialKeyDict: dict = {
'{ENTER}': 13,
'{TAB}': 9,
'{ESC}': 27,
'{SPACE}': 32,
'{BACKSPACE}': 8,
'{DELETE}': 46,
'{HOME}': 36,
'{END}': 35,
'{LEFT}': 37,
'{UP}': 38,
'{RIGHT}': 39,
'{DOWN}': 40,
'{PAGEUP}': 33,
'{PAGEDOWN}': 34,
'{F1}': 112,
# ... additional special keys
}
# Character to virtual key code mapping
CharacterDict: dict = {
'a': 65, 'A': 65,
'b': 66, 'B': 66,
# ... additional character mappings
}import uiautomation
# Find window by title
handle = uiautomation.Win32API.FindWindow(None, "Calculator")
if handle:
# Bring to foreground
uiautomation.Win32API.SetForegroundWindow(handle)
# Get window position and size
left, top, right, bottom = uiautomation.Win32API.GetWindowRect(handle)
print(f"Window bounds: ({left}, {top}, {right}, {bottom})")
# Move and resize window
uiautomation.Win32API.MoveWindow(handle, 100, 100, 800, 600)
# Maximize window
uiautomation.Win32API.ShowWindow(handle, uiautomation.ShowWindow.SW_SHOWMAXIMIZED)# Get screen dimensions
width, height = uiautomation.Win32API.GetScreenSize()
print(f"Screen size: {width} x {height}")
# Get computer and user info
computer = uiautomation.Win32API.GetComputerName()
user = uiautomation.Win32API.GetUserName()
print(f"Computer: {computer}, User: {user}")
# Get cursor position
x, y = uiautomation.Win32API.GetCursorPos()
print(f"Cursor at: ({x}, {y})")# Simple message box
result = uiautomation.Win32API.MessageBox("Hello World!", "Greeting")
# Yes/No question
result = uiautomation.Win32API.MessageBox(
"Do you want to continue?",
"Confirmation",
uiautomation.MB.MB_YESNO | uiautomation.MB.MB_ICONQUESTION
)
if result == uiautomation.MessageBoxResult.IDYES:
print("User clicked Yes")
elif result == uiautomation.MessageBoxResult.IDNO:
print("User clicked No")
# Input dialog
user_input = uiautomation.Win32API.InputBox("Enter your name:", "Input Required", "Default Name")
if user_input:
print(f"User entered: {user_input}")# Get current process ID
current_pid = uiautomation.Win32API.GetCurrentProcessId()
print(f"Current process ID: {current_pid}")
# Get process ID for a window
handle = uiautomation.Win32API.FindWindow(None, "Notepad")
if handle:
thread_id, process_id = uiautomation.Win32API.GetWindowThreadProcessId(handle)
print(f"Notepad process ID: {process_id}")
# Launch new process
new_pid = uiautomation.Win32API.CreateProcess("notepad.exe")
if new_pid:
print(f"Launched process with ID: {new_pid}")# Check if key is currently pressed
if uiautomation.Win32API.GetAsyncKeyState(uiautomation.Keys.VK_SHIFT) & 0x8000:
print("Shift key is currently pressed")
# Send complex key combinations
uiautomation.Win32API.KeyDown(uiautomation.Keys.VK_CONTROL)
uiautomation.Win32API.SendKey(uiautomation.Keys.VK_C) # Ctrl+C
uiautomation.Win32API.KeyUp(uiautomation.Keys.VK_CONTROL)# Get and set working directory
current_dir = uiautomation.Win32API.GetCurrentDirectory()
print(f"Current directory: {current_dir}")
# Change directory
success = uiautomation.Win32API.SetCurrentDirectory("C:\\Users")
if success:
print("Directory changed successfully")
# Get special folder paths
temp_path = uiautomation.Win32API.GetTempPath()
print(f"Temp directory: {temp_path}")def list_all_windows():
"""List all top-level windows."""
window_handles = uiautomation.Win32API.EnumWindows()
for handle in window_handles:
title = uiautomation.Win32API.GetWindowText(handle)
if title: # Only show windows with titles
left, top, right, bottom = uiautomation.Win32API.GetWindowRect(handle)
print(f"Window: '{title}' at ({left}, {top}) size ({right-left}x{bottom-top})")
# List all windows
list_all_windows()def wait_for_window(window_title, timeout=30):
"""Wait for a window to appear."""
import time
start_time = time.time()
while time.time() - start_time < timeout:
handle = uiautomation.Win32API.FindWindow(None, window_title)
if handle:
return handle
time.sleep(0.5)
return None
def ensure_window_visible(window_title):
"""Ensure window is visible and in foreground."""
handle = uiautomation.Win32API.FindWindow(None, window_title)
if handle:
# Restore if minimized
uiautomation.Win32API.ShowWindow(handle, uiautomation.ShowWindow.SW_RESTORE)
# Bring to foreground
uiautomation.Win32API.SetForegroundWindow(handle)
return True
return FalseInstall with Tessl CLI
npx tessl i tessl/pypi-uiautomation