typechar
Type any Unicode character — or string — on macOS, regardless of your keyboard layout.
Why this exists
macOS keyboard layouts define which characters your keys can produce. If a character isn't on your layout, no key combination will type it. And tools like Karabiner-Elements can't help directly: Karabiner remaps key codes, not characters — whatever key it synthesizes is still interpreted through your active layout.
The concrete story behind this tool: on a US layout, € lives on exactly one combination — ⌥⇧2. If a window manager like AeroSpace or any other hotkey daemon claims that combo, the character becomes untypeable. Your options are to sacrifice the hotkey, or to bypass the layout system entirely.
typechar does the latter. It posts the character itself as a keyboard event via CoreGraphics (CGEventKeyboardSetUnicodeString), so the layout never gets a vote. Bind it to any hotkey via Karabiner, skhd, Hammerspoon, or a shell alias, and type €, ✓, →, °, or any snippet — from any layout.
Install
Homebrew
Cargo
From source
Usage
typechar [OPTIONS] <string>
typechar [OPTIONS] --unicode <hex> [--unicode <hex>...]
Options:
-u, --unicode <hex> Codepoint to type, e.g. 20ac or U+20AC (repeatable)
-d, --delay <ms> Wait before typing (for apps that drop fast events)
-h, --help Show this help
-V, --version Show version
Examples:
Permissions
The process that invokes typechar needs Accessibility permission (System Settings → Privacy & Security → Accessibility):
- run from a terminal → grant it to your terminal app
- run from a Karabiner
shell_command→ grant it tokarabiner_console_user_server - run from skhd / Hammerspoon → grant it to that daemon
If permission is missing, typechar exits with an error telling you so instead of silently typing nothing.
Karabiner-Elements example
Bind ⌥E to € (add to a rule in ~/.config/karabiner/karabiner.json):
--unicode avoids putting non-ASCII literals in JSON; --delay 50 keeps the synthetic
event from racing your still-held modifier keys.
skhd example
alt - e : /opt/homebrew/bin/typechar --delay 50 --unicode 20ac
Problems this solves
Situations where people end up here:
- "How do I type € on a US keyboard on macOS?" — natively it's ⌥⇧2,
but if a window manager or hotkey daemon has claimed that combo, the character
is untypeable.
typechar €on any free hotkey fixes it. - "Karabiner types the wrong character / can't type a Unicode character." —
Karabiner remaps key codes, which are still interpreted through your keyboard
layout. A character that isn't on your layout can't be produced by any key code.
Calling typechar from a
shell_commandsidesteps the layout entirely. - "Type em-dash / arrow / checkmark / degree sign from a keyboard shortcut." —
typechar —,typechar →,typechar ✓,typechar °, or any snippet, without switching layouts or opening the character picker. - "AeroSpace / skhd / Rectangle stole the shortcut for a special character." — tiling window managers commonly bind ⌥-combos that macOS layouts use for symbols. typechar gives every symbol a home on whatever keys are left.
Use as a library
typechar is also a Rust crate (docs.rs/typechar):
if !has_permission
type_string?;
type_string posts the text to the frontmost app, bypassing the keyboard
layout; it returns TypeError::PermissionDenied when the process lacks
Accessibility permission instead of silently doing nothing.
How it works
typechar creates a keyboard event with CGEventCreateKeyboardEvent, attaches your
string with CGEventKeyboardSetUnicodeString, and posts it to the HID event tap.
The frontmost app receives the characters directly — the keyboard layout is never
consulted. Long strings are split into 20-code-unit chunks (the API's practical
limit), never splitting a surrogate pair.