Linux edition — this page is an offline copy generated automatically from the Markdown in docs/user/. If anything looks out of date or a link is broken, see the latest version in the GitHub docs.
UNIM 0.4.0 — Universal Next-generation Input Method A Rust-based input method engine for fluid Korean/English typing. Goal of this document: get a first-time user to type one Korean syllable within five minutes.
Acronyms expanded: IM Module (Input Method Module) — toolkit-specific adapter (one per GTK/Qt/etc) that lets an app delegate keystrokes to the IME. DBus (Desktop Bus) — the Linux desktop's inter-process communication bus; UNIM uses it to talk between the daemon and the frontends. XIM (X Input Method) — the oldest IME protocol, dating back to X11. Wayland — modern display protocol; IM handling differs from X11.
🐧 Linux — supported: Ubuntu 24.04 (noble) or newer / equivalent Debian, amd64. The release
.debs are built on noble.
A single line downloads every UNIM .deb from GitHub Releases and installs them via apt. Every .deb is SHA256-verified, isolated in a mktemp working directory, and external runtime dependencies are resolved automatically. On any checksum mismatch it aborts without installing anything (no partial install).
curl -fsSL https://raw.githubusercontent.com/from104/unim/main/install.sh | bash
To pin a specific version:
UNIM_VERSION=v0.4.0 curl -fsSL https://raw.githubusercontent.com/from104/unim/main/install.sh | bash
If you don't trust curl | bash, download the script first, read it, then run it:
curl -fsSL https://raw.githubusercontent.com/from104/unim/main/install.sh -o install.sh
less install.sh && bash install.sh
Grab every unim*_<version>-1_{amd64,all}.deb plus SHA256SUMS from Releases into the same directory, verify, and install.
# Verify checksums (e.g. 0.4.0-1 — 11 packages)
sha256sum -c SHA256SUMS
# Install (apt resolves dependencies automatically)
sudo apt install ./unim*.deb
# Remove IBus (avoids conflict on GNOME)
sudo apt remove ibus
# Register UNIM as the system IME (Debian/Ubuntu standard tool)
im-config -n unim
Log out and back in once so the new environment variables propagate to your shell.
git clone https://github.com/from104/unim.git
cd unim
make build # Builds Rust workspace + GTK3/4 + Qt5/6 IM modules in one shot
sudo make install PREFIX=/usr
sudo make install-systemd PREFIX=/usr
systemctl --user daemon-reload
systemctl --user enable --now unim-daemon.service
Source builds need cargo 1.95+, GTK4/libadwaita headers, and Qt5/Qt6 dev packages. Package names vary by distro; see troubleshooting/build-failure.
For KDE Plasma, XFCE, Sway, Hyprland, etc., add three lines to ~/.xprofile or /etc/environment:
export GTK_IM_MODULE=unim
export QT_IM_MODULE=unim
export XMODIFIERS="@im=unim"
Log out and back in. On Debian-family distros, im-config -n unim does the same in one command.
On GNOME Shell, the unim-gnome-extension is responsible for key interception and popup rendering. You enable the extension instead of setting environment variables.
gnome-extensions enable unim-gnome@from104.github.io
Disable or remove IBus to avoid conflicts:
sudo apt remove ibus
Shift+Space, depending on your keyboard) — the tray icon switches to "한".dkssud → "안녕" appears.安寧 candidates appears. Pick with digits 1–9.If all five steps work, you are done. If not, head to troubleshooting.
🐧 Linux — since UNIM 0.3.0, hanja, special-character, and emoji popups are rendered by a single service: unim-popup-service.
| Environment | Popup renderer | Notes |
|---|---|---|
| GNOME Wayland | GNOME Extension popup_view.js (St widget) | Mutter does not support wlr-layer-shell; extension renders directly |
| GNOME X11 / KDE / Xfce / X11 WM | unim-popup-service GTK4 window | Auto-launched via D-Bus activation |
| Wayland (KDE Plasma 6 / Sway / Hyprland) | unim-popup-service GTK4 window (wayland-backend) | Requires libgtk4-layer-shell |
Single source of truth: regardless of environment, the daemon's PopupRender payload (cells, header, footer, tabs, highlight) is the single view-model delivered to all renderers. Only the rendering implementation differs.
Outside-click dismiss: clicking outside the popup closes it, and the click event is passed through to the window below. If a popup closes unexpectedly, this is intended behavior — see troubleshooting.
KDE Plasma 5.x Wayland — unsupported: gtk4-layer-shell is not available in the Ubuntu 24.04 standard repository, so popups do not appear. Workaround: use an X11 session or switch to GNOME.
KDE Plasma 6 Wayland / Sway / Hyprland / river — experimental, undertested: builds with the wayland-backend cargo feature and libgtk4-layer-shell installed are theoretically functional, but this experimental status has not changed since the 0.3.0 QA cycle — no additional verification was done for v0.4.0. Expect possible regressions in popup placement, IME focus handover, and layer-shell coordinate translation. For the full per-environment support matrix, see troubleshooting §G environment matrix.
🐧 Linux — which path UNIM takes depends on your desktop environment and the app's toolkit.
| Environment | Install method | IM module | Popup owner | Watch out for |
|---|---|---|---|---|
| X11 + GTK apps | GTK_IM_MODULE=unim | gtk3/gtk4 IM module | unim-popup-service (GTK4, D-Bus auto-activation) | — |
| X11 + Qt apps | QT_IM_MODULE=unim | qt5/qt6 IM plugin | Same | On Plasma, prefer Qt mode |
| X11 + legacy (Emacs, xterm) | XMODIFIERS=@im=unim | xim frontend | XIM's own Xft popup | over-the-spot mode |
| GNOME + Wayland | Enable GNOME extension | (apps speak text-input-v3 directly) | GNOME Extension | IBus removal mandatory |
| KDE + Wayland | QT_IM_MODULE=unim + Wayland frontend | wayland | unim-popup-service (wayland-backend) | input-method-v2 |
| Sway/Hyprland (Wayland) | env vars + Wayland frontend | wayland | unim-popup-service (wayland-backend) | Compositor must support input-method-v2 |
Detect your environment:
echo $XDG_SESSION_TYPE(x11/wayland),echo $XDG_CURRENT_DESKTOP(GNOME/KDE/sway).
On GNOME+Wayland, Flatpak/Snap apps (Telegram, VS Code) have no UNIM IM module inside their sandbox. The host's GTK_IM_MODULE=unim actually blocks input.
Automatic handling: when unim-daemon detects GNOME+Wayland, it sets a Flatpak global override at startup that empties the IM environment variables, so Flatpak apps fall back to the Wayland text-input-v3 → GNOME Extension path.
Manual override (if the auto setup did not run):
flatpak override --user --env=QT_IM_MODULE= --env=GTK_IM_MODULE=
Snap has no global override mechanism. Add a conditional snippet to ~/.profile that empties the IM vars on GNOME+Wayland — see README §1.7.
| Key | Action | Note |
|---|---|---|
| Hangul key | Toggle mode | Key code varies by keyboard |
Shift+Space | Toggle (fallback) | Works on any keyboard |
| Right Alt (RightAlt) | Toggle mode (when added to toggle_keys) | Now works on every environment, including GTK/Qt/GNOME |
| Tray icon click | Toggle (mouse) | unim-indicator lives in the tray |
Mode share (
mode_sharingsetting, CLI keymode-sharing): "Global" or "Per-app". Global is the default — switching mode in one window instantly syncs every window. Switch to "Per-app" if you want your terminal to stay in English while your text editor stays in Korean.
Accessibility — turn on the toggle beep if you type without watching the screen: Linux has no screen-reader announcement for mode switches, and the toggle beep itself defaults to off (a deliberate choice to avoid false positives). If you type without watching the screen, we recommend turning it on:
unim-cli config set toggle-announce-beep trueOn and off are announced with different pitches.
Note: this beep can go silent depending on the mode-share setting. The beep that fires from a tray-icon or GNOME-extension mode change only plays in "Global" mode (
unim-dbus/src/engine_worker.rs:1766-1772). Switch to "Per-app" and a tray toggle no longer actually changes the focused window's mode (by design — it avoids sending a false signal), so this beep path goes silent. If you rely on the beep to confirm a language switch, be aware that switching to "Per-app" costs you this signal from tray/extension interactions.
Toggling with Right Alt: Add
RightAltto thetoggle_keyssetting to switch Korean/English with the right Alt key. GTK, Qt, and the GNOME extension used to filter Right Alt themselves, so it did nothing there (XIM and pure Wayland already worked); the toggle decision is now unified in the daemon, so it behaves the same everywhere. AltGr layouts (right Alt used as AltGr) are unaffected. Note that at the moment of toggling the application may also receive the Alt input (e.g. menu-bar focus in some apps); if you don't want that side effect, removeRightAltfromtoggle_keys.
Key-name spelling:
toggle_keystakes key names UNIM knows, one name per entry (defaults:Korean,RightAlt). Unlike the AutoTypeFix hotkeys (§4.4), the toggle key does not accept modifier combinations (Ctrl+X). The CLI and the settings app warn about names they cannot parse when saving, and the daemon logs the parse failure — the value is still stored, but the dead key no longer disappears silently.
한국).韓國, 漢國, …. (period) to toggle to a 9×9=81-cell expanded grid. The ⊞/⊟ icon in the corner reflects the current mode.Choosing the Hanja key:
hanja_keysdefaults toHanja,F9. Like the toggle key (§4.1) it takes single key names only — no modifier combinations. The CLI and the settings app warn about names they cannot parse when saving, and the daemon logs the parse failure.
When candidates exceed one page (9 cells or 81 cells), the footer shows ◀ / ▶ buttons.
[◀] page 2 / 5 [▶] ⊞
← / Page Up : previous page, → / Page Down : next page. Same wrap-around.Acronym: cursor here means the highlighted cell currently holding keyboard focus (rendered as a background highlight).
The ◀ / ▶ page buttons behave identically across every frontend, but right-clicking on the grid body itself carries different meaning depending on the frontend you are using. If you want to use it as a mouse shortcut, learn your environment's mapping; otherwise stick to the keyboard shortcuts which are uniform.
→ / Page Down.unim-popup-service Standalone, raw Wayland): no action (undefined).Why is GNOME different? GNOME Shell exposes each candidate cell as a
Clutter.Actor, so per-cell right-click hit-testing is natural — mapping right-click to the bookmark toggle saves a hand move. GTK/Qt IM modules and XIM run in X11/Wayland override-redirect windows where per-cell hit-testing is more limited, so they keep the classical IME convention of right-click = next page.In short: ◀ / ▶, keyboard
←/→, and Space mean the same thing everywhere. Only the right-click on the grid body varies. If in doubt, the keyboard alone covers every action.
You can star frequently used Hanja. With a candidate focused, Space toggles ☆ (unbookmarked) ↔ ★ (bookmarked).
The HanjaCandidatesReordered DBus signal refreshes every open popup across GTK/Qt/XIM/Wayland/GNOME/Windows instantly.
When you toggle, the candidate list reorders and the cursor follows the affected hanja:
#f9e2af for 140 ms so you immediately notice "I unstarred this and it landed here".Why is there flash on un-bookmark but not on bookmark? Bookmarking always lands on page 1 row 1, which is a predictable, eye-catching location — no extra hint needed. Un-bookmarking can jump to any page, so the flash is what tells you where the candidate went.
In Korean mode, type a single jamo (consonant) and then press the Hanja key. The category depends on the consonant.
| Jamo | Category | Examples |
|---|---|---|
| ㄱ | Symbols | !, @, ÷, ≠, ∞ |
| ㄴ | Brackets | 「」, 『』, ≪≫ |
| ㄷ | Math | ∂, ∇, √, ∫ |
| ㄹ | Units | $, %, ℃, Å |
| ㅁ | Shapes | ■, □, ●, ○ |
| ㅂ | Lines | ─, │, ┌, ┐ |
| ㅅ | Hangul jamo | ㄱ, ㄴ, ㅏ |
| ㅇ | Circled | ①, ⓐ |
| ㅈ | Parenthesized Hangul | ㈀, ㈁ |
| ㅊ/ㅋ | Parenthesized digits | ⑴, ⑵ |
| ㅌ | Parenthesized letters | ⒜, ⒝ |
| ㅍ | Greek | Α, β, γ |
| ㅎ | Misc | ●, ♨, ☏ |
Example: type ㅁ, press Hanja, pick 2 from the shapes grid → □ is committed.
Auto-recovers text typed in the wrong mode. Two directions:
gksrmf came out — replaced with 한글 at word boundaries (space/punctuation).ㅈㅐㅍㅁ becomes wave.When a particular word keeps getting corrected against your wishes:
BackSpace to undo the correction and switch modes — UNIM marks the word as "Pending".Storage: ~/.config/unim/typefix-blacklist.yaml. The daemon hot-reloads on mtime change.
User dictionary (reverse whitelist) — new in 0.2.0. Select text and use a shortcut to call the
RegisterUserDictFromSelectionDBus method, registering an English-side entry. Manage entries in the GUI's "User Dictionary" page.
A shortcut can turn AutoTypeFix on or off instantly. The master toggle defaults to Shift+F8; the forward- and reverse-only shortcuts are empty (assign them only if you want them). Three of them, set separately:
Set them from the CLI:
# The default (master toggle = Shift+F8)
unim-cli config set auto-typefix-toggle-keys "Shift+F8"
# Forward / reverse on F10 and F11 respectively
unim-cli config set auto-typefix-forward-toggle-keys F10
unim-cli config set auto-typefix-reverse-toggle-keys F11
# Multiple keys, comma-separated (any of them toggles)
unim-cli config set auto-typefix-toggle-keys "Shift+F8,Ctrl+Left"
# Clear — an empty value consumes no key
unim-cli config set auto-typefix-toggle-keys ""
In the GTK settings GUI the three fields are not grouped together but distributed across each feature group — the Master toggle sits in the "Type Correction" master group (next to the overall on/off switch), the Forward toggle in the "Forward" group, and the Reverse toggle in the "Reverse" group. Type a key name into each field; leave one empty to disable it.
In the Slint settings app (unim-settings, including Windows) the three fields are gathered side by side in the "Toggle hotkeys" group on the Type Correction page (5.2).
- Modifier combinations are supported — write them as
Shift+F8,Ctrl+Left,Ctrl+Shift+F7(Ctrl/Control,Alt,Super/Win/Meta,Shift; case- and order-insensitive). A bare name likeF10fires on that key alone, as before.+is the canonical separator; when a spec contains no+at all,-is accepted too (Ctrl-F8=Ctrl+F8). Mixing them (Ctrl+Shift-F8) is invalid.- It fires only on an exact modifier match. Combinations you did not configure (e.g.
Shift+F10for the context menu) are not intercepted and reach the application unchanged.- The default is
Shift+F8— F9–F11 are avoided because some keyboards lose them to media functions or remapping (cut/copy/paste) before they reach the OS. It does not clash with the hanja/emoji key (bareF9), and an F9 combo likeShift+F9leaves the bare-F9popup intact.- Key names must be ones UNIM knows, such as
F1–F12(ScrollLock,Pause,PrintScreen, andMenuare not recognized). The CLI and the settings app warn about names they cannot parse when saving, and the daemon logs the parse failure — nothing is dropped silently.- Clear the list (
"") to disable a shortcut; it then consumes no key.- On GNOME (Wayland), Ctrl/Alt/Super combinations such as
Ctrl+Leftwork too — the UNIM extension forwards toggle combos to the engine (re-login after updating the extension).- On Windows (TSF), combination specs behave exactly as on Linux — the default
Shift+F8works as-is.- Toggling only forward on while the master switch is off flips the flag but produces no correction until the master switch is on again (the master gates everything). The forward/reverse toggles change only each direction's flag.
- Accessibility note: with
toggle-announce-beepenabled, this toggle also announces its state with a differential beep (rising pitch = on / falling pitch = off), just like the Korean/English switch sound — on both Windows and Linux (on Linux the daemon plays the tone via whichever ofpaplay/pw-cat/aplayit finds on PATH; if none exist, it's a silent no-op). Default is off — see the accessibility note in 4.1.
In password and PIN fields, AutoTypeFix turns off automatically. When the app reports "this field is a password" (content_purpose), UNIM stops both forward and reverse correction while you are in that field, and also clears any keystroke-observation buffer and undo history already accumulated. This keeps a password typed like dkssud from being auto-corrected into Korean and corrupted.
Opt-in feature for vim command mode (Esc), CLI slash commands (/), etc. Off by default.
Escape, Slash. Add virtual names like ShiftSemicolon (:) or ShiftSlash (?) if you need them.If your toggle key collides with a trigger key, the toggle wins (its branch comes first in
press_key). Password fields are unaffected (they force English already).
Trigger spelling: write triggers as
key:<key name>orchar:<character>(e.g.key:Escape,char:/). The older prefix-less form (Escape) is still recognized, and modifier combinations such askey:Ctrl+Bare allowed. The CLI and the settings app warn about specs they cannot parse when saving, and the daemon logs the parse failure — nothing is dropped silently.
By default, UNIM commits per syllable — a syllable is finalized as soon as it is complete. Set this to word unit instead and composition accumulates as underlined preedit through a word boundary (space, punctuation) before committing all at once. BackSpace during composition still steps back one jamo at a time, and this meshes more naturally with AutoTypeFix's reverse correction (4.4).
There are three values.
word-mode-apps, syllable-unit everywhere else. The default list is just winword.exe (Windows), so on Linux, with nothing added, this is effectively syllable-unit with no regression.This does not apply to English input — by design. The commit unit governs Hangul composition only. So when you mix the two, only the Hangul stretches are underlined and English commits the moment you type it. Uneven underlining is that, not a broken setting.
The underline under Hangul shows a composition in progress —
ㅎ+ㅏ+ㄴbecoming한. English has nothing to compose, since one key is already one letter, and so nothing to show. Underlining English too would make the application treat those letters as "not yet committed", which stops autocomplete, spell check, and live search, and breaks single-letter shortcuts (keys likejortin browsers and editors). It costs a lot and gains nothing, so it is not done.
Turning it on
# Global word-unit
unim-cli config set commit-unit word
# Smart + specific apps only (e.g. LibreOffice)
unim-cli config set commit-unit smart
unim-cli config set word-mode-apps "winword.exe,soffice"
In the settings GUI, pick it from the Korean commit unit combo under General → Layout options. word-mode-apps is edited via CLI/config.yaml (exact match, case-insensitive). Example Linux app ID: LibreOffice is soffice — app IDs can be checked in the log when Mode share is set to Per-app.
When it doesn't apply (safety net)
In word-unit mode, AutoTypeFix's reverse correction (Korean→English) only replaces the composition — it never touches already-committed text. In all of the excluded cases above, UNIM automatically falls back to syllable-unit, so it's safe to leave word-unit turned on without worrying about data loss.
unim-settings (Slint, a single codebase shared by Linux and Windows) is the one entry point for settings. That means the four pages below are identical on both operating systems — only the way you open the window differs.
🐧 Opening it on Linux — the "UNIM Settings" app-menu item, the first-run wizard, and the tray menu all launch this same executable. You can also start it from a terminal.
unim-settings &
About the legacy GTK dialog (
unim-settings-gtk): the old GTK4+libadwaita settings window is still shipped in the package, but it is no longer exposed in the app menu (NoDisplay=truein its.desktopfile). You can still launch it directly withunim-settings-gtk &, but new settings may not be reflected there — treatunim-settingsabove as the source of truth. The Qt dialog (unim-gui-qt) has already been retired; the tray icon is now owned byunim-indicator, and the hanja/special-char/emoji popups are owned byunim-popup-service, each running as its own process (see §2.5).
Four pages (left-hand navigation):
| Group | Widget | Note |
|---|---|---|
| Layout options | Korean layout / English layout | e.g. ko_2bulstd (Dubeolsik standard) — see §7.1. Layout-specific dynamic options (e.g. Sebeolsik 390's "sun-arae batchim") also appear here |
| Korean commit unit | Syllable / Word / Smart — see 4.6 | |
| Input mode | Initial mode | Korean or English when the daemon starts |
| Mode share | Global (default) / Per-app — see 4.1 | |
| Per-app rules | Add rules so specific apps (matched by window/client-name substring) always start in a given mode. Most useful when Mode share = Per-app | |
| Auto-English-Mode | Enable switch + trigger keys | Off by default — see 4.5 |
| Accessibility | One-click presets ("One-hand use" / "Relaxed timing") + individual switches | See below |
Accessibility presets: "One-hand use" applies the Sebeolsik-noshift layout + a non-modifier toggle key + moachigi off + auto-repeat suppression, all at once. "Relaxed timing" applies auto-repeat suppression + a wider typo-correction detection window + (on layouts that support it) a wider moachigi chord window. Either preset can still be fine-tuned afterward with the individual switches.
Suppress Composition Key Auto-repeat (accessibility): When you hold a key down, the OS re-fires it rapidly (auto-repeat); enabling this option makes the daemon ignore those repeats. It is meant for users with motor disabilities who tend to hold keys too long (e.g. tremor), and it is now enforced by the daemon on both Windows and Linux (Linux enforcement was previously missing; fixed in v0.4.0). Suppression applies to the Korean/English toggle key and character keys in Korean mode; repeats of editing keys (Backspace, arrows) and direct English typing are left alone. Wayland, Qt5/6, and the GNOME extension detect repeats precisely; the GTK3/4, XIM, and ibus-compatible paths approximate with an 80 ms time window, so the first repeat may slip through and, if your system key-repeat interval is set longer than 80 ms, repeats may not be filtered (in either case it errs toward suppressing less, fail-safe). The default is off; you can also enable it with
unim-cli config set ignore-key-repeat true. GNOME extension users: applies after re-login.Emoji input has no separate switch — it shares the hanja-popup path and is always on; call it with
Super+.(or whatever shortcut you registered) — see the keyboard shortcuts guide.GNOME-extension-only settings (whether the panel indicator is shown, the manual conversion shortcuts, etc.) live in
gnome-extensions prefs unim-gnome@from104.github.io, not in this app — see the keyboard shortcuts guide's GNOME section.
| Group | Widget | Note |
|---|---|---|
| Enable | Enable AutoTypeFix | Master switch. OFF stops both forward and reverse |
| Correction strength | Conservative / Standard / Aggressive presets | Tunes thresholds, minimum word length, and detection window all at once. The "Advanced settings" section below still lets you fine-tune individual values |
| Direction | Enable forward / Enable reverse | Each can be toggled independently — see 4.4 |
| Toggle hotkeys | Master on/off, Forward on/off, Reverse on/off (three fields, one group) | Toggle instantly with the assigned key. Leave empty to disable. Modifier combos like Shift+F9 are allowed — see 4.4 |
| Advanced settings (collapsible) | Korean-syllable threshold / English minimum word length / forward & reverse detection windows (ms) / Tentative expiry (hours) / Observation timeout (sec) — all sliders | The "Correction strength" presets above cover most cases |
| Options (inside Advanced) | Skip English words / Skip complete syllables / Rollback detection / User-dictionary only | — |
| — | Restore defaults | Resets AutoTypeFix settings to their initial values (undo within 5 seconds) |
A single list shows Tentative, Confirmed, and Inactive suppressions together (distinguished by a status badge, unlike the old GTK dialog's three separate sections). Select an entry and choose Confirm (promotes to Confirmed) or Delete; Clear all empties the whole list (undo within 5 seconds).
Even if the daemon updates the file, the GUI refreshes immediately. No manual reload needed.
Enter a word and an optional note, then Add, to register an English ↔ Korean-jamo-sequence mapping. E.g. wave ↔ ㅈㅐㅍㅁ. Select an entry below and Delete to remove it. Reverse correction prefers user-dict entries.
Separate from the settings GUI, two GTK4 companion tools ship with UNIM for viewing, editing,
and practicing layouts. Each registers in the app list with its own icon
(io.github.from104.unim.KeymapStudio, io.github.from104.unim.TypingPractice).
unim-keymap-studio & # view / edit layouts
unim-typing-practice & # typing practice
See which jamo/characters each key produces for Korean/English layouts, and build your own.
my_3bul_variant.~/.config/unim/layouts/, which the daemon auto-scans so it shows up in the settings GUI's
layout list.
If you edit one of those JSON files by hand, the daemon picks the change up the next time the
settings file is saved (any setting) or at the next login — it does not watch the layout files themselves.| Key | Action |
|---|---|
| F1 | Help |
| Ctrl + N | New layout |
| Ctrl + D | Duplicate current layout |
| Ctrl + S | Save (user layouts) |
| Ctrl + Shift + S | Save As |
| Ctrl + E | Export |
| Ctrl + I | Import |
| Ctrl + 1 / 2 / 3 / 4 | Switch tab (Basic / Keymap / Combos / Extended) |
Practice typing with the currently active layout (the one the daemon uses). It auto-reloads when you switch layouts.
| Key | Action |
|---|---|
| F1 | Help |
| Ctrl + R | Restart |
| Ctrl + Shift + C | Copy results |
| Ctrl + 1 | Practice view |
| Ctrl + 2 | Results view |
| Ctrl + O | Import material from file |
| Ctrl + Shift + V | Import material from clipboard |
🐧 Linux
| Situation | Key | Result |
|---|---|---|
| Anywhere | Hangul (or Shift+Space) | Toggle mode |
| Korean mode, after typed jamos | Hanja (F9) | Hanja popup |
| Hanja popup | 1–9 | Direct select |
| Hanja popup | Arrows | Move focus |
| Hanja popup | ←/→ or PageUp/PageDown | Page navigation (wrap-around) |
| Hanja popup | Mouse ◀ / ▶ | Page navigation (wrap-around, hidden on single page) |
| Hanja popup | Mouse right-click | Frontend-specific: GNOME = toggle ★ bookmark / GTK·Qt IM·XIM = next page / others = no action (see §4.2) |
| Hanja popup | Enter | Commit focused |
| Hanja popup | ESC | Cancel |
| Hanja popup | . | 9 ↔ 81 grid toggle |
| Hanja popup | Space | Bookmark ☆/★ (un-bookmark flashes destination cell 140 ms) |
| Korean mode, lone consonant | Hanja (F9) | Special-char popup |
| Composing | BackSpace | Delete last jamo |
| After unwanted forward correction | BS + Hangul | Trigger Tentative learning |
| With Auto-English on | Esc or / | Force English + pass key |
unim-cli)Two purposes: (1) Korean↔English conversion filter, (2) settings management.
echo "dkssudgktpdy" | unim-cli # English → Korean (default)
echo "안녕하세요" | unim-cli -d # Korean → English
echo "ekswn" | unim-cli -k 2bul # Dubeolsik (default)
echo "j;ax" | unim-cli -k 390 # Sebeolsik 390
unim-cli -o out.txt input.txt # File I/O
Supported layouts:
2bul, 390, 391, noshiftqwerty, dvorak, colemak, colemak_dh, workman# Show the full current config (or grep for a specific key)
unim-cli config show
# Set a value — key names take kebab-case (hyphens) only
unim-cli config set auto-typefix true
unim-cli config set auto-typefix-tentative-expiry-hours 6
unim-cli config set auto-english true
# Korean commit unit (syllable/word/smart) — see 4.6
unim-cli config set commit-unit word
# AutoTypeFix toggle hotkeys (comma-separated; modifier combos allowed) — see 4.4
unim-cli config set auto-typefix-toggle-keys "Shift+F8"
unim-cli config set auto-typefix-forward-toggle-keys F10
unim-cli config set auto-typefix-reverse-toggle-keys F11
# Layout profile management
unim-cli config layout list # built-in + user profiles
unim-cli config layout describe ko_3bul390 # profile details
unim-cli config layout validate my.json # validate a custom layout
Setting changes apply to the daemon immediately. config.yaml ↔
unim-cli↔ the settings GUI (unim-settings) are kept in sync at all three points by design.
| File | Purpose | Back up? |
|---|---|---|
~/.config/unim/config.yaml | General settings | YES |
~/.config/unim/typefix-blacklist.yaml | Learned suppressions | YES |
~/.config/unim/typefix-userdict.yaml | Reverse user dict | YES |
~/.config/unim/layouts/*.json | Custom v1 layouts | YES |
~/.unim-errors.log | Debug log (UNIM_DEVELOP=1) | NO |
tar -czf unim-backup-$(date +%F).tar.gz -C ~/.config unim
tar -xzf unim-backup-2026-04-26.tar.gz -C ~/.config
systemctl --user restart unim-daemon
CONTRIBUTING.mdIME_BEHAVIOR.md, POPUP_SPEC.mdDoc version: 0.4.0 / 2026-08-01 / License: same as the project.
▲ Back to contents🐧 Linux
UNIM shortcuts are captured by different actors depending on your desktop / compositor environment. This document explains how to enable them on each environment.
Korean original:
README-ko.md
On GNOME Shell (unim-gnome-extension), the three shortcuts below are on by default with no setup required. No other desktop/compositor (KDE, Sway, Hyprland, etc.) has them — this is a GNOME-only feature, registered directly with the Shell via Main.wm.addKeybinding by the GNOME extension.
| Shortcut | Action | Example |
|---|---|---|
Super+K | Convert the focused word English → Korean and replace it | gksrmf → 한글 |
Shift+Super+K | Convert the focused word Korean → English and replace it | ㅗ디ㅣㅐ → hello |
Super+E | Read the selection and register it in the reverse (Korean→English) AutoTypeFix user dictionary | select ㅎㅑㅅ → registered as git |
These three are distinct from the automatic correction in 4.4 AutoTypeFix — they are manual conversions the user triggers directly. If you use Super combos for something else, or hit a conflict, open the extension's preferences to rebind or disable them:
gnome-extensions prefs unim-gnome@from104.github.io
Rebind or clear Super+K / Shift+Super+K in the "Conversion shortcuts" group, and Super+E in the "Register user dictionary" group.
Super+.)UNIM can pop up an emoji picker at the last active input location. The default shortcut is Super+. (Meta+.). However, who captures the shortcut differs per environment, so on some setups you must register it yourself.
| Environment | Auto? | How to register |
|---|---|---|
| X11 / XIM | Auto | The unim daemon receives the shortcut via X server redirect |
| Wayland + GNOME | Auto | UNIM GNOME extension registers via Main.wm.addKeybinding |
| Wayland + KDE Plasma | Manual | KCM Custom Shortcuts |
| Wayland + Hyprland | Manual | hyprland.conf |
| Wayland + Sway | Manual | sway/config |
| Wayland + Wayfire | Manual | wayfire.ini |
| Wayland + other compositors | Manual | Compositor's shortcut tool |
Wayland compositors (KDE / Hyprland / Sway / Wayfire, etc.) intercept modifier-based combos like Super+... in their own shortcut subsystem before any application sees them. If the compositor consumes the keystroke, the input method (IME) never receives the event.
On GNOME, the UNIM GNOME extension hooks into Shell's shortcut slot, so it works automatically. Other compositors do not have such an extension, so you need to register unim-cli trigger emoji_popup as a shortcut command in the compositor's own shortcut system.
unim-cli trigger emoji_popup
Internally this calls the daemon's DBus interface org.atit.unim.InputMethod via the TriggerAction RPC. When the daemon receives the signal, it shows the emoji popup at the most recently active input context (the text widget you used last).
Future actions (e.g. hanja_popup) will follow the same unim-cli trigger <action> pattern.
Trigger UNIM emoji popup (any name)Meta+.unim-cli trigger emoji_popupPlasma 5 works the same way (paths:
System Settings → Shortcuts → Custom Shortcuts).
Add to ~/.config/hypr/hyprland.conf:
bind = SUPER, period, exec, unim-cli trigger emoji_popup
The config auto-reloads; force it with hyprctl reload.
Add to ~/.config/sway/config:
bindsym Mod4+period exec unim-cli trigger emoji_popup
Mod4 is the Super (Windows) key. Apply with swaymsg reload.
Add the following to the [command] section of ~/.config/wayfire.ini:
[command]
binding_emoji = <super> KEY_DOT
command_emoji = unim-cli trigger emoji_popup
The config auto-reloads on save.
If you have the UNIM GNOME extension installed and enabled, no setup is needed. Otherwise, GNOME's built-in shortcut system can do the same:
UNIM Emoji Popupunim-cli trigger emoji_popupSuper+. → AddSome
Supercombos are reserved by GNOME. If there is a conflict, try a different combo (e.g.Ctrl+Alt+E).
On X11/XIM, the daemon usually matches the shortcut automatically and no manual registration is required. However, in environments where the daemon does not receive the key (some game modes, certain screen-switching tools), you can supplement with xbindkeys.
Add to ~/.xbindkeysrc:
"unim-cli trigger emoji_popup"
Mod4 + period
Apply:
xbindkeys -p # stop existing instance
xbindkeys # start again
After registering the shortcut, watch the daemon log:
journalctl --user -f | grep unim
Or if you run it as a systemd service:
journalctl --user -u unim-daemon -f
A successful press should produce something like:
[DBus] TriggerAction(emoji_popup) received
If you don't see that message:
which unim-cliunim-cli trigger emoji_popup directly in a terminal and verify there are no errorssystemctl --user status unim-daemonThe Super+. above is a desktop-global shortcut, but the two GTK4 layout tools that ship with
UNIM have their own shortcuts that work only inside their windows (no compositor registration
needed). For usage details see
user manual §5.6.
| Key | Action |
|---|---|
| F1 | Help |
| Ctrl + N | New layout |
| Ctrl + D | Duplicate current layout |
| Ctrl + S | Save (user layouts) |
| Ctrl + Shift + S | Save As |
| Ctrl + E | Export |
| Ctrl + I | Import |
| Ctrl + 1 / 2 / 3 / 4 | Switch tab (Basic / Keymap / Combos / Extended) |
| Key | Action |
|---|---|
| F1 | Help |
| Ctrl + R | Restart |
| Ctrl + Shift + C | Copy results |
| Ctrl + 1 | Practice view |
| Ctrl + 2 | Results view |
| Ctrl + O | Import material from file |
| Ctrl + Shift + V | Import material from clipboard |
unim-cli trigger <action> pattern and can be registered the same way.Related docs:
unim-cli/SPEC.md — CLI specificationunim-daemon/SPEC.md — daemon DBus interfaceunim-gnome-extension/SPEC.md — GNOME extension shortcut handlingThe questions people actually ask about UNIM 0.4.4. Each answer carries at least one line of "why it works that way" so you can use it for your next decision, not just as a fact lookup.
| Item | UNIM | ibus-hangul | fcitx-hangul | kime | nimf |
|---|---|---|---|---|---|
| Core language | Rust | C | C | Rust | C |
| Transport | DBus daemon + IM module | IBus daemon | Fcitx daemon | Embedded | Daemon |
| GTK3/4 | ✅ Native IM module | ✅ | ✅ | ✅ | ✅ |
| Qt5/6 | ✅ Native plugin | ✅ | ✅ | ✅ | ✅ |
| XIM | ✅ | ✅ | ✅ | ✅ | ✅ |
| Wayland (input-method-v2) | ✅ | ✅ (IBus) | ✅ | △ | ✅ |
| GNOME Shell direct integration | ✅ Own extension | ✅ (IBus) | △ | ✗ | ✗ |
| Auto Korean↔English typo fix | ✅ AutoTypeFix (forward + reverse + learning) | ✗ | ✗ | ✗ | ✗ |
| Hanja 9-cell / 81-cell grid | ✅ unified | △ | △ | ✗ | △ |
| Hanja bookmarks | ✅ DBus signal sync | ✗ | ✗ | ✗ | ✗ |
| User layout v1 JSON | ✅ inherits + rule_sets | ✗ | △ | △ | ✗ |
| License | (see project license) | LGPL/GPL | GPL | GPLv3 | LGPL |
One-liner: UNIM's design is "one Rust core plugged into every environment", and it differentiates further on user-experience features (AutoTypeFix, learned suppression dictionary) that other IMEs do not have.
🐧 Linux
Technically yes, but not recommended. With two IMEs alive, the OS and toolkit cannot tell where to deliver key events.
sudo apt remove ibus
Bottom line: pick exactly one. Cleanly remove the other before installing UNIM.
🐧 Linux
Stability tier as of UNIM 0.2.0:
| Environment | Tier | Note |
|---|---|---|
| Ubuntu 24.04 + GNOME(Wayland) + extension | 🟢 A | Recommended; main dev/test environment |
| Ubuntu 24.04 + GNOME(X11) | 🟢 A | Env vars + Standalone popup |
| KDE Plasma 6 (Wayland) | 🟢 B+ | input-method-v2 works |
| KDE Plasma 6 (X11) | 🟢 B+ | XIM/Qt IM both fine |
| Sway (Wayland) | 🟡 B | Popup positioning slightly off — see popup spec §8.4 |
| Hyprland (Wayland) | 🟡 B | Same |
| XFCE/MATE (X11) | 🟢 B+ | Traditional, solid |
| Pure Wayland (compositor-dependent) | 🟡 B/C | Depends on the compositor's IM protocol support |
Tier A = "first-time user starting point". Once you are familiar, the rest is fine too.
Two stages.
The engine simulates two virtual tracks (Korean track, English track) for every keystroke regardless of mode. So in English mode, while gksrmf arrives, the Korean track is also producing 한글 in parallel.
At a word boundary (space, punctuation, Enter), if the other track has produced a meaningful word, propose a correction.
gksrmf → 한글.ㅈㅐㅍㅁ → wave.If the user rejects a correction with BS+mode-switch → marked Pending. The next time the same word triggers, the engine suppresses that attempt and registers it as Tentative. Pressing Confirm in the GUI promotes it to Confirmed (permanent).
Key insight: registration happens at retrigger time, not rollback time. This keeps a one-off mode mistake from becoming a permanent suppression.
Yes, that is the designed behavior. Bookmarking (★) promotes a hanja to the top of page 1; un-bookmarking (☆) demotes it back to its lexicographic home. If that home is on a different page, the popup follows.
To make sure you do not miss that jump, the destination cell flashes Catppuccin yellow (#f9e2af) for 140 ms. The flash answers "I just unstarred it — where did it go?" with a single visual signal.
For mechanics see user manual §4.2 and popup spec §3.6/§3.7.
| Item | 9-cell (compact) | 81-cell (expanded) |
|---|---|---|
| Screen footprint | small | large |
| Visible candidates | 9 | 81 (9×9) |
| Best for | top candidate is the right one | rare hanja, many homophones |
| Toggle key | — | . (period) |
| Indicator | ⊟ icon | ⊞ icon |
| Bindings | 1–9 direct, arrows | 1–9 + row jump, arrows |
With more than 9 candidates, 9-cell paginates with arrow keys; 81-cell unfolds nine pages at once for visual comparison.
🐧 Linux
~/.config/unim/
├── config.yaml # General settings (source of truth)
├── typefix-blacklist.yaml # Learned suppressions
├── userdict.yaml # Reverse user dict (new in 0.2.0)
└── layouts/ # Custom v1 layouts
└── my_3bul_variant.json
tar -czf ~/unim-backup-$(date +%F).tar.gz -C ~/.config unim
systemctl --user stop unim-daemon
tar -xzf ~/unim-backup-2026-04-26.tar.gz -C ~/.config
systemctl --user start unim-daemon
The daemon hot-reloads
typefix-blacklist.yamlanduserdict.yamlon mtime change, so you can restore them without stopping the daemon.config.yamlcaches some keys at start, so a restart is safer for it.
ko_2bulstd (Dubeolsik standard), ko_3bul390 (Sebeolsik 390), ko_3bul391, ko_3bul_noshift, ko_3bul_anmatae (Ahnmatae, chord/moachigi).
Note: Qwerty Sebeolsik (
ko_3bul_qwerty) is preserved as a research reference, not as a built-in. Copydocs/references/keymaps/ko_3bul_qwerty_v2.jsonto~/.config/unim/layouts/ko_3bul_qwerty.jsonto activate it as a user profile.
qwerty, dvorak, colemak, colemak_dh, workman.
🐧 Linux
Drop a v1 schema JSON into ~/.config/unim/layouts/<name>.json — daemon scans automatically. Use inherits: "ko_3bul390" to override only what you need.
unim-cli config layout validate ~/.config/unim/layouts/my.json
# activate
unim-cli config set korean-layout my
Schema details: docs/archive/plans/LAYOUT_PROFILE_V1.md.
Use
rule_setsto bundle optional toggles with a layout. E.g.ko_3bul390'ssun_arae_batchim. The settings GUI dynamically renders a SwitchRow.
In normal operation, unim-daemon RSS sits in 30–80 MB. UNIM 0.2.0 hardens this:
#[global_allocator] tikv_jemallocator::Jemalloc blocks the glibc ptmalloc arena explosion.Environment=MALLOC_ARENA_MAX=2 in systemd (belt-and-suspenders for the C path).libc::malloc_trim(0) task forces memory release back to the OS.A previous incident saw RSS balloon to 2 GB on 0.1.x. Regression on those items is forbidden. If you observe RSS > 500 MB, see troubleshooting §14.
No. Password fields are detected via content_purpose and forced to English. AutoTypeFix (both forward and reverse), hanja conversion, and the special-char popup are all disabled. Any keystroke-observation buffer and undo history already accumulated are cleared too, so a password typed like dkssud is never auto-corrected into Korean and corrupted. The input is not retained in daemon memory.
Caveat: automatic detection only works when the app accurately reports
content_purpose=password(Linux) orInputScope(Windows). Environments that do not report it — legacy XIM apps, and some Wayland compositors/web forms that do not send content-purpose — may fail to auto-detect; verify English mode manually via the toggle key there. (Environments that detect correctly: GTK3/4, Qt5/6, GNOME extension, Windows TSF — both 64-bit and 32-bit apps are detected the same way, via theunim_tsf32.dllTSF TIP'sInputScope. If you've seen a claim that "Windows IMM32 apps are detected on a best-effort basis for standard ES_PASSWORD controls only," that describes the IMM32 fallback, which is not actually shipped in the release — see Q11.)
This is intended. AutoTypeFix is deliberately disabled in password and PIN fields (see Q9), because otherwise a password typed like dkssud would flip to Korean at a word boundary and break your login. It returns to normal the moment you leave the field, and any on/off toggle state you set manually is preserved.
Conversely, if correction fails in a non-password field, the cause is different → Troubleshooting §8. In the undetectable environments above (XIM, some Wayland), a password field is treated as a normal field and correction may in fact fire — that limitation is documented in Troubleshooting §8-1.
install.sh safe?curl -fsSL .../install.sh | bash is convenient, but it does mean "run an entire unseen script," which can be unnerving. The UNIM installer has four safety guards:
SHA256SUMS shipped in the release acts as the manifest; every downloaded .deb is verified against it. On any mismatch it aborts before the install step (no partial install).mktemp working directory that a trap removes automatically on success, failure, or interrupt. Nothing is left on your system.apt install, not dpkg -i, so even external runtime dependencies are resolved inside apt's atomic transaction; a failure leaves no partial install.curl ... -o install.sh and read it before running.Limitation: because
SHA256SUMSlives at the same origin (GitHub Releases) as the.debs, transfer integrity is guaranteed but origin authenticity relies on trusting GitHub's TLS. GPG/minisign signing is future work. For minimal trust, use Method 2 (manual download) and verify each file yourself.
Mostly automatic. Two normalizations:
korean.layout written as an enum (Dubeolsik) is auto-converted to a string (ko_2bulstd).english.layout written as an enum is auto-converted (qwerty, etc.).typefix-blacklist.yaml's old keys go through a serde compat layer.C API: UnimEnglishLayout / UnimKoreanLayout enums removed → setters/getters now take/return C strings. Affects only C/C++ clients.
Full migration: changelog 0.2.0.
Windows: yes. macOS: not yet.
As of v0.4.0, Windows 10/11 (64-bit) is supported via unim-tsf, built on the Text Services Framework (TSF).
irm https://raw.githubusercontent.com/from104/unim/main/install.ps1 | iex
downloads and installs the MSI (see user manual §2.1 Install). 32-bit apps are handled by a separate 32-bit TSF TIP (unim_tsf32.dll) rather than the 64-bit TSF path. The IMM32 fallback explored earlier (the unim-imm32 crate) remains only as diagnostic/research source that is not included in the shipped MSI — if you've seen documentation advertising an "IMM32 fallback" as a shipped feature, it's out of date.
The Windows side is in daily production use on the maintainer's machine and is refined from that use, but it has not been through the same breadth of machines and applications as Linux. If you hit a problem, please report it on GitHub Issues with the app name and your Windows version (winver).
macOS is still not started (roadmap stage 5). Because the Rust core and C-API are separated, in principle an adapter for macOS's IMKit is feasible, but nobody has started it yet. Volunteers welcome.
Cargo.lock is in v4 format. cargo 1.83+ handles it safely (1.95 is the version we verify). Some distros ship /usr/bin/cargo as 1.75; explicitly use rustup:
rustup update stable
which cargo # should be ~/.cargo/bin/cargo
cargo --version # 1.95.0+
The error lock file version 4 requires '-Znext-lockfile-bump' is always this issue.
CONTRIBUTING.md — branch/PR workflow.AGENTS.md — architecture and component map.IME_BEHAVIOR.md — behavior spec.SPEC.md.make build warning-free + cargo test --workspace all pass.good-first-issue labels are the best entry point.
Universal Next-generation Input Method. Although it is a Korean IME, "universal" stands for (a) bidirectional Korean ↔ English handling and (b) one core plugged into every toolkit. In the long term, also macOS/Windows (roadmap stage 5).
Ahnmatae (안마태) is a specific keyboard layout. Finalized in 2003, it is a three-beol (sebeolsik) style layout with fixed cho/jung/jong regions mapped to distinct keyboard zones. In UNIM it ships as the ko_3bul_anmatae built-in profile.
Moachigi (모아치기, "gather-and-strike") is an input method. Multiple jamo pressed simultaneously or within a short window are combined into a single syllable. Unlike ordinary dubeolsik/sebeolsik which process one key at a time, moachigi collects all keys within the chord window (default 60 ms) and resolves them at expiry.
In UNIM 0.3.0, Ahnmatae is the first built-in layout that supports moachigi. The moachigi settings group in the GTK settings dialog appears only when the selected layout has supports_moachigi=true.
First check whether unim-popup-service is available on the bus:
busctl --user introspect org.atit.unim.PopupService /org/atit/unim/popup
No response means the package is not installed or the D-Bus service file is missing. See troubleshooting §16 for the full diagnosis flow.
Yes. All user data lives under ~/.config/unim/ and is independent of the package format:
~/.config/unim/config.yaml — main settings~/.config/unim/layouts/*.json — custom keyboard profiles~/.config/unim/typefix-blacklist.yaml — AutoTypeFix suppression dictionary~/.config/unim/typefix-userdict.yaml — user dictionaryUninstalling one package format and installing the other leaves these files untouched. Note that the unim-gui-qt package was removed in 0.3.0 — the tray icon, settings window, and popup renderer are now split between unim-desktop (indicator + legacy settings dialog + unim-popup-service, bundled together) and unim-settings (the Slint settings app). For the current full list of 11 packages, check debian/control or dpkg -l 'unim*'.
Two GTK4 companion tools ship alongside UNIM.
unim-keymap-studio (Keymap Studio): view and edit Korean/English layouts visually.
A three-stage header dropdown (language > source > layout) selects the target, and four tabs
(Basic / Keymap / Combos / Extended) show the content. The Combos and Extended tabs
appear only for Korean layouts. The header's right side holds [Help] / [Settings] / [Menu].
~/.config/unim/layouts/ (same location as the
user-defined layouts in Q7).unim-typing-practice (Typing Practice): practice typing with the currently active layout.
It measures WPM/CPM, accuracy, and a typo heatmap so you can see which keys you mistype most.Both tools share the same five-row keyboard widget, so the layout looks consistent across them. For shortcuts see user manual §5.6.
Valid range: 10–200 ms. Default: 60 ms (tuned for experienced typists).
| Profile | Recommended range | Notes |
|---|---|---|
| Beginner | 100–150 ms | Chord timing still inconsistent; extra window prevents missed chords |
| General | 60–100 ms | Comfortable for most users |
| Expert | 10–60 ms | Minimize false positives, maximize responsiveness |
Set to 0 to disable moachigi entirely.
🐧 Linux — adjust via the settings dialog slider or:
unim-cli config set korean-chord-window-ms 80
If you hold a key down (e.g. because of a tremor), the OS re-fires the same key rapidly (auto-repeat). UNIM has a Suppress Composition Key Auto-repeat (accessibility) option that makes the daemon ignore those repeats. Suppression applies to the Korean/English toggle key and character keys in Korean mode; repeats of editing keys (Backspace, arrows) and direct English typing are left alone. The default is off, so nothing changes until you enable it.
🐧 Linux
To enable it — the Accessibility → Suppress Composition Key Auto-repeat switch in the settings app, or the CLI:
unim-cli config set ignore-key-repeat true
Fallback limits: Wayland, Qt5/6, and the GNOME extension detect repeats precisely. The GTK3/4, XIM, and ibus-compatible paths approximate with an 80 ms time window, so (1) the first repeat may slip through, and (2) if your system key-repeat interval is set longer than 80 ms, repeats may not be filtered. In either case, when in doubt it errs toward suppressing less (fail-safe). GNOME extension users: applies after re-login.
Chrome does not report input field types to the input method, so UNIM cannot auto-detect them.
--enable-wayland-ime not enabled)By default, Chrome does not use the Wayland input method protocol (input-method-v2). You must enable the flag explicitly.
Solutions:
Option 1 — Command-line flag
google-chrome --enable-wayland-ime
chromium --enable-wayland-ime
Option 2 — Flag file (~/.config/chrome-flags.conf)
--enable-wayland-ime
Option 3 — .desktop entry (all users, persists across package upgrades)
# Find /usr/share/applications/google-chrome.desktop or ~/.local/share/applications/google-chrome.desktop
# Locate the Exec= line and append --enable-wayland-ime
Exec=/opt/google/chrome/google-chrome --enable-wayland-ime %U
After enabling the flag and restarting Chrome, UNIM will detect password fields.
The Chromium engine does not report input field types to the input method even on X11. This is a design choice in Chromium that UNIM cannot override. Manually verify English mode by pressing the Hangul/Korean toggle key before entering the password.
Alternative: Firefox reports field info to the input method, so detection works correctly.
The XIM protocol itself has no way to convey input field semantics.
XIM (X Input Method) is a legacy protocol from 1994 with no facility to signal field types like "password". Your options:
Removing UNIM does not automatically restore the system IME setting. If you removed IBus with sudo apt remove ibus while installing UNIM (as Q2 recommends), the "current IME = unim" setting made by im-config -n unim (or by enabling the GNOME+Wayland extension) survives even after you remove the UNIM package. Log back in after that and you're left with run_im unim pointing at a binary that no longer exists — no IME starts at all, and Korean/English toggling stops working entirely.
Switch back to another IME before removing UNIM.
# Example: install ibus-hangul first if you want to go back to it
sudo apt install ibus ibus-hangul
# Point im-config back
im-config -n ibus
# Or let it auto-pick from what's installed
im-config -n auto
# Now remove UNIM (all packages at once — shell glob)
sudo apt remove 'unim*'
im-config -n auto to auto-reassign to whatever IME is installed. If nothing is installed, sudo apt install ibus ibus-hangul first, then rerun it.~/.xinputrc directly — if run_im unim is still there, delete it or replace it with another IME's name (on a GNOME+Wayland session this file may not be used at all — see user manual §2.2).This removal/rollback path is managed by Debian/Ubuntu's
im-configframework, not by UNIM's package scripts, so UNIM cannot automatically revert it. The manual steps above are currently the only recovery path.
IME_BEHAVIOR.mdPOPUP_SPEC.mdUNIM 0.4.0 — organized as Symptom → first diagnosis → second-level command → fix. Covers 14 commonly seen symptoms, from "Korean never types" to "broken in one specific app".
🐧 Linux
Every diagnosis starts with two questions: is the daemon alive? and what does the log say?
# (1) Is the daemon alive?
systemctl --user status unim-daemon
# Or PID check
unim-daemon --check && echo "RUNNING" || echo "STOPPED"
# (2) Turn on debug logging and reproduce
UNIM_DEVELOP=1 systemctl --user restart unim-daemon
> ~/.unim-errors.log # truncate
# … reproduce the bug …
tail -f ~/.unim-errors.log
UNIM_DEVELOP=1aggregates Engine/DBus/Frontend/Extension logs into a single file (~/.unim-errors.log). The default is OFF so the log file does not grow unbounded.
🐧 Linux
echo $GTK_IM_MODULE # should be: unim
echo $QT_IM_MODULE # should be: unim
echo $XMODIFIERS # should be: @im=unim
unim-daemon --check && echo OK || echo MISSING
| Symptom | Cause | Fix |
|---|---|---|
| Env vars empty | im-config not configured | im-config -n unim, then log out/in |
unim-daemon --check → MISSING | Systemd unit not enabled | systemctl --user enable --now unim-daemon |
| Visible in shell, not in GUI apps | Display manager did not load env | export in ~/.xprofile or /etc/environment |
| GNOME+Wayland | Env-var path is dead | Use gnome-extensions enable unim-gnome@from104.github.io instead |
🐧 Linux — §2–§4 cover the Linux frontends (GTK / Qt / GNOME extension) only.
ls /usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules/im-unim.so 2>/dev/null
ls /usr/lib/x86_64-linux-gnu/gtk-4.0/4.0.0/immodules/libim-unim.so 2>/dev/null
sudo gtk-query-immodules-3.0 --update-cache
sudo gtk-query-immodules-4.0 --update-cache
unim-im-gtk or rerun sudo make install PREFIX=/usr.libim-unim.so, GTK3's is im-unim.so (different lib prefix).Tip:
GTK_IM_MODULE_FILE=/usr/lib/.../immodules.cache GTK_IM_MODULE=unim gnome-text-editorshows module-load errors on stderr.
ls /usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/libunimplatforminputcontextplugin.so
ls /usr/lib/x86_64-linux-gnu/qt6/plugins/platforminputcontexts/libunimplatforminputcontextplugin.so
QT_DEBUG_PLUGINS=1 kate 2>&1 | grep -i unim
unim-im-qt.QT_DEBUG_PLUGINS=1 shows Cannot load library → check dependencies with ldd <plugin>.so.QT_IM_MODULE=unim is enough.gnome-extensions list | grep unim
gnome-extensions info unim-gnome@from104.github.io
journalctl --user -u gnome-shell -b | grep -i unim
~/.local/share/gnome-shell/extensions/unim-gnome@from104.github.io/ exists.make dev-extension (source) or install the unim-gnome package.gnome-extensions enable unim-gnome@from104.github.io → Alt+F2 → r (X11) or log out/in (Wayland).metadata.json's shell-version array.🐧 Linux
# Is the popup renderer alive? (X11/KDE/Xfce — if not, see §16)
pgrep -a unim-popup
# On GNOME Wayland, is the extension enabled?
gnome-extensions list --enabled | grep unim
# Are DBus signals being emitted? (in a separate terminal)
busctl --user monitor org.atit.unim.InputMethod
# Then type Korean and press Hanja → ShowHanjaPopup signal should appear
| Environment | Popup renderer (0.3.0+) | Note |
|---|---|---|
| GNOME+Wayland | GNOME extension popup_view.js (St widget) | Extension receives PopupRender and paints directly |
| GNOME X11 / KDE / Xfce / X11 WM | unim-popup-service (GTK4) | Auto-launched via D-Bus activation |
| Wayland (KDE Plasma 6 / Sway, etc.) | unim-popup-service (GTK4, wayland-backend) | Needs libgtk4-layer-shell, experimental — see popup spec §12 |
Since 0.3.0, IM modules no longer draw their own popups. Rendering of the hanja / special-char / emoji popups is centralized in
unim-popup-service(or the GNOME extension). Diagnosis therefore checks whether the renderer process is alive, notpopup_mode.
DBus dead?:
busctl --user list | grep atit— if empty, the daemon failed to register. Checkjournalctl --user -u unim-daemon -n 100.
Same code path as Hanja popup, so the cause is similar.
🐧 Linux — There is no CLI key to query the current input mode (Korean/English) — check via the tray icon or the GNOME extension indicator instead.
Type one consonant (ㄱ–ㅎ) while in Korean mode, then press Hanja.
Works cleanly on Dubeolsik; on Sebeolsik the consonant entry is different.
🐧 Linux
UNIM_DEVELOP=1 systemctl --user restart unim-daemon
# Open the Hanja popup, hit `.`, then:
grep -i 'ToggleExpanded\|9x9\|expanded' ~/.unim-errors.log
make build && sudo make install.. for the period key.🐧 Linux — §7-1 and §7-2 are Linux-only symptoms (Wayland compositors / XIM).
On unim-frontends/wayland popups (compositors: GNOME mutter, KWin, Sway, etc.) the ◀/▶ buttons render correctly but a mouse left-click on them produces no reaction.
Wayland popups are drawn on zwp_input_popup_surface_v2. For pointer events to reach this surface, the compositor must route them into the IM popup. Some compositors (notably some GNOME mutter versions) treat the IM popup as pass-through, so the click falls through to the application below.
← / → (or Page Up / Page Down). 100 % equivalent to the mouse buttons.gnome-extensions list --enabled | grep unim.Keyboard ←/→ is guaranteed across every compositor. Mouse ◀/▶ is best-effort, gated by compositor policy.
In XIM (unim-frontends/xim) the emoji popup shows category tabs (smileys, animals, food, …) along the top and ◀/▶ paginate buttons at the bottom. Both react to left-click, which can be confusing.
Working as intended. The XIM emoji popup has two distinct controls: (1) category tabs along the top (left-click switches category), (2) ◀/▶ in the footer (left-click moves one page within the active category). Both use left-click but they live in different regions.
Tab (next) / Shift+Tab (previous).← / → (or Page Up/Page Down).The behavior is intended but visually under-separated. Tracked for a footer color tweak in a future release.
🐧 Linux
unim-cli config show | grep -i typefix # master/forward/reverse enabled state
cat ~/.config/unim/typefix-blacklist.yaml | head -50
Password protection (FAQ Q9) works only when the app reports "this field is a password" (content_purpose). The environments below cannot deliver that signal to UNIM, so the password field is treated as a normal field.
| Environment | Status | Reason |
|---|---|---|
GTK3/4, Qt5/6, GNOME extension, Windows TSF (both 64-bit and 32-bit unim_tsf32.dll) | Detected | content_purpose / InputScope delivered correctly |
| Legacy XIM apps | Not detected | XIM protocol has no such signal |
| Some Wayland compositors / web forms | Not detected | content-purpose not sent (app/compositor's discretion) |
| GTK apps that change purpose after focus | Not detected | The GTK IM reads input-purpose only at focus time and does not subscribe to notify::input-purpose (existing limitation) — if the same field later becomes a password, it is not reflected until re-focus |
This table is still sparse — reports are wanted. Which applications report password fields correctly and which do not can only be filled in from real-world use. On Linux and Windows alike there are not enough cases yet, so per-application handling is incomplete. If you find an app where correction fires inside a password field, please report the app name and version on GitHub Issues. That is the only way this table gets filled in.
unim-cli config set warns on such duplicates).preedit-exposure — tracked separately: In a password field, Korean composition itself is blocked, so a character briefly showing as preedit (underline) during composition is essentially absent in the correctly-detected environments. In the undetectable Wayland environments above, exposure could occur in theory; this is tracked as a separate issue, and the current recommended workaround is "verify English mode manually" above.
🐧 Linux
| Case | Fix |
|---|---|
| One specific word | BS + Hangul to roll back → next time the same word triggers, it auto-registers as Tentative |
| Frequent regrets | Settings → "Type Correction" → bump tentative-expiry hours |
| Reverse fires in English mode | Turn ON auto_typefix.reverse.skip_incomplete_syllable |
| Hand-edit | Open ~/.config/unim/typefix-blacklist.yaml — daemon hot-reloads on mtime change |
🐧 Linux
ls -la ~/.config/unim/
test -w ~/.config/unim/config.yaml && echo writable || echo BLOCKED
unim-cli config show 2>&1 | head -5
journalctl --user -u unim-daemon -n 50
chmod 644 ~/.config/unim/*.yaml, chmod 755 ~/.config/unim.sudo chown -R $USER:$USER ~/.config/unim.systemctl --user restart unim-daemon.🐧 Linux — §11–§14 are Linux-only. Windows has no GTK IM module, no Flatpak, no Snap, and no resident daemon.
Symptom: after one keystroke, the terminal freezes IME-wise.
Missing preedit-end signal in GTK3/4 IM (a 0.1.x leftover; resolved in 0.2.0 via the unim_emit_preedit helper).
unim-cli --version # 0.2.0+ contains the fix
If 0.1.x, rebuild and reinstall: make build && sudo make install.
flatpak list --columns=application,environment | grep -E 'GTK_IM|QT_IM'
On GNOME+Wayland, the host's IM env vars leak into the Flatpak sandbox and block input. Auto-handling should clear them.
# Verify auto-handling worked
journalctl --user -u unim-daemon | grep -i flatpak
# These two lines mean OK:
# [Flatpak] GNOME+Wayland detected — applying Flatpak IM override
# [Flatpak] IM environment override done
# Manual fallback
flatpak override --user --env=QT_IM_MODULE= --env=GTK_IM_MODULE=
flatpak kill org.telegram.desktop
On X11 or non-GNOME you actually need to keep the env vars — auto-handling fires only on GNOME+Wayland.
⚠️ Persists after uninstalling UNIM: this override is written permanently to your per-user
~/.local/share/flatpak/overrides/globalfile and is not reverted automatically when theunimpackage is removed. If you switch to another input method and Flatpak apps start misbehaving, unset it yourself:flatpak override --user --unset-env=QT_IM_MODULE --unset-env=GTK_IM_MODULE
Snap inherits host env vars but offers no global-override mechanism.
Conditional export in ~/.profile:
if [ "$XDG_SESSION_TYPE" = "wayland" ] && echo "$XDG_CURRENT_DESKTOP" | grep -q "GNOME"; then
export GTK_IM_MODULE=
export QT_IM_MODULE=
else
export GTK_IM_MODULE=unim
export QT_IM_MODULE=unim
fi
export XMODIFIERS="@im=unim"
Or per-launch:
QT_IM_MODULE= GTK_IM_MODULE= snap run telegram-desktop
grep -E 'VmRSS|VmData|Threads' /proc/$(pidof unim-daemon)/status
cat /proc/$(pidof unim-daemon)/smaps_rollup | grep -E 'Rss|Anonymous'
UNIM 0.2.0 ships with tikv_jemallocator + MALLOC_ARENA_MAX=2 + a 60-second malloc_trim(0) task, which keeps RSS in the low MB. If you still cross 500 MB:
# Quick recovery
systemctl --user restart unim-daemon
# Diagnostics for an issue report
ps -o pid,rss,vsz,cmd $(pidof unim-daemon)
journalctl --user -u unim-daemon -n 500 > unim-mem.log
AGENTS.md §Memory rules lists the regression-banned items and diagnostic commands.
Chord input failures have several possible causes. Work through the items below in order.
Chord input is only available for layouts that carry supports_moachigi: true. Among the built-ins, only the Ahnmatae layout (ko_3bul_anmatae) qualifies. Qwerty Sebeolsik v2 is preserved as a research reference (docs/references/keymaps/ko_3bul_qwerty_v2.json); copy it into your user layout folder to enable it as a moachigi-capable user profile.
The user layout folder is ~/.config/unim/layouts/ — copy the file to ~/.config/unim/layouts/ko_3bul_qwerty.json.
# Check the active layout
unim-cli config show | grep -E 'layout|keymap'
If the active layout is not moachigi-capable, switch to one in the GTK settings dialog. The Moachigi option group appears automatically once a compatible layout is selected.
The recommended default for chord_window_ms is 60 ms. If you are new to moachigi or type at a moderate pace, start at 80–100 ms and lower the value as you become comfortable.
# Check current setting
unim-cli config show | grep chord-window
# Set to 80 ms
unim-cli config set korean-chord-window-ms 80
Alternatively, use the settings app (unim-settings) → General page → layout options (shown only for chord-capable layouts) → slider.
If reverse-order jamo combinations do not work (e.g., ᆯ+ᆨ → ᆰ, or ㅎ+ㄱ → ㅋ), the Bidirectional Jamo Combine option is disabled.
# Check current state
unim-cli config show | grep bidirectional-combine
# Enable
unim-cli config set korean-bidirectional-combine true
Or in the settings app (unim-settings) → General page → layout options → Bidirectional Jamo Combine toggle → ON.
Standard membrane keyboards are limited to 2–3 KRO (Key Rollover). When more keys are pressed simultaneously than the keyboard can report, the extras are silently dropped — this is called ghosting. Symptoms include chords that are consistently incomplete or produce the wrong jamo.
Self-diagnosis:
# Check simultaneous key events on X11
xev -event keyboard
On Wayland, use wev instead of xev (apt install wev or equivalent).
Focus the window that appears, then press all keys in your chord at once. The terminal must print one KeyPress event per key. You can also use an online key tester such as keyboardchecker.com.
Fix: use a gaming keyboard or a mechanical keyboard in NKRO mode. See Ahnmatae keyboard guide — Keyboard Compatibility for details.
The default USB polling rate is 125 Hz (one report every 8 ms). If chord_window_ms is set to 10–30 ms, the polling interval itself occupies most of the window, causing some chord keys to be missed.
Fix:
chord_window_ms to 60 ms or higher to accommodate polling latency.🐧 Linux
make clean
make build 2>&1 | tee /tmp/unim-build.log
| Error | Cause | Fix |
|---|---|---|
lock file version 4 requires '-Znext-lockfile-bump' | cargo 1.75 (old) | rustup update stable to get cargo 1.95+ |
gtk4/libadwaita not found | Dev headers missing | sudo apt install libgtk-4-dev libadwaita-1-dev |
Qt6Core not found | Qt6 dev missing | sudo apt install qt6-base-dev |
cxx-qt build error | Qt header path mismatch | Inspect pkg-config --cflags Qt6Core |
| Any warnings | UNIM enforces zero-warning | File the warning verbatim as an issue |
The canonical build command is
make build.cargo build --workspacealone misses the C/C++ frontends.
🐧 Linux
{
echo "=== version ==="
unim-cli --version
echo "=== env ==="
echo "session=$XDG_SESSION_TYPE"
echo "desktop=$XDG_CURRENT_DESKTOP"
env | grep -E 'GTK_IM|QT_IM|XMOD' | sort
echo "=== daemon ==="
systemctl --user status unim-daemon --no-pager
echo "=== config ==="
unim-cli config show
echo "=== logs (last 200) ==="
tail -n 200 ~/.unim-errors.log 2>/dev/null
} > unim-report.txt
Attach unim-report.txt to your issue. Skim it once first — passwords/tokens are unlikely to be in the log, but a quick check is wise.
IME_BEHAVIOR.md — behavior spec (developer-oriented)AGENTS.md — architecture and memory rules🐧 Linux — §16 and the 0.2.0 release notes below are Linux-only.
Since 0.3.0, all popups are rendered exclusively by unim-popup-service. Even if the daemon is running, popups will not appear if popup-service is not available.
# Check whether popup-service process is running
pgrep -a unim-popup
# Verify the DBus interface is exposed
busctl --user introspect org.atit.unim.PopupService /org/atit/unim/popup
# Check that the D-Bus service activation file is installed
ls ~/.local/share/dbus-1/services/org.atit.unim.PopupService.service \
/usr/share/dbus-1/services/org.atit.unim.PopupService.service 2>/dev/null
If the service file is absent, the unim-desktop package (which bundles unim-popup-service together with the indicator and the legacy settings dialog) is not installed — unim-popup-service is not a standalone package.
# deb (match the version to whatever you actually downloaded)
sudo apt install ./unim-desktop_<version>_amd64.deb
# or, from source
sudo make install PREFIX=/usr
If the service file exists but popups still do not appear, start the service manually to see log output:
UNIM_DEVELOP=1 unim-popup-service &
# trigger hanja popup, then check terminal output
If busctl introspect fails entirely, the service is not responding. Check:
systemctl --user status unim-popup-service
journalctl --user -t unim-popup-service -b --no-pager
Clicking outside the popup is intentional dismiss behavior — the popup closes and the click event is passed through to the window underneath. Clicking inside a cell or button should not close the popup. If clicking inside the popup dismisses it, the popup position or size is being calculated incorrectly; check the DBus caret coordinates (caret_rect).
Meta.is_wayland_compositor() detection has failed, causing both the extension PopupView and the popup-service GTK4 window to render simultaneously. Check your GNOME Shell version, then disable and re-enable the unim-gnome@from104.github.io extension.
Right after a syllable is committed, the next jamo you type does not appear on screen. Open since 0.3.0, and the status now differs by path.
Fixed (2026-08-07) — for self-hosted XIM clients and OVER-THE-SPOT clients (XTerm, WezTerm). The cause was not what this page previously claimed (the xim crate's commit() not updating preedit_started) — removing that workaround entirely left the symptom unchanged. The real cause is that ON-THE-SPOT clients stop processing messages once they hit Commit while handling a key, so a new preedit sent after the commit was discarded. XIM now sends the preedit before the commit; see the exception in docs/dev/architecture/IME_BEHAVIOR.md §8.1.
Still open (confirmed 2026-08-10) — when GTK attaches through its XIM module (im-xim), the symptom remains and the cause is different. There the input method stalls right after the commit, so the next character is swallowed for several seconds (libX11 recovers on its own after a timeout). Sending PreeditDraw is what wedges that input context: it stops receiving further keys. Reproduces 3/3.
im-unim.so is not visible inside the sandbox, so GTK falls back to XIM. Obsidian (Electron) is the common case.Progress is tracked in ROADMAP phase 3, "Sandboxed apps (Flatpak/Snap) input path".
Auxiliary diagnostics drafted by manual-test-planner just before the 0.2.0 release. The user-facing sections above (§1–§14) take precedence; this section keeps only supplementary diagnostic tools and regression-watch items.
| Command | Purpose |
|---|---|
journalctl --user -u unim -b --no-pager | Daemon systemd logs (this boot) |
: > ~/.unim-errors.log; UNIM_DEVELOP=1 /usr/libexec/unim-daemon -n --replace & | Reset log + restart in dev mode |
pgrep -a unim- | All unim-* processes |
busctl --user introspect org.atit.unim.InputMethod /org/atit/unim/InputMethod | DBus API surface |
늘늘): focus-out CommitText broadcast — fixed in 0.2.0.consumed=true commit=" " path.tentative_expiry_hours unit changed days → hours (1..=12) since 0.2.0; existing config auto-migrates.Commit while handling a key (the long-standing claim that xim's commit() fails to update preedit_started was a misdiagnosis), so XIM — and only XIM — now sends the preedit before the commit (IME_BEHAVIOR.md §8.1). However, the path where GTK attaches via im-xim is still broken as of 2026-08-10, with a different cause: sending PreeditDraw wedges that input context so it receives no further keys (reproduces 3/3). Flatpak and Snap apps are the main victims. Regression watch: tests/unim-test-xim and tests/unim-test-gtk3 (ON-THE-SPOT), xterm (OVER-THE-SPOT), plus tests/unim-test-gtk3 launched with GTK_IM_MODULE=xim.pkill -9 -x unim-daemon; sleep 1; systemctl --user start unim--replace.cursor_y = 0 fallback (see POPUP_SPEC §6.3)..) key intercepted elsewhere; check keymap.HanjaBookmarkChanged signal not reaching listeners → busctl --user monitor org.atit.unim.InputMethod.sudo locale-gen ko_KR.UTF-8.mo file missing: ls /usr/share/locale/ko/LC_MESSAGES/unim*.mounim-cli config set doesn't show up in the GUIpkill -SIGHUP unim-daemon| Environment | Support | Notes |
|---|---|---|
| GNOME Wayland | ✅ Validated | GNOME extension popup_view.js (St widgets) renders popups directly |
| GNOME X11 | ✅ Validated | popup-service GTK4 + GNOME extension assist |
| X11 + KDE Plasma 5.x | ✅ Validated | popup-service GTK4 |
| X11 + XFCE / MATE / Cinnamon / LXDE | ✅ Validated | popup-service GTK4 |
| Wayland + KDE Plasma 5.x | ❌ Unsupported | gtk4-layer-shell missing in Ubuntu 24.04 (noble) standard repos → use X11 session or GNOME |
| Wayland + KDE Plasma 6 | ⚠️ Experimental | Requires wayland-backend feature + libgtk4-layer-shell. Not exercised in 0.4.0 QA either (unchanged since 0.3.0) |
| Sway / Hyprland / river (standalone Wayland) | ⚠️ Experimental | Same as above. Possible regressions in popup placement and IME focus handover |
| Weston etc. reference Wayland | ⚠️ Experimental | Same as above |
0.4.0 reconfirmation: the table above still holds as of the v0.4.0 release — pure (non-GNOME) Wayland still does not support the hanja/special-character popup in this release (a deliberate design constraint, unchanged), and Wayland compositors that don't go through GNOME remain "experimental". Windows (TSF, both 64-bit and 32-bit via
unim_tsf32.dll) is a newly added experimental platform in v0.4.0 and is not included in this table — see FAQ Q11 instead.
⚠️ For issues on experimental environments, please file a bug at GitHub Issues.
# If you're using Claude Code
/unim-log
→ automatically classifies, summarizes, and diagnoses ~/.unim-errors.log.