- C++ 55.7%
- C 27.3%
- JavaScript 9.5%
- Shell 4.4%
- Python 3%
- Other 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The helpers' behaviour was reconstructed from the x64 binaries, so "clean-room" was not accurate. Reword the README, build scripts and source comments, and add a License section. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
| config/hypr | ||
| extras/mic-button | ||
| helpers | ||
| patches | ||
| .gitignore | ||
| build.sh | ||
| install.sh | ||
| LICENSE | ||
| README.md | ||
| uninstall.sh | ||
typeless-omarchy
Status: shelved (2026-10-02). Typeless is not installed; Wispr Flow is the dictation app in use. Build outputs (
work/,stage/,dl/) have been removed; rebuild with the instructions below (./build.sh) if this is ever picked up again.
An unofficial arm64 Linux port of Typeless, the AI voice-dictation app, for Omarchy / Hyprland on aarch64 machines.
Typeless only ships an x64 .deb for Linux. The app is Electron, so most of it
runs anywhere once its runtime is swapped, but it loads six closed-source x64
native helpers in-process. On a 16K-page kernel (Apple silicon) x86 emulation
isn't an option, so this repo contains interoperable arm64
reimplementations of those helpers (behaviour reconstructed from the x64
binaries for interoperability), plus the scripts that turn the official
download into a working arm64 install.
No Typeless code or binaries are in this repo. build.sh downloads the official
package from Typeless's own update feed at build time (verified against the
feed's sha512) and assembles the port locally. Not affiliated with Typeless.
Quick start
./build.sh # compile helpers, download Typeless, assemble stage/Typeless
./install.sh --all # app + Hyprland rules + mic-button watcher
Then open Typeless from the launcher and sign in.
./install.sh without flags installs only the app. --hyprland adds the
window rules, --mic-button[=<source>] adds the USB-mic button watcher.
./uninstall.sh removes everything (--purge also deletes
~/.config/Typeless).
Requirements
- aarch64 Linux with Wayland (tested: Omarchy, Hyprland 0.56, PipeWire)
- Build:
base-devel,pkg-config,libpulse,libsecret,glib2,at-spi2-core,dbus,wayland,wayland-protocols,libarchive(bsdtar),curl,python3, Node.js 20+ (npx) - Runtime:
wl-clipboard,at-spi2-core, XWayland - Read access to
/dev/input/event*and write access to/dev/uinput(logind'suaccessACLs or theinputgroup)
What gets built
| Piece | Source | Notes |
|---|---|---|
| Electron runtime | electron/electron releases | Same version as upstream (detected from the .deb), fuses mirrored |
better-sqlite3 |
WiseLibs prebuilds | Matched to the Electron ABI |
koffi |
bundled in the app | Its linux_arm64 build is already in app.asar |
libKeyboardHelper.so |
helpers/keyboard-helper |
Global hotkeys from evdev |
libInputHelper.so + typeless-clipboard |
helpers/input-helper |
Text insertion: clipboard + Ctrl+V (Ctrl+Shift+V in terminals) through a uinput keyboard, clipboard restored afterwards |
libContextHelper.so |
helpers/context-helper |
Focused app (Hyprland IPC), focused element / surrounding text / URL (AT-SPI) |
libUtilHelper.so |
helpers/util-helper |
Audio devices, ducking, sounds, device id, permission checks |
libopusenc.so |
helpers/libopusenc |
libopus 1.5.2 + libopusenc 0.2.1 + the app's wrapper API |
typeless-atspi-helper |
helpers/linux-shared |
Shared out-of-process AT-SPI helper |
Each helper has its own build.sh and headless tests under test/.
patches/ edits the app bundle:
10-disable-updater.sh— the upstream feed only has x64 packages, so the in-app updater always reports "up to date". To update, run./build.sh <new-version>and./install.sh.20-force-x11.sh— the floating bar positions itself with raw Xlib calls, so the app must run under XWayland. Omarchy setsELECTRON_OZONE_PLATFORM_HINT=waylandand Typeless rewrites its own launcher entries, so the app relaunches itself once with--ozone-platform=x11(TYPELESS_ALLOW_WAYLAND=1disables this).
Differences from upstream behaviour
- Hotkeys don't grab the keyboard. Upstream takes exclusive control of every
keyboard (EVIOCGRAB) so shortcut keys don't reach apps; that breaks other
hotkey readers such as Wispr Flow. This port listens passively by default;
KEYBOARD_HELPER_NO_GRAB=0restores grabbing. - Non-keyboard buttons work. Upstream only watches full keyboards; this port
also reads media/consumer-key devices (headset buttons, remotes) and names
keys it doesn't know (e.g.
VoiceCommand,Fn). - Accessibility check asks the AT-SPI bus directly instead of going through the helper process, which deadlocks while a Typeless window has focus.
Mic mute button → dictation (extras/mic-button)
Some USB mics (e.g. the JIAYZ BY-GM18CU) have a button that toggles a
hardware mute and reports nothing to the computer: no key event, no mixer
change. A muted mic streams exact digital zeros, while a live one always has a
noise floor, so typeless-mic-button listens to the mic and taps a virtual
VoiceCommand key whenever the state flips:
- unmute (LED live) → tap → Typeless starts dictating
- mute → tap → Typeless finishes and pastes
Setup: ./install.sh --mic-button=<source> (find the source with
pactl list short sources; the default is the BY-GM18CU), then in Typeless
set the Dictate shortcut by pressing the mic button once.
The key and behaviour are set in ~/.config/typeless-mic-button.env
(restart with systemctl --user restart typeless-mic-button):
| App | MIC_BUTTON_KEY |
MIC_BUTTON_MODE |
Bind in the app |
|---|---|---|---|
| Typeless (default) | voicecommand |
tap |
Dictate → press the button once |
| Wispr Flow | f24 + MIC_BUTTON_MODIFIER=rightctrl |
hold |
Push-to-talk → unmute, then mute |
Wispr Flow only reads devices that have letter keys, has no VoiceCommand
key code and insists on a modifier, so for Wispr the watcher holds
Right Ctrl + F24 while the mic is live (push-to-talk). Its helper also only
opens input devices that exist when it starts: start Wispr after the watcher
(or restart Wispr after restarting the watcher).
- The virtual device is disabled in Hyprland (
config/hypr/typeless.lua) so the key never reaches apps; Typeless reads/dev/inputdirectly. - The watcher keeps a capture stream open, so Omarchy's bar microphone icon always shows "in use". The mic's LED is the real indicator.
- It follows the mute state, not Typeless's state: if dictation ends another way, the next mute starts one. Press the button again to resync.
Troubleshooting
- Orange border / box over the screen: the floating bar window is missing
its rules — run
./install.sh --hyprlandand restart Typeless. - App exits at start with
BadWindow: it's running on native Wayland; check thatpatches/20-force-x11.shwas applied (rebuild). - Logs: start
~/.local/opt/Typeless/typelessfrom a terminal; the helpers print to stderr. Mic watcher:journalctl --user -u typeless-mic-button.
License
MIT for the scripts and helper sources in this repository; see LICENSE. Typeless itself is proprietary, is not included, and is downloaded from its vendor at build time under its own terms. This is an unofficial project, not affiliated with or endorsed by Typeless.