tecla (Spanish) - key; teclado - keyboard
Status: Experimental. Fresh out of oven - expect weirdness.
Keyboard-oriented workflows are often far more efficient and less frustrating than similar mouse-driven techniques. The typical strategy is to use a multitude of keyboard shortcuts. Obviously, that approach is not very scalable. You start adding keyboard shortcuts for various actions - soon you will be blocked by conflicting shortcuts.
Command composability idea of Vim, although does require some initial learning and getting used to, allows you to expand your keyboard-oriented workflow with a minimal effort to memorize keys. There’s so much you can do with the home-row keys (h/j/k/l) alone.
However, that “one-dimensional” approach used in vanilla Vim/Neovim, where a single modal (Normal/Insert/Selection modes) is used, has limitations. Fortunately, the basic idea of modality can be expanded further. The Spacemacs project is an excellent example of where that was done. In Spacemacs|Doom there is a single primary “modifier” key - SPACE. To trigger an action, user is required to press a mnemonically recognizable combination e.g., SPC w m - to maximize current window.
This idea was originally explored in Spacehammer - a macOS project built on Hammerspoon. Tecla brings the same approach to Linux. Jumping between apps, controlling windows, searching, editing text fields in Emacs - everything follows simple, mnemonic semantics. It lets you keep your fingers on the home row.
Two-process design:
- tecla-bridge (C) - grabs all physical keyboards via evdev, creates a virtual keyboard via uinput. A dumb I/O pipe with no keyboard logic. Communicates over a Unix domain socket.
- tecla (Babashka/Clojure) - receives raw key events, processes remaps, runs the modal FSM, dispatches actions. All configuration and logic lives here. Includes an nREPL server for live development.
Compositor-agnostic: works on Hyprland, GNOME, Sway, and other Wayland compositors.
- Babashka (bb)
libevdev-dev(for building the bridge)wl-clipboard(wl-copy,wl-paste)- A running Emacs server (for edit-with-emacs feature)
git clone https://github.com/agzam/tecla.git
cd tecla
bb runThe bridge binary requires access to /dev/uinput and /dev/input/event*. Either run as root or add your user to the input group and set up udev rules.
All configuration lives in ~/.config/tecla/config.edn (copied from config.example.edn on first run). Plain Clojure data - EDN maps, keywords, vectors.
Config is hot-reloaded - save the file and changes take effect within a couple of seconds.
The main modal is activated by Super+Space (configurable in config.edn). From there, mnemonic key sequences invoke actions.
Mac-like keybindings on Linux - Super+C for copy, Super+V for paste, etc.:
{:global-keymap
{[:super :c] [:ctrl :c]
[:super :v] [:ctrl :v]
[:super :a] [:ctrl :a]
...}}h/j/k/l- focus windows directionallyShift + h/j/k/l- move windowsm- maximizec- close windowf- toggle floatings- pin (always on top)o- move to other monitorr- enter resize mode (transient:h/lwidth,j/kheight)
e- Emacsi- Kittyb- Braves- Slack
Uses wm/focus-or-launch - focuses the app if running, launches it otherwise.
j/k- volume down/upm- mute toggles- play/pauseh/l- previous/next track
Edit any text field on the system using Emacs. Default binding: Super+Ctrl+O.
- Tecla copies the focused field’s text (
Ctrl+CorCtrl+A, Ctrl+C) - Opens an Emacs buffer with the captured text
- Edit freely, then:
C-c C-c- paste text back to the app, close bufferC-c C-s- sync text to the app, keep editingC-c C-k- cancel, return to app without changes
Requires a running Emacs server (M-x server-start). The Elisp package (tecla.el) is auto-loaded on first invocation.
See full spec for details.
Override bindings for specific apps:
:app-local-keymap
{:kitty
{[:super :c] [:ctrl :shift :c]
[:super :v] [:ctrl :shift :v]}
:brave-browser
{[:super :l] [:ctrl :l]
[:super :j] [:ctrl :shift :tab]
[:super :k] [:ctrl :tab]}}Pattern-based matching is also supported - use strings as regex keys:
{"brave|firefox" {[:super :l] [:ctrl :l]}}A GTK4 overlay shows available keys and descriptions when you enter a modal menu. Uses gtk4-layer-shell on wlroots compositors.
Bind any key combo to a shell command:
[:super :ctrl :p] "cliphist list | wofi --dmenu | cliphist decode | wl-copy"
[:super :ctrl :5] "flameshot gui"Bind to arbitrary Clojure functions with namespace-qualified forms:
[:super :ctrl :o] (emacs/edit-with-emacs)
:e {:desc "Emacs" :action (wm/focus-or-launch {:class "Emacs"})}Short aliases: wm/ -> tecla.wm/, media/ -> tecla.media/, emacs/ -> tecla.emacs/.
Tecla runs an nREPL server (default port 7890). Connect from Emacs/CIDER and modify keymaps, test actions, or reload config at runtime:
;; From a connected REPL
(tecla.core/reload-config! (tecla.core/default-config-path))
(tecla.wm/focus-or-launch {:class "kitty"})User code can be placed in ~/.config/tecla/src/ - this directory is automatically added to the classpath.
Tecla is the Linux successor of Spacehammer, which pioneered this approach on macOS using Hammerspoon. The edit-with-emacs feature, modal menu design, and overall philosophy are directly inherited from that project.
Copyright - Ag Ibragimov. GNU General Public License