| cli | ||
| daemon | ||
| engine | ||
| packaging | ||
| protocol | ||
| scripts | ||
| ui | ||
| .gitignore | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| vietc.service | ||
| vietc.toml | ||
Viet+
Vietnamese Input Method for Linux
Zero underline • Native X11 • Backspace-Replay sync • Built in Rust
About Viet+
Viet+ is a modern Vietnamese input method for Linux that eliminates the underline hell common in other Vietnamese IMEs. Unlike traditional solutions that use pre-edit buffers with ugly underlines and duplicate text, Viet+ implements a Direct Input approach:
- No pre-edit buffer — keystrokes are instantly converted to Unicode
- No underline — clean, distraction-free typing
- No text duplication — just pure Vietnamese
- Backspace-Replay sync — engine state never desyncs from what's on screen
Features
| Feature | Description |
|---|---|
| Direct Input Engine | No pre-edit buffer, no underline, no text duplication |
| Backspace-Replay | Replays entire keystroke history through a fresh engine on every keypress — eliminates state desync |
| Telex & VNI | Both input methods fully supported |
| Flexible Diacritic Placement | Type modifiers/tone marks at end of syllable (e.g., tranaf -> trần) |
| Auto-Restore English | Hit space/ESC to undo accidental Vietnamese conversion |
| ESC Undo | Strip all tones from the current word instantly |
| Smart App Memory | Remembers Vietnamese/English per application |
| Macro Expansion | Custom shortcuts (e.g., ko -> không) |
| Focus Reset | Automatically clears engine state on focus change between apps |
| Casing Preservation | Syllable substitutions preserve your exact casing (e.g. Saa -> Sả, SAA -> SẢ) |
| CPU Priority | Pins daemon to P-cores + nice(-10) for low-latency input |
| Zero Telemetry | No keylogging, no network calls, fully FOSS |
Why Viet+?
Most Vietnamese input methods on Linux suffer from underline hell — pre-edit buffers that duplicate text, show ugly underlines, and break your flow. Viet+ takes a different approach:
Direct Input — keystrokes are instantly converted to Unicode. No pre-edit buffer. No underline. No text duplication. Just pure Vietnamese.
The Backspace-Replay pattern keeps the engine perfectly in sync: instead of tracking state incrementally (which can desync), Viet+ replays the entire keystroke history through a fresh engine on every keypress. The screen output is always recomputed from scratch.
Quick Start
# Clone and build
git clone https://git.khoavo.myds.me/vndangkhoa/vietc.git
cd vietc
make build-all
# Test the engine interactively
cargo run --bin vietc-cli
# Run the daemon
cargo run --bin vietc
# Or download a package from the releases page
# AppImage: ./Viet+-0.1.0-x86_64.AppImage
# Debian: sudo dpkg -i vietc_0.1.0-1_amd64.deb
Input Methods
Telex
| Key | Result | Example |
|---|---|---|
aa |
â | tan -> tân |
aw |
ă | tan -> tăn |
ee |
ê | men -> mên |
oo |
ô | to -> tô |
ow |
ơ | to -> tơ |
uw |
ư | tu -> tư |
s |
á (sắc) | as -> á |
f |
à (huyền) | af -> à |
r |
ả (hỏi) | ar -> ả |
x |
ã (ngã) | ax -> ã |
j |
ạ (nặng) | aj -> ạ |
dd |
đ | dd -> đ |
VNI
| Key | Result |
|---|---|
a1 |
á |
a2 |
à |
a3 |
ả |
a4 |
ã |
a5 |
ạ |
a6 |
â |
a8 |
ă |
e6 |
ê |
o6 |
ô |
o7 |
ơ |
u7 |
ư |
Configuration
Config file: ~/.config/vietc/config.toml or ./vietc.toml
input_method = "vni"
toggle_key = "space"
start_enabled = false
grab = true
[auto_restore]
enabled = true
trigger_keys = ["space", "escape"]
[app_state]
enabled = true
english_apps = ["code", "vim", "kitty", "foot"]
vietnamese_apps = ["telegram", "discord", "firefox"]
[macros]
ko = "không"
dc = "được"
vs = "với"
lm = "làm"
Architecture
┌──────────────────┐ ┌──────────────────┐ ┌────────────────┐
│ X11 Keyboard │────▶│ Viet+ Daemon │────▶│ X11/XTEST │
│ Grab (XGrabKb) │ │ │ │ Injection │
│ │ │ Backspace-Replay│ │ │
│ FocusIn/Out │ │ Engine │ │ Direct │
│ Detection │ │ (Telex/VNI) │ │ Clipboard │
└──────────────────┘ └──────────────────┘ └────────────────┘
│
┌─────┴─────┐
│ App State │
│ Manager │
└───────────┘
How Backspace-Replay Works
- All keystrokes in the current word are stored in
keystroke_history - On each keypress, a fresh engine is created and the entire history is replayed through it
- The engine's buffer IS what should be on screen
- Viet+ calculates the diff: backspaces to erase old text + new text to type
- On flush (space/period/etc.), history is cleared for the next word
This eliminates the state desync bugs that plague incremental engines.
Installation
Debian/Ubuntu Package
sudo dpkg -i vietc_0.1.0-1_amd64.deb
Recommends: libxtst6, xclip (for clipboard injection)
AppImage
./Viet+-0.1.0-x86_64.AppImage
No special permissions needed on X11 — uses XGrabKeyboard + XTest injection.
Manual Install
make build-all
sudo make install
Building
# Build all backends (X11 + Wayland)
make build-all
# Run tests (255+ tests)
make test
# Run interactive test harness
cargo run --bin vietc-cli
# Build packages
make deb # .deb package
make appimage # AppImage
Project Structure
vietc/
├── engine/ # Core IME engine (Telex + VNI)
│ ├── src/
│ │ ├── engine.rs # Main engine + replay_keystrokes()
│ │ ├── telex.rs # Telex state machine
│ │ ├── vni.rs # VNI engine
│ │ ├── english.rs # English auto-restore dictionary
│ │ └── tests/ # 255+ unit tests
│ └── Cargo.toml
├── protocol/ # Injection backends
│ ├── src/
│ │ ├── inject.rs # KeyInjector trait
│ │ ├── x11_capture.rs # X11 keyboard capture (XGrabKeyboard)
│ │ ├── x11_inject.rs # Direct X11 clipboard + XTest injection
│ │ └── wayland_im.rs # Wayland IM protocol
│ └── Cargo.toml
├── daemon/ # Background daemon
│ ├── src/
│ │ ├── main.rs # Event loop, Backspace-Replay integration
│ │ ├── config.rs # TOML config loader
│ │ ├── app_state.rs # Per-app state manager
│ │ └── display.rs # Display server detection
│ └── Cargo.toml
├── cli/ # Interactive test harness
├── ui/ # Tray icon application
├── packaging/ # Distribution packages
│ ├── appimage/ # AppImage build scripts
│ └── deb/ # .deb package build scripts
├── vietc.toml # Default configuration
├── vietc.service # Systemd user service
├── Makefile # Build targets
└── README.md
Changelog
See CHANGELOG.md for release history.
License
MIT License - see LICENSE for details.
Made with love for the Vietnamese Linux community