Close

Firmware 0.6.0: an app launcher, BLE Gamepad and an air mouse without the cable

A project log for EvilKey: I Needed a FIDO2 Key. Then the Maker Brain Took Over.

ESP32-S3 FIDO2 prototype: touch AMOLED, microSD apps, HID scripts, USB/BLE AirMouse and an IMU BLE Gamepad. A key that got carried away.

michal-wojciechowskiMichal Wojciechowski • 10/03/2026 at 15:03•0 Comments

I needed a FIDO2 key. It acquired a screen, then an air mouse, then games. Firmware 0.6.0 is the next consequence of leaving that compiler within reach: a proper app launcher and two deliberately activated BLE controls.

The public release now contains the exact PCB V1 BIN tested on my device, its public source and checksums. The firmware and LVGL GUI are AGPLv3; the app SDK remains MIT.

The app experiments now have a front door

From Home, swipe your finger left for Apps, then left again for Settings. Swipe right from Home for the screensaver. Apps opens with an animated introduction matching Settings; up/down moves through pages of 3×3 icons with names. Tap an icon to run its package. Without compatible apps, navigation goes directly to Settings. Charger-only USB power still permits these screens.

The catalog is cached instead of doing the whole card scan on each UI transition. Packages are independent .ekapp files in /evilkey/apps/ on FAT32 microSD. Copy a file to add an app, replace it to update, remove it to remove the app. Its bounded <id>.save sits beside it, so keeping that file keeps the saved state.

Runtime remains ABI v4. The current package format is revision 5: every app carries a readable name and 64×64 RGB565 icon and follows the shared corner-exit-v1 UI profile. Older package revisions are rejected. The public specification, MIT SDK and UI profile describe the format, raw touch, motion samples, drawing/image data and saves.

Sliders should slide, not close the app

A whole-screen right swipe was too easy to confuse with an app control. The firmware now owns a small upper-left exit grip, with a visible progress strip. Start there, drag right and release after completion to open the shared Yes/No confirmation. Once captured, the gesture tolerates some downward movement and stays complete if the finger continues towards the edge. App time pauses during the gesture/dialog. Touch gestures starting elsewhere remain available to the app. SDK layouts reserve the 56×56 corner, so each app does not need to implement its own exit dialog.

A gamepad, with a useful hardware lesson

The landscape BLE Gamepad has an A/B/X/Y cross, shoulder controls, Start/Select and an IMU center action. Direction comes from tilting the key; a touch button can be used at the same time. Settings include analog/D-pad mode, dead zone, Rotate 180 and pairing controls. Its PC/Xbox and Generic/Android profiles are BLE HID; the profile name does not establish native XInput or game-console compatibility.

An important correction to the earlier ABI-v4 write-up: the interface has room for two touch contacts, but this tested FT3168 panel reports one. Repeated hardware tests did not establish multitouch. The final controls therefore use IMU steering plus one touch button, without button combinations. App authors should also design for a single contact on this board.

AirMouse: cable or BLE

AirMouse now offers USB HID or BLE. Hold MOVE to steer the cursor and release to stop. Tap DRAG to hold/release the left mouse button; with drag latched, one finger can hold MOVE to drag. Left/right click and scrolling stay on the screen. Both modules use the same dark-and-mint visual language.

The radio has an off switch in the lifecycle

BLE starts only when a BLE module is launched. Choosing a BLE preference without launching it does not turn the radio on. Leaving the module returns to FIDO with BLE off; Home, Apps, Settings, screensaver and USB roles keep it off. Mouse and the two gamepad profiles have separate BLE identities and bond stores, and Forget Pairing is limited to the selected profile.

The tested image, storage and limits

The final image was flashed through EvilKey.cmd. Application readback passed and the before/after digests of protected storage matched. Device tests covered Gamepad appearance and controls, Center/settings feedback, both orientations, AirMouse, return to USB/FIDO with existing credentials, and games with save/resume. Windows measurements established input from both BLE HID gamepad profiles and AirMouse. Android-handset testing, console/XInput compatibility and long-duration endurance remain unestablished.

Use EvilKey.cmd and the build/flash guide for checks, building and the guarded uploader. The reviewed layout supports a 4 MiB app at 0x500000; migrations preserve credential/storage offsets and verify protected partitions. This is not a full-flash erase workflow. The validation record states the accepted image identity and test scope.

Security status has not silently changed: this remains a development prototype with unencrypted credential NVS and no Secure Boot or encrypted flash/NVS provisioning. Preserving credentials during an upload is not proof of resistance to extraction or runtime compromise. Apps have no direct FIDO, NVS, USB or networking API; bounded interpreter checks are not demonstrated hardware isolation. Package hashes check corruption, not publisher identity.

Back to the question that started the app work

Firmware 0.4.0 was a big step towards extending this device without changing firmware for every new idea. That is why I asked what else people wanted it to do. ABI v4 and this launcher make that question more practical: screen-and-motion utilities, games and other experiments can be separate files on SD. New device capabilities still need considered firmware/ABI work.

The independent game source, artwork and packages remain separately licensed and are not included in these public repositories. The earlier real-device Apps Short shows falling blocks and pinball, with the launch menu used when it was filmed. What useful, odd or gloriously unnecessary app would you build with the current screen, touch, motion and save interface?

Discussions