Step 01

Parts List

Gather the following components. All parts are available from Adafruit, Digi-Key, or similar suppliers.

ComponentDetailsNotes
Adafruit Feather ESP32-S3 Rev TFT#5691Built-in 240×135 TFT display
3.5mm Stereo Jack Breakout (×2)TRRS or TRS, panel-mountFor A1 (nav) and A2 (select)
Accessibility switches (×1 or ×2)Any 3.5mm momentary assistive switchWired to GND, normally open
Small enclosureAny project box ≥ 80×50mm or 3D printed files3D print or off-the-shelf
USB-C cableData-capableFor firmware install and USB HID
The Feather has onboard D0, D1, and D2 buttons for mode selection — no extra buttons needed.
Step 02

Wiring & Pin Connections

Both switch inputs use internal pull-up resistors — a pressed switch reads LOW (False).

PinRoleWiringLogic
A1Navigate switchTip → A1, Sleeve → GNDActive LOW (Pull.UP)
A2Select / Single switchTip → A2, Sleeve → GNDActive LOW (Pull.UP)
GNDGround referenceSleeve of both jacks
D0Onboard — Direct Switch InterfaceBuilt-in buttonActive LOW (Pull.UP)
D1Onboard — single-switch modeBuilt-in buttonActive HIGH (Pull.DOWN)
D2Onboard — two-switch modeBuilt-in buttonActive HIGH (Pull.DOWN)
Do not apply voltage to A1 or A2 — digital input only. Use normally-open switches wired to GND.
Step 03

Install CircuitPython

Your board may require installation of the TinyUF2 bootloader. Follow the instructions on the Adafruit Learn Guide.

The firmware requires CircuitPython 10 or later.

  1. Download the latest .UF2 for Feather ESP32-S3 Rev TFT from circuitpython.org.
  2. Enter bootloader by clicking the RESET button— the drive FTHRS3BOOT appears.
  3. Drag and drop the .UF2 file onto FTHRS3BOOT. The board reboots automatically.
  4. A drive named CIRCUITPY appears — you're ready to copy files.
Step 04

Install Libraries

Copy these from the CircuitPython Library Bundle into the lib/ folder on CIRCUITPY:

  1. adafruit_st7789 — TFT display driver
  2. adafruit_display_text — on-screen labels
  3. adafruit_hid — USB HID keyboard emulation
CIRCUITPY/ ├── code.py ├── config.py # optional — generated by configurator └── lib/ ├── adafruit_st7789.mpy ├── adafruit_display_text/ └── adafruit_hid/
Step 05

Install Firmware Files

Download code.py from the GitHub repository and copy it to the root of CIRCUITPY. It runs automatically on every boot.

Video walkthrough

Do not rename code.py — CircuitPython runs this filename on boot. Place config.py alongside it to override defaults (see Step 6).
Step 06

Configuration (optional)

Without a config.py the device uses built-in defaults. To customise:

  1. Open the Shortcut Configurator in your browser.
  2. Select your OS and adjust shortcuts and timing as needed.
  3. Click Generate config.py then Download config.py.
  4. Copy the file to the root of CIRCUITPY — the device reloads automatically.

The import block in code.py (placed after KEYCODES / KEY_SYMBOLS):

try: from config import * except ImportError: pass # config.py missing — use defaults above
Video walkthrough available
Step 07

First Boot

Power via USB. The TFT shows the mode-select screen with three zones:

  • Left — D0 — Direct Switch Mode (Mode 0)
  • Centre — D1 / A2 — Single-switch scanning mode
  • Right — D2 / A1 — Two-switch direct mode

Press the relevant onboard button or external switch to enter a mode. To return to the mode-select screen, press the board's RESET button. In Mode 0 you can also hold an external switch for 1.5 s to exit (useful when the onboard buttons aren't reachable).

Can't reach the onboard D0 button? Double-click either external switch (A1 or A2) at the mode-select screen to jump straight into Mode 0 — Direct Switch.
Step 08

Switch Modes Reference

Single-Switch (A2)

One switch controls everything — short press to select, hold to auto-scan.

Short pressSelect & send current item
Hold (2s)Start auto-scanning
Press during scanSelect, stop scanning
D0Return to mode select

Two-Switch (A1 + A2)

Separate navigate and select switches for faster, direct control.

A1 pressAdvance to next item
A2 pressSelect & send current item
D0Return to mode select
Single-switch and two-switch modes can also be selected at startup with the external switches: A2 (select) for single-switch mode, A1 (nav) for two-switch mode. To leave any mode, press the board's RESET button (Mode 0 can also be exited by holding a switch).
Mode 0

Direct Switch Mode

Mode 0 maps each external switch directly to a single, immediate action — no scanning or navigation required. It is designed for users who need a simple, low-effort input method or who want to control mouse and media functions with their switches.

Direct Switch (Mode 0)

Each switch fires one action immediately on press. Default: Switch 1 = Enter, Switch 2 = Tab. Fully configurable in the Shortcut Configurator.

A1 tapSwitch 1 action (default: Enter)
A2 tapSwitch 2 action (default: Tab)
A1/A2 hold (1.5 s)Return to mode select
RESET buttonReturn to mode select

How to enter Mode 0

MethodHowBest for
D0Press onboard D0 button at mode-select screenInitial setup, tester access
Double-clickDouble-click either external switch (A1 or A2) at the mode-select screen within 0.4 sUsers who cannot reach onboard buttons
config.pyRun run_direct_switch_mode() as the first call in the main loopDedicated single-purpose device
Because a single external-switch click waits briefly (the double-click window, default 0.4 s) to watch for a second click, entering single- or two-switch mode via an external switch has a short deliberate delay. The onboard D1 / D2 buttons enter those modes instantly.

How to exit Mode 0

MethodHowBest for
Hold a switchHold A1 or A2 for 1.5 s — a short tap still fires the action, only a long hold exitsUsers who entered by double-click
RESETPress the board's onboard RESET buttonWhen the board is reachable

Supported action types

TypeWhat it doesExample
Keyboard keyPress (and release) any key or key comboEnter, Tab, Ctrl+C, Cmd+Space
Mouse clickLeft, right, or middle button clickLeft click for activation
Mouse scrollScroll up or down by N ticks per pressScroll down a page
Mouse moveMove pointer by X/Y pixels per pressNudge cursor right
Media controlPlay/pause, volume, track skip, mute, brightnessPlay/pause music
Customise both switch actions in the Shortcut Configurator under Mode 0 — Direct Switch Actions, then download and drop the generated config.py onto your device.
Step 09

Display (optional)

The Feather ESP32-S3 TFT has a small built-in display that shows the active shortcut, next shortcut and connection status. Users with low vision may benefit from the Display Tool as an alternative to the small onboard screen. The web app tool provides a larger, high contrast, more readable interface for displaying information and text to speech support if enabled.

Watch the walkthrough below for a live demo of the display in action.

Note: This tool is only support by Chrome or Edge browsers that support WebUSB. TTS is only supported on computers. This tool has not yet been tested on mobile devices.