Automate Windows Hello PIN entry via USB HID keyboard (Raspberry Pi Pico)
Project description
pywinhello
Automate Windows Hello PIN entry via USB HID keyboard (Raspberry Pi Pico).
Windows Hello's Credential Dialog is protected by UIPI — no software input method
(SendInput, pyautogui, pywinauto) can type into it. pywinhello uses a Raspberry Pi
Pico as a USB HID keyboard to bypass this restriction and enter PINs automatically.
Features
- Process-aware: identifies which app triggered Windows Hello, enters the correct PIN
- Two-pass detection: handles both PIN mode and fingerprint mode automatically
- Progressive API: from raw HID keyboard to full daemon monitor
- Zero polling: uses WinEvent hooks for instant dialog detection
- Automated Pico setup: flashes CircuitPython, downloads libraries, installs firmware
Install
pip install pywinhello
Hardware
Any Raspberry Pi Pico variant (Pico, Pico W, Pico 2, Pico 2 W) — ~$4.
Automated Setup
# Hold BOOTSEL on Pico, plug in USB, then:
pywinhello setup-pico
This handles everything: flashing CircuitPython, downloading adafruit_hid, and installing the HID bridge firmware.
Verify
pywinhello ping
# PONG from COM8
Quick Start
from pywinhello import enter_pin
# One-shot: enter PIN when dialog appears
event = enter_pin("1234")
print(event.dialog_dismissed) # True if PIN was accepted
Process-aware daemon
Create config.yaml:
apps:
- exe: MarketSpeed2.exe
pin: "1234"
- exe: chrome.exe
pin: "5678"
from pywinhello import HelloMonitor, load_config
config = load_config("config.yaml")
monitor = HelloMonitor(config)
monitor.serve(on_event=lambda e: print(e))
CLI
# Run monitor daemon
pywinhello serve -c config.yaml
# Ping Pico
pywinhello ping
# Set up Pico (flash + firmware)
pywinhello setup-pico
Architecture
Host (Python) Pico (CircuitPython) Windows
┌──────────┐ serial ┌──────────┐ USB HID ┌──────────┐
│ pywinhello│─────────→│ code.py │───────────→│ Credential│
│ │ TYPE:1234 │ keyboard │ keystrokes │ Dialog │
│ │←─────────│ │ │ │
│ │ OK │ │ │ │
└──────────┘ └──────────┘ └──────────┘
Progressive API
serve() Daemon — handles all dialogs automatically
└── handle_next() One-shot — wait for next dialog
└── enter_pin() Immediate — type PIN into current dialog
└── HIDKeyboard Raw — serial HID bridge
How it works
- Dialog detection —
SetWinEventHook(EVENT_OBJECT_CREATE)detectsCredential Dialog Xaml Hostinstantly - Process identification —
GetWindow(GW_OWNER)traces the dialog to the requesting process - Focus —
AttachThreadInput+SetForegroundWindowbrings the dialog to focus - Two-pass entry — Types PIN directly; if dialog persists, sends ESCAPE to navigate from fingerprint to PIN mode, then retries
- HID bypass — Physical keyboard input from the Pico bypasses UIPI restrictions
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pywinhello-0.2.0.tar.gz.
File metadata
- Download URL: pywinhello-0.2.0.tar.gz
- Upload date:
- Size: 86.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
483b6a1f7e7f4c7f31b2a98d2193b8352aa22588d48e86a7661be0a6bd01b93d
|
|
| MD5 |
01856380fcf59a3a240b68e31c879539
|
|
| BLAKE2b-256 |
fd6a7dab5c073a9df766b7bc57fbc01938cff6c1d6970d47fe25911669a95d0e
|
File details
Details for the file pywinhello-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pywinhello-0.2.0-py3-none-any.whl
- Upload date:
- Size: 23.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27e8acd95ca9f7faca49861535b25ff09304d9739e20af08d07dadaa81d7d4c9
|
|
| MD5 |
d4bdebc153c8a77a6bf24ff5c8d4df39
|
|
| BLAKE2b-256 |
dcf2fff36d4127f870ad280d08e814c7c5dc2dbb0fbc76012ef24901db6cd171
|