# typechar
Type any Unicode character — or string — on macOS, regardless of your keyboard layout.
```sh
typechar €
typechar --unicode 20ac
typechar '¯\_(ツ)_/¯'
```
## 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](https://karabiner-elements.pqrs.org/) 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 — <kbd>⌥⇧2</kbd>. If a window manager like [AeroSpace](https://github.com/nikitabobko/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
```sh
brew install blaueeiner/tap/typechar
```
### Cargo
```sh
cargo install typechar
```
### From source
```sh
git clone https://github.com/blaueeiner/typechar
cd typechar
cargo install --path .
```
## 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:
```sh
typechar € # type a literal character
typechar --unicode 20ac # same thing, by codepoint (handy inside JSON configs)
typechar -u 2713 -u 2192 # ✓→ — codepoints compose in order
typechar 'Hello — World' # whole strings work; it's a snippet tool too
typechar --delay 100 € # some apps drop events that arrive mid-keystroke
typechar -- --help # everything after -- is typed literally
```
### 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 to `karabiner_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 <kbd>⌥E</kbd> to `€` (add to a rule in `~/.config/karabiner/karabiner.json`):
```json
{
"description": "Option+E types €",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "e",
"modifiers": { "mandatory": ["option"] }
},
"to": [
{ "shell_command": "/opt/homebrew/bin/typechar --delay 50 --unicode 20ac" }
]
}
]
}
```
`--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
```
## 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.
## License
[MIT](LICENSE)