# Windows UI Automation Framework
_Automate Windows apps easily using pywinauto — Launch, Connect, and Control with one class._

---

## 🚀 Overview

This Python framework provides a **clean, unified interface for automating Windows applications**.  
It is built on top of `pywinauto` and `psutil` to help you **launch**, **connect**, and **interact with UI elements** programmatically — ideal for UI validation, smoke testing, or system automation.

**Key Capabilities**
- Launch and connect to Windows apps (EXE or UWP)
- Locate and interact with UI controls (`click`, `type_keys`, etc.)
- Extract UI tree structure to JSON for inspection
- Handle element reloads automatically with configurable wait times
- Optionally capture system metrics (CPU, memory, battery)
- Support HP laptop power switching *(available on request — HP confidential)*

---

## 🧩 Installation

```bash
pip install windows-ui-automation
```

**Requirements**
- Windows 11 or later  
- Python 3.10+ (tested with 3.13)  
- Dependencies: `pywinauto`, `psutil`, `wmi` *(optional)*  

---

## ⚡ Quickstart

Here’s how to launch and connect to an application using the latest `ensure_connected()` method.

```python
from app_manager import AppManager
import time

app = AppManager()

# Example 1: Use window title and app name for UWP apps and installed programs
app_window = app.ensure_connected(launch_app="Camera", connect_window="Camera")

# Example 2: Connect to a running app or launch by exe path if not running
# app_window = app.ensure_connected(
#     exe_path=r"C:\Users\ivers\AppData\Local\Programs\LM Studio\LM Studio.exe",
#     process_name="LM Studio.exe"
# )

# UI Locators
SETTINGS_BTN = {"automation_id": "settingsButton"}

# Interact with elements
app.element(SETTINGS_BTN).click_input()
time.sleep(1)
app.close(graceful=True)
```

✅ `ensure_connected()` automatically:
1. Tries to connect to an existing app window (by title or process).
2. If not found, launches the app (by `exe_path` or `app_name`).
3. Retries connection until success or timeout.

---

## 📘 Core Components

### 1. `AppManager` (in `app_manager.py`)
The central class that manages application lifecycle and UI element operations.

**Highlights**
- `ensure_connected()` – One-call launch & connect helper  
- `launch()` – Start an app via `.exe` path or UWP name  
- `connect()` – Attach to a running app via window title or process name  
- `extract_elements()` – Dump all UI elements as structured JSON  
- `element()` – Retrieve specific UI elements via locator dictionary  

**Custom Exceptions**
- `AppManagerError`
- `AumidNotFoundError`
- `WindowNotFoundError`
- `ElementNotFoundError`

**Element Wait Time**
```python
app = AppManager(ele_wait_time=8)  # wait up to 8 seconds for elements to appear
```
- Increase for slow apps
- Keep small for responsive ones
- You can manually call `app.refresh_elements()` anytime

---

### 2. System Metrics (`utils.py`)
```python
from utils import capture_system_metrics

capture_system_metrics('Test Started')
# ... run automation ...
capture_system_metrics('Test Completed')
```
Writes timestamped CPU/memory/battery stats to `system_metrics.csv`.

---

### 3. HP Power Switching (`hp_power_switch.py`)
> ⚠️ This module is **not included** in the public release because it contains HP confidential content.  
> For HP internal users, contact the author to request access to the HP-specific scripts.

**Functions (internal version)**
- `switch_power_mode(target)` – switch between `'AC'` and `'DC'`
- `get_power_status()` – retrieve current power source

**Requirements**
- HP laptop with BIOS power switching
- Admin privileges  
- `wmi`, `pywin32`

---

## 🧠 Example: Automating Camera

```python
from app_manager import AppManager

app = AppManager()
app_window = app.ensure_connected(launch_app="Camera", connect_window="Camera")

app.element({"automation_id": "settingsButton"}).click_input()
app.close(graceful=True)
```

---

## 💡 Common Patterns

### Typing into Fields
```python
SEARCH_BOX = {"control_type": "Edit", "name": "Search"}
app.element(SEARCH_BOX).type_keys("Hello World", with_spaces=True)
app.element(SEARCH_BOX).type_keys("{ENTER}")
```

### Clicking Menu Items
```python
FILE_MENU = {"control_type": "MenuItem", "name": "File"}
SAVE_OPTION = {"control_type": "MenuItem", "name": "Save"}

app.element(FILE_MENU).click_input()
app.element(SAVE_OPTION).click_input()
```

### Waiting for Elements
```python
app = AppManager(ele_wait_time=10)
time.sleep(2)
```

### Error Handling
```python
from app_manager import ElementNotFoundError

try:
    app.element({"name": "Submit"}).click_input()
except ElementNotFoundError:
    app.element({"automation_id": "submitBtn"}).click_input()
```

---

## 🧩 Advanced Usage

### Extract Elements Tree
```python
app.extract_elements(max_depth=5, include_invisible=True, dump_file="ui_elements.json")
```

### Use Locator Modules
```python
# locators_myapp.py
OK_BTN = {"control_type": "Button", "name": "OK"}
USERNAME = {"automation_id": "UsernameInput"}

# script
import locators_myapp as ui
app.element(ui.USERNAME).type_keys("user@example.com", with_spaces=True)
app.element(ui.OK_BTN).click_input()
```

---

## 🔍 Troubleshooting

**Element Not Found**
- Re-extract elements to confirm locator
- Check if control is visible and loaded
- Use `include_invisible=True` for hidden items
- Increase `ele_wait_time`

**App Won’t Launch**
- For UWP apps: ensure the name matches Start Menu entry  
- For `.exe`: use full path  
- Check if already running

**Metrics Not Captured**
- Verify permissions for output folder  
- Ensure `psutil` is installed

**HP Power Switching Not Available**
- Internal-only module (contact author for details)

---

## ⚙️ Logging

```python
import logging

logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
```

---

## 🧭 Project Structure

```
ui_automation/
├── app_manager.py
├── utils.py
├── hp_power_switch.py        # HP internal module (confidential)
├── requirements.txt
├── samples/
│   ├── auto_camera.py
│   ├── auto_lm_studio.py
│   └── locators_*.py
└── README.md
```

---

## 🤝 Contributing

When extending this framework:
1. Follow the established patterns (`AppManager`, locators modules, sample scripts)
2. Add docstrings to new methods
3. Test on Windows 11
4. Update README if adding new features

---

## 🧾 License

This project is provided for **educational and testing purposes**.  
For commercial or HP internal use, please contact the author.

---

## 💬 Author Contact

For inquiries or to request HP internal scripts (power switching, enterprise utilities),  
please contact the author directly.

---

Happy automating! 🚀
