ditto logo [![CI](https://img.shields.io/github/actions/workflow/status/arvingarciabtw/ditto/ci.yml?label=status)](https://github.com/arvingarciabtw/ditto/actions) [![Go](https://img.shields.io/badge/go-1.26.2-blue?logo=go)](https://go.dev) [![AUR](https://img.shields.io/aur/version/ditto?logo=archlinux)](https://aur.archlinux.org/packages/ditto) [![Release](https://img.shields.io/github/v/release/arvingarciabtw/ditto?logo=github)](https://github.com/arvingarciabtw/ditto/releases) [![Downloads](https://img.shields.io/github/downloads/arvingarciabtw/ditto/total?logo=github)](https://github.com/arvingarciabtw/ditto/releases) [![License](https://img.shields.io/badge/license-MIT-blue)](https://github.com/arvingarciabtw/ditto/blob/main/LICENSE) [![Charm in the Wild](https://img.shields.io/badge/featured-charm_in_the_wild-pink)](https://github.com/charm-and-friends/charm-in-the-wild#development-tools) ditto v1.3.0 demo Ditto is a system-wide ASCII keyboard visualizer and keycaster that mirrors your live keyboard inputs in real time, even when the terminal isn't in focus. It automatically syncs with your native terminal color scheme for seamless, interactive eye candy. If you love it, drop a ⭐ on the repo! ## Showcase
screenshot of rice with catppuccin screenshot of rice with gruvbox
screenshot of rice with everforest screenshot of rice with tokyonight
## Table of Contents - [Motivation](#motivation) - [Installation](#installation) - [Permissions](#permissions) - [Config](#config) - [Usage](#usage) - [Modes](#modes) - [Keycast](#keycast) - [Visual](#visual) - [Lists](#lists) - [Size List](#size-list) - [Layout List](#layout-list) - [Standard List](#standard-list) - [Custom Layouts](#custom-layouts) - [Lock](#lock) - [Roadmap](#roadmap) - [Contributing](#contributing) - [Stargazers](#stargazers) - [Resources](#resources) - [Note on AI](#note-on-ai) - [License](#license) ## Motivation If you've seen rices over at places like [r/unixp\*rn](https://www.reddit.com/r/unixporn/), every now and then you'll see some developer layouts where you'd have a code editor, then some eye candy to fill up dead space. I thought it would be nice to have some eye candy that was interactive. And so, I thought a keyboard visualizer that updates no matter which window has focus would be pretty neat. You code away on your editor, and the ASCII keyboard on the corner lights up! Practically, it could have a niche use as well, like sharing your screen with other people so ~~you can flex your Vim skills~~ they can see the keys you press as you navigate through your workflow. ## Installation ### Linux I recommend installing the program through Go: ```bash go install github.com/arvingarciabtw/ditto/cmd/ditto@latest ``` Or you can install the program via the AUR: ```bash yay -S ditto # or paru -S ditto ``` Or via the flake for nix users: ```nix { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; ditto = { url = "github:arvingarciabtw/ditto"; inputs.nixpkgs.follows = "nixpkgs"; }; }; # ... } ``` It's available under `ditto.packages..default`. Or download `ditto_linux_amd64.tar.gz` from the [Releases](https://github.com/arvingarciabtw/ditto/releases) page, extract, and move the binary to a directory on your `PATH`: ```bash tar xzf ditto_linux_amd64.tar.gz mv ditto_linux_amd64 ~/.local/bin/ditto ``` Before executing the program with `ditto`, refer to the [permissions](#permissions) section below. ### Windows Download `ditto_windows_amd64.zip` from the [Releases](https://github.com/arvingarciabtw/ditto/releases) page, put it somewhere convenient (e.g. `C:\Users\\bin`), and add that folder to your `PATH`. ### macOS Download `ditto_darwin_arm64.tar.gz` (Apple Silicon) or `ditto_darwin_amd64.tar.gz` (Intel) from the [Releases](https://github.com/arvingarciabtw/ditto/releases) page, extract it, rename the binary to dittokb, and move it to a directory on your PATH. > [!NOTE] > macOS support is **untested**. The keymapper is implemented and it compiles via CI, but it hasn't been verified on a physical Mac. If you try it, please report any issues! > > The binary is named dittokb rather than ditto on macOS, since ditto is already a built-in system utility. All commands below that reference ditto should be run as `dittokb` instead. ## Permissions > [!IMPORTANT] > For Linux users: > > To add support for Wayland compositors, keyboard events are captured via `evdev`. Ditto reads raw events from `/dev/input/event\*`, which isn't readable by normal users by default. You can grant the binary read access with: > > `sudo setcap cap_dac_read_search=ep "$(which ditto)"` > > The program will inform you about this when executing without permissions. > > This adds a single Linux capability to the binary, so it only bypasses the DAC read check on `/dev/input/event*`, nothing else. The binary still runs as your user, not as root. You'd need to re-run it if you rebuilt the binary. You can revoke anytime with: > > `sudo setcap -r "$(which ditto)"` > > To my knowledge, this is the safer way of granting permissions. You could technically add the user to the input group and it would work, but that'd be more unsafe since that would grant full control over all devices under `/dev/input`. > [!NOTE] > Since Nix store paths change on every rebuild, you'll need to re-run `setcap` after updating the flake input. ## Config Ditto stores its config file and custom layouts in a per-OS config directory: - **Linux:** `~/.config/ditto/` (or `$XDG_CONFIG_HOME/ditto/` if set) - **macOS:** `~/Library/Application Support/ditto/` - **Windows:** `%AppData%\ditto\` ## Usage > [!NOTE] > macOS users: substitute `dittokb` for `ditto` in all commands below. #### General | Key | Action | | ----------- | ----------------------------------------- | | `m` | Switch between default and keycast mode | | `v` | Toggle between ASCII and box draw render | | `l` | Open the layout list | | `s` | Open the size list | | `d` | Open the standard list | | `c` | Toggle kana/hangeul overlay (JIS/KS only) | | `?` | Toggle key bindings help | | `h` | Toggle info bar | | `q` / `esc` | Open quit dialog | | `ctrl+c` | Quit | #### Keycast mode | Key | Action | | --- | -------------------------------- | | `f` | Toggle finger color highlighting | #### Overlay navigation | Key | Action | | ------------ | ------------------- | | `j` / `down` | Move selection down | | `k` / `up` | Move selection up | | `enter` | Confirm selection | | `q` / `esc` | Close overlay | ### Modes There are two modes: default and keycast. Default mode is a visualizer for your keyboard with your selected layout, size, and standard. Keycast mode is ideal for practical usage, where you want to much more clearly display each pressed key, similar to existing keycasting software. #### Keycast keycast demo Ideal usage of this mode is by setting your terminal to float, and bumping up the font size to make the keys more visible. The bottom bar while in keycast mode provides the available commands: `h` for toggling the hidden state of the bar, `f` to add key colors based on finger mappings, `m` to choose between modes, and `q` to quit the program. ### Visual visual demo To alter the visual look of the keyboard and the keys shown in keycast mode, press `v` to toggle between an ASCII variant and a box draw variant. ### Lists #### Size List size list demo Press `s` to open the size list. This determines which physical key matrix the ASCII keyboard renders. Choose from compact 60% all the way up to full-size 100%.
Size Form Factor
60%Compact, no F-row or arrows
65%60% + arrow keys + nav cluster
75%Has F-row, compact layout
80%TKL — F-row, arrows, no numpad
96%Compact full-size, includes numpad
100%Full-size with everything
#### Layout List layout list demo Press `l` to open the layout list. This determines how the keys are remapped. Choose from popular layouts like QWERTY, Dvorak, Colemak, and more.
Layout Description
qwertyStandard US layout
qwerty ukStandard UK layout
qwertzGerman QWERTZ layout
dvorakDvorak simplified
dvorak ukDvorak UK layout
colemakColemak modern alternative
colemak-dhColemak with angle mod
workmanWorkman layout
azertyFrench AZERTY
#### Standard List standard list demo Press `d` to open the standard list. This determines the physical keyboard standard. Choose from ANSI, ISO, ABNT, JIS, or KS.
Standard Description
ansiAmerican National Standards Institute
isoInternational Organization for Standardization (ISO)
abntAssociação Brasileira de Normas Técnicas
jisJapanese Industrial Standard
ksKorean Standard
### Custom Layouts Custom layouts are loaded from a `layouts/` folder inside [ditto's config directory](#configuration). Each `.json` file becomes a named layout (the filename without extension). Format: ```jsonc { "map": { "A": "A", "S": "O", "D": "E", "F": "U", "G": "I", "H": "D", "J": "H", "K": "T", "L": "N", "Q": "'", "W": ",", "E": ".", // ... }, "shift": { "1": "!", "2": "@", // ... }, } ``` - **map is required** — maps physical key labels → remapped labels (same format as the built-in layouts in layouts.go) - **shift is optional** — shifted state mappings; falls back to shift mappings for qwerty us layout if omitted The layout will automatically appear in the layout list the next time you launch Ditto. ### Lock If you're happy with the current layout and want to keep that permanently every time you run the program, you can lock the keyboard with `ditto --lock`. Locking it means that your visual settings will not work. Bindings for opening up a list, toggling the TUI text with `h`, or toggling the logograms with `c` will intentionally not work. Inversely, you can just do `ditto --unlock` to unlock the keyboard. If you prefer, you can also just edit `config.json` in [ditto's config directory](#configuration) directly to change the value of the `locked` key. ## Roadmap Some features I'm thinking of implementing in the future, not in order. - [x] Physical layouts (standards) - [x] Cross-platform support - [x] Keycast mode - [x] Smoother variant with box drawing characters - [ ] Layers - [ ] Custom layouts via TUI ## Contributing I'm certainly not much of an experienced programmer, so any contributions you make are **greatly appreciated**. As I kept developing this program, I've learned that keyboards actually get pretty deep. For instance, check out this [list](https://en.wikipedia.org/wiki/List_of_QWERTY_keyboard_language_variants) of QWERTY keyboard language variants. If you'd like to add a specific layout variant to the layout list, I'd appreciate a pull request or opening up an issue about it. When writing my commit messages, I follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) spec, so I'd be glad if you followed this convention as well for your contributions for the sake of consistency. If you're liking Ditto, I'd appreciate a star! Thanks again! ⭐ ## Stargazers Huge thanks to everyone that found the project interesting! :) ditto stargazers ## Resources Here is a list of useful resources that I always refer to when developing: - [effective go](https://go.dev/doc/effective_go) - [bubble tea docs](https://pkg.go.dev/charm.land/bubbletea/v2) - [lipgloss docs](https://pkg.go.dev/charm.land/lipgloss/v2) - [evdev docs](https://pkg.go.dev/github.com/gvalkov/golang-evdev) - [input interfaces](https://www.kernel.org/doc/html/latest/input/input.html) - [setcap](https://man.archlinux.org/man/setcap.8.en) - [standards reference](https://en.wikipedia.org/wiki/Keyboard_layout#/media/File:Physical_keyboard_layouts_comparison_ANSI_ISO_KS_ABNT_JIS.png) ## Note on AI I'm not an experienced programmer and I've only recently picked up Go, so I'm well aware that the codebase is subpar. I still don't have an eye for what is considered idiomatic Go or not. I've used AI to assist me with making this project, notably for pointing me towards reliable resources like documentation and for easily doing tedious, repetitive tasks (especially so for when I was adding the key matrices for each keyboard standard's size). In the cases where I couldn't figure out an implementation despite researching on my own, I did lean into AI for suggestions, and sometimes an initial prototype of an implementation. Rest assured that I did my best in reviewing these suggestions, and making appropriate changes along the way. Of course, I'm certain the code can still be improved a lot more, so I'd be happy to hear any feedback or suggestions. If you'd like to contribute, you can refer to the [Contributing](#contributing) section above. ## License Distributed under the MIT License. See `LICENSE` for more information.