{"id":51871924,"url":"https://github.com/controllercustom/touchwasd","last_synced_at":"2026-07-25T00:32:36.919Z","repository":{"id":371191180,"uuid":"1295874204","full_name":"controllercustom/touchwasd","owner":"controllercustom","description":"Touch WASD keyboard using phone or tablet made with Arduino ESP32S3","archived":false,"fork":false,"pushed_at":"2026-07-20T22:57:11.000Z","size":518,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-21T00:27:28.890Z","etag":null,"topics":["arduino","atoms3","esp32s3","m5stack"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/controllercustom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-07-09T23:48:24.000Z","updated_at":"2026-07-20T22:57:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/controllercustom/touchwasd","commit_stats":null,"previous_names":["controllercustom/touchwasd"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/controllercustom/touchwasd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/controllercustom%2Ftouchwasd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/controllercustom%2Ftouchwasd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/controllercustom%2Ftouchwasd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/controllercustom%2Ftouchwasd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/controllercustom","download_url":"https://codeload.github.com/controllercustom/touchwasd/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/controllercustom%2Ftouchwasd/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35861393,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-24T02:00:07.870Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","atoms3","esp32s3","m5stack"],"created_at":"2026-07-25T00:32:36.029Z","updated_at":"2026-07-25T00:32:36.907Z","avatar_url":"https://github.com/controllercustom.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# touchWASD — Touchscreen WASD USB Keyboard\n\ntouchWASD turns an M5Stack AtomS3 (or any ESP32-S3) into a USB HID keyboard controlled by a circular touch overlay on your phone or tablet. Open a browser, touch a direction on the circle, and the corresponding WASD or arrow key is pressed on your computer — no software to install on the target machine.\n\n```\n[ Phone/Tablet ] --WiFi--\u003e [ AtomS3 ] --USB--\u003e [ Computer ]\n  (touch circle          (keys pressed     (sees standard\n   on web page)           via WebSocket)    USB keyboard)\n```\n\nPerfect for gaming, presentations, KVM control, or any situation where you want a wireless WASD/arrow input.\n\n## Features\n\n- **Zero software on the target PC** — shows up as a standard USB keyboard\n- **Web-based 8-slice touch circle** — intuitive directional input from any phone or tablet\n- **WASD mode** (default) — sends `W` `A` `S` `D` to the host PC\n- **Arrow key mode** — sends ↑ ← ↓ → instead\n- **Diagonal support** — NE/SE/SW/NW slices send two simultaneous keys (e.g., `W` + `D`)\n- **Slide-typing** — drag your finger across slices; keys release from the old slice and press on the new one\n- **4 sizes** — Small, Medium, Large, Full, persisted in browser storage\n- **7 positions** — place the circle at center, top, bottom, or any corner\n- **Auto-relocating gear** — the settings button moves out of the way when placed at top-right\n- **Multi-client** — multiple tablets can connect simultaneously; key presses are reference-counted\n- **WiFiManager** — configure WiFi via captive portal on first boot\n- **Customizable mDNS hostname** — default `touchwasd.local`, configurable in the captive portal\n- **OTA updates** — upload firmware wirelessly via native arduino-cli, `espota.py`, or browser (`/update`)\n- **AtomS3 display** — shows IP, hostname, mode, and client count on the built-in 128×128 screen\n\n## Hardware Requirements\n\n| Component | Required | Notes |\n|---|---|---|\n| ESP32-S3 with native USB | Yes | M5Stack AtomS3 recommended; any ESP32-S3 works |\n| USB-C cable | Yes | Connects ESP32 to target computer |\n| Phone / Tablet | Yes | Any device with a web browser |\n\n## Quick Start\n\n### 1. Flash the Firmware\n\n#### Arduino CLI\n\nPinned builds (use `--profile` instead of `--fqbn` for exact versions from `sketch.yaml`):\n\n```bash\n# AtomS3 (pinned via sketch.yaml)\narduino-cli compile --profile atoms3 .\n# Hold Reset button 2-3s on AtomS3 for download mode (LED turns green)\narduino-cli upload -p /dev/ttyACM0 --fqbn \"esp32:esp32:m5stack_atoms3:PartitionScheme=default_8MB,USBMode=default,CDCOnBoot=default\" .\n\n# Generic ESP32-S3 (pinned via sketch.yaml)\narduino-cli compile --profile esp32s3 .\n# Serial upload (port is typically /dev/ttyUSB0 or /dev/ttyACMx)\narduino-cli upload -p /dev/ttyUSB0 --fqbn \"esp32:esp32:esp32s3:USBMode=default,CDCOnBoot=default\" .\n```\n\n#### Arduino IDE\n\n1. Add `https://espressif.github.io/arduino-esp32/package_esp32_index.json` to *Additional Boards Manager URLs*\n2. Install **ESP32** board package and libraries: **WiFiManager**, **M5GFX** (AtomS3 only), **WebSockets**. The USB HID keyboard library is built into the ESP32 core — no additional install needed.\n3. Select **M5AtomS3** (or **ESP32S3 Dev Module** for generic boards)\n4. Set *Tools → USB Mode → **USB-OTG (TinyUSB)***\n5. Set *Tools → USB CDC On Boot → **Disabled***\n6. AtomS3 only: *Tools → Partition Scheme → **8M with spiffs (3MB APP/1.5MB SPIFFS)***\n7. Open `touchwasd.ino` and upload\n\n\u003e **AtomS3 bootloader mode**: With CDC ACM disabled, press and hold the small Reset button for 2–3 seconds. The LED turns green solid. Upload immediately after.\n\n### 2. Connect to WiFi\n\nOn first boot, the ESP32 starts an access point named **touchWASD-Config**. Connect to it with your phone — a captive portal opens. Select your WiFi network and enter the password.\n\n### 3. Open the Touch Overlay\n\nOnce connected, open a browser on any device on the same network:\n\n```\nhttp://touchwasd.local\n```\n\nA circular 8-slice touch overlay appears. Tap or drag on the circle to send keystrokes to the host computer.\n\n### 4. Plug into the Host Computer\n\nConnect the ESP32 to the computer via its **native USB port**. It enumerates as a standard USB HID keyboard — no drivers needed.\n\n## Usage\n\n### Touch Circle\n\nThe circle is divided into 8 slices (45° each), centered at 0° (straight up):\n\n| Slice | Label | Keys Sent |\n|-------|-------|-----------|\n| North (top) | **W** ↑ | `W` |\n| Northeast | **W+D** ↗ | `W` + `D` |\n| East (right) | **D** → | `D` |\n| Southeast | **D+S** ↘ | `D` + `S` |\n| South (bottom) | **S** ↓ | `S` |\n| Southwest | **S+A** ↙ | `S` + `A` |\n| West (left) | **A** ← | `A` |\n| Northwest | **A+W** ↖ | `A` + `W` |\n\n**Single tap**: Press and release — sends the key(s) then releases immediately.\n\n**Hold**: Sends and holds the key(s). Release your finger to release.\n\n**Slide**: Drag across slices — held keys release and new ones press as you cross slice boundaries.\n\n### Mode Switch\n\nTap the ⚙ cog button to open the settings panel. From here you can:\n\n- **Mode**: toggle between WASD and Arrow keys (persisted on the device)\n- **Size**: choose Small, Medium, Large, or Full (persisted in browser)\n- **Position**: place the circle at center, top, bottom, or any corner (persisted in browser)\n\nThe cog button auto-relocates to avoid overlapping the circle.\n\n### Multiple Devices\n\nOpen `http://touchwasd.local` on multiple phones or tablets. All clients share the same key state — pressing `W` on one device and `D` on another simultaneously produces `W`+`D`. Reference counting ensures keys release only when every client has released the key.\n\n## OTA Updates\n\nOnce the device is online and connected, upload firmware wirelessly.\n\n**Native arduino-cli OTA** (arduino-cli 1.5.1+). Pass the device **IP** (or hostname) directly to `-p` with `--protocol network` (without it arduino-cli tries to open the address as a serial port). Default OTA port is 3232; ArduinoOTA must be enabled in firmware (it is). A disabled OTA password is passed as `--upload-field password=\"\"`:\n\n```bash\narduino-cli compile --profile atoms3 . \\\n  \u0026\u0026 arduino-cli upload -p \u003cip\u003e --fqbn \"esp32:esp32:m5stack_atoms3:PartitionScheme=default_8MB,USBMode=default,CDCOnBoot=default\" \\\n  --upload-field port=3232 --upload-field password=\"\" \\\n  --protocol network \\\n  .\n```\n\n**espota.py fallback** (path must match installed esp32 core):\n\n```bash\narduino-cli compile --profile atoms3 . --output-dir /tmp/touchwasd-build \\\n  \u0026\u0026 python3 ~/.arduino15/packages/esp32/hardware/esp32/3.3.10/tools/espota.py \\\n  -i touchwasd.local -f /tmp/touchwasd-build/touchwasd.ino.bin -r -d\n# If OTA password is enabled, add: -a \"\u003cpassword\u003e\"\n```\n\nOr use the web interface at `http://touchwasd.local/update`.\n\n### OTA Password\n\nBy default, OTA updates require no password — anyone on your network can upload firmware. To enable password protection:\n\n1. Open `touchwasd.ino` and uncomment this line near the top:\n   ```cpp\n   // #define OTA_PASS \"your-password-here\"\n   ```\n2. Change `\"your-password-here\"` to your chosen password.\n3. Recompile and upload via serial.\n\nPassword applies to ArduinoOTA — native arduino-cli OTA (`--upload-field password=\"\u003cpassword\u003e\"`), `espota.py -a \"\u003cpassword\u003e\"`, and the Web OTA interface (HTTP Basic Auth).\n\n## Resetting WiFi\n\nHold the built-in button for 5 seconds:\n\n- **AtomS3**: hold GPIO41 button (display shows \"Resetting WiFi...\")\n- **Generic**: hold BOOT button (GPIO0)\n\nWiFi credentials are erased and the device reboots into the `touchWASD-Config` captive portal.\n\n## Build Reference\n\n### Board Options\n\n```\nAtomS3:   esp32:esp32:m5stack_atoms3:PartitionScheme=default_8MB,USBMode=default,CDCOnBoot=default\nGeneric:  esp32:esp32:esp32s3:USBMode=default,CDCOnBoot=default\n```\n\n### Required Libraries\n\n- **WiFiManager** by tzapu\n- **WebSockets** by Markus Sattler\n- **M5GFX** by M5Stack (AtomS3 only — optional for generic boards)\n- USB HID keyboard is built into the ESP32 core (`USB.h`) — no additional library needed\n\n### Versions\n\nPinned in `sketch.yaml` for reproducible builds:\n\n| Component | Version | Notes |\n|---|---|---|\n| ESP32 Core | 3.3.10 | Pinned in `sketch.yaml` |\n| WiFiManager | 2.0.17 | Pinned in `sketch.yaml` |\n| WebSockets | 2.7.2 | Pinned in `sketch.yaml` |\n| M5GFX | 0.2.26 | Pinned in `sketch.yaml` (AtomS3 only) |\n\n\n## Tests\n\nPython 3 test suite at `test/`. Tests both core logic and wire protocol:\n\n```bash\n# Mock device tests (no hardware needed)\npython3 -m pytest test/ -v\n\n# Live device tests (requires AtomS3 on the network)\npython3 -m pytest test/test_protocol.py --host touchwasd.local -v\n```\n\nWith `python3-evdev` installed and the device's USB HID keyboard visible to the host (e.g. `/dev/input/event5`), the live tests also assert the **actual USB HID keystrokes** the device emits — see `test/test_hid.py`. Without evdev (or no `--host`), those HID-inspection assertions are skipped and only protocol-level checks run.\n\n### `test/test_core.py` — Unit tests (stdlib only, no dependencies)\n- `charToHID()` lookup table validation against every ASCII character\n- Key state management: press/release lifecycle, 6-key limit, swap-removal\n- Reference counting: multi-client, overflow cap at 255\n- Mode mapping: WASD vs Arrow key translation\n- HID report format: 8-byte report structure\n\n### `test/test_protocol.py` — Integration tests (requires `websocket-client`)\n- `MockTouchWASDDevice`: simulated ESP32 with WS+HTTP servers; `--host` flag connects to a real device instead\n- WebSocket handshake, key press/release, diagonal, release-all (`~`)\n- Mode switch round-trip (`#MODE:wasd` / `#MODE:arrows`)\n- Two-client reference counting over real WS connections\n- Disconnect resets state, new client receives mode sync\n- HTTP root page serving\n\n### `test/test_hid.py` — Live USB HID inspection (requires `--host` + `python3-evdev`)\n- Reads the device's real keystrokes via evdev (`/dev/input/event*`)\n- Press/release round-trip, diagonal two-key, arrow-mode mapping, release-all\n- Verifies the monitor reports HID usage codes (not raw evdev codes)\n\n### `test/test_e2e.py` — Latency measurement (standalone, no pytest)\n- Sends key presses over WebSocket, observes HID arrival via evdev `select.select()`\n- Measures end-to-end latency (WS send → USB HID on host) with statistical report\n- Optional `--serial` flag reads `[TIMING]` markers for firmware processing time split\n- Configurable pass/fail threshold (default 20ms p99)\n- Usage: `python3 test/test_e2e.py --host \u003cip\u003e [--serial /dev/ttyUSB0] [--samples 50]`\n\n### Live Test Prerequisites\n\nTo run live tests with USB HID inspection against a plugged-in device:\n\n1. Install `python3-evdev`: `pip install python3-evdev`\n2. Ensure your user can read `/dev/input/event*`. On Ubuntu 24.04 and similar distros, add yourself to the **input** group:\n   ```bash\n   sudo usermod -aG input $USER\n   # Log out and back in (or run `newgrp input`) for the change to take effect\n   ```\n3. Run with both flags so tests connect over WiFi *and* inspect USB HID locally:\n   ```bash\n   python3 -m pytest test/ --host 192.168.1.xxx -v\n   ```\n\nThe `--hid-name` flag can override the auto-detected keyboard name substring if needed (e.g., `--hid-name \"ESP32S3_DEV\"`).\n\n## License\n\nMIT","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontrollercustom%2Ftouchwasd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcontrollercustom%2Ftouchwasd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontrollercustom%2Ftouchwasd/lists"}