The paragraphs on candidates, keys, and searches had grown by patches; they read as three: Japanese, Korean, and the searches.
221 lines
8.6 KiB
Markdown
221 lines
8.6 KiB
Markdown
# strans
|
|
|
|
strans is a small, single-user input method for Korean, Japanese, English,
|
|
emoji, and symbols. It provides one engine for IBus (which GTK 4 and
|
|
Qt use), XIM, and GTK 3. Vietnamese Telex is also available as a
|
|
compatibility mode.
|
|
|
|
## Input modes
|
|
|
|
| Key | Mode |
|
|
| --- | --- |
|
|
| `Ctrl+N` | Japanese Hiragana and Kanji conversion |
|
|
| `Ctrl+K` | Japanese Katakana |
|
|
| `Ctrl+S` | Korean Hangul (2-beolsik) |
|
|
| `Ctrl+T` | English |
|
|
| `Ctrl+V` | Vietnamese Telex |
|
|
| `Ctrl+E` | Emoji and symbol search |
|
|
| `Ctrl+H` | One-shot Hanja search |
|
|
|
|
A Korean keyboard's 한/영 key toggles Korean and English, and its 한자 key
|
|
is `Ctrl+H`; a Japanese keyboard's 半角/全角 toggles Japanese and English,
|
|
ひらがな/カタカナ switches between the two kana modes, 変換 turns Japanese
|
|
on and then converts like `Space`, and 無変換 turns it off. Only a plain
|
|
`Ctrl` chord is a strans key: with `Shift`, `Alt`, or `Super` held it
|
|
commits what is pending and goes to the application, so `Ctrl+Shift+V`
|
|
still pastes.
|
|
|
|
Hiragana mode composes a complete reading, then shows its Kanji candidates
|
|
with none chosen: the exact readings of the dictionary, then the verbs and
|
|
adjectives SKK keys by stem and okurigana (かく offers 確 and 書く), and
|
|
under `Space` the reading in Katakana last, so a word the dictionary lacks
|
|
converts to Katakana with one `Space`. `Space` or `Tab` chooses the first
|
|
candidate and then steps on, wrapping (with `Shift`, back); `Up`/`Down` and
|
|
`PageUp`/`PageDown` move without wrapping. An unmodified `1`-`9` commits
|
|
that row of the current page. `Enter` commits the chosen candidate, or the
|
|
reading when none is chosen, as `0` always does; so does typing on, or any
|
|
key that ends the composition. `Backspace` deletes the last kana shown;
|
|
romaji that made no kana stays in the reading as typed until it is mended.
|
|
`Backspace` and `Esc` on a chosen candidate go back to the reading, and
|
|
`Esc` on the reading cancels it. Katakana mode does not perform Kanji
|
|
conversion.
|
|
|
|
Korean composes one syllable at a time; `Enter`, `Tab`, `Esc`, and any key
|
|
that is not a jamo commit the syllable and go on to the application, so
|
|
`Esc` still leaves insert mode. Two lone consonants join into the compound
|
|
final they make (rt → ㄳ) and a vowel typed before its consonant is
|
|
reordered under it (kr → 가), as in libhangul.
|
|
|
|
Emoji and Hanja searches take over the keys until `Enter`, `Space`, or a
|
|
digit picks a result or `Esc` cancels; they return to the previous mode
|
|
after use, and switching language during a search commits the shown
|
|
query. `Tab`/`Shift-Tab` wrap through the results, and a search with
|
|
nothing typed yet shows ☺ or 漢 in the popup. The Emoji search matches the
|
|
typed keys, and what they spell in the current language, against a prefix
|
|
of every emoji's CLDR name and keywords in English, Korean, and Japanese,
|
|
and against ASCII symbol aliases such as `->` and `<=`. `Ctrl+H` takes the
|
|
syllable being composed as its query and composes on from it; `Esc` gives
|
|
the syllable back; the Hanja dictionary lists one modern Hangul syllable at
|
|
a time. Leaving the field or clicking elsewhere commits what is pending.
|
|
|
|
## Preedit and candidates
|
|
|
|
| Frontend | Preedit | Candidates |
|
|
| --- | --- | --- |
|
|
| GTK 3 and IBus | inline in the client | strans popup |
|
|
| XIM PreeditCallbacks | inline through XIM callbacks | strans popup |
|
|
| XIM PreeditPosition | strans popup | strans popup |
|
|
| XIM PreeditNothing | strans popup | strans popup |
|
|
|
|
Each XIM style is offered with StatusNothing and with StatusNone.
|
|
|
|
XIM text travels as `COMPOUND_TEXT`, which carries any UTF-8. A client that
|
|
sends `XNSpotLocation` gets the popup under that spot whatever its preedit
|
|
style, and above the line when there is no room below; otherwise the popup
|
|
sits under the focus window, or under the client window when no focus
|
|
window is set.
|
|
|
|
The popup is an X11 window sized by `GDK_SCALE` on HiDPI displays, XIM is
|
|
X11-only, and GTK popup placement converts the GTK caret to X11 root
|
|
coordinates. There is no native Wayland popup surface or Wayland caret
|
|
positioning. GTK and IBus clients can still use inline preedit where their
|
|
display environment supports it.
|
|
|
|
## Build and test
|
|
|
|
Initialize the bundled test library, then use the pinned Docker environment
|
|
for a reproducible build:
|
|
|
|
```sh
|
|
git submodule update --init
|
|
make docker-image
|
|
make docker-build
|
|
```
|
|
|
|
Build output:
|
|
|
|
```text
|
|
strans daemon with IBus and XIM frontends
|
|
gtk/im-strans.so GTK 3 frontend module
|
|
```
|
|
|
|
Tests have three tiers:
|
|
|
|
```sh
|
|
make check # generated-map validation and focused unit tests
|
|
make check-live # one IBus, GTK, XIM, and IPC daemon smoke
|
|
make check-stress # randomized, capacity, collision, failure, and restart tests
|
|
```
|
|
|
|
`UNITARGS` filters only the focused C unit suite, for example
|
|
`make check UNITARGS=hangul`. It does not select or skip live and stress
|
|
tests. `make docker-check` rebuilds and runs all three tiers in the
|
|
container, and `make docker-valgrind` runs the unit suite under Valgrind
|
|
there; run `make docker-image` first after changing `Dockerfile`.
|
|
|
|
Native Linux source builds require a C toolchain, Make, pkg-config, Python 3,
|
|
and cmp/diff, plus development files for:
|
|
|
|
- Plan 9 port (`9c`, `9l`, `libthread`, and `libbio`);
|
|
- D-Bus development files;
|
|
- XCB, XCB RandR, XCB XKB, xcb-util, xcb-imdkit, xkbcommon, and xkbcommon-x11;
|
|
- Pango, PangoCairo, Cairo, and Fontconfig;
|
|
- GTK 3, plus libibus and Xlib for the live clients;
|
|
- Xvfb for the X11 live tests;
|
|
- a working `C.UTF-8` locale and fonts covering Latin, CJK, and emoji.
|
|
|
|
The package names used by the canonical Arch Linux image are listed in
|
|
[`Dockerfile`](Dockerfile).
|
|
|
|
## Run
|
|
|
|
The popup uses the normal system fonts found by Pango and Fontconfig; no font
|
|
file argument or system-wide strans installation is required. Run it directly
|
|
from the build tree:
|
|
|
|
```sh
|
|
./run.sh
|
|
# equivalently
|
|
./strans map
|
|
```
|
|
|
|
`run.sh` stops every same-user process whose exact name is `strans`, starts one
|
|
build-tree daemon in the background, and returns to the shell. It requires
|
|
`pkill` from procps. Startup and frontend failures remain visible on the
|
|
caller's standard error. A service supervisor should instead run
|
|
`./strans map` directly in the foreground.
|
|
|
|
The build does not copy or install the daemon or its data. `./strans DIR`
|
|
opens `hira.map`, `kata.map`, `telex.map`, `kanji.dict`, `emoji.dict`, and
|
|
`hanja.dict` from `DIR` at runtime; `run.sh` passes the tracked `map/`
|
|
directory. Only the GTK subdirectory has install and uninstall targets.
|
|
|
|
Pango shapes the complete string and selects glyph fallback from the system
|
|
font set.
|
|
|
|
The popup renderer uses Pango/PangoCairo and Cairo. When `DISPLAY` is set,
|
|
`strans` starts its XIM worker in the same process.
|
|
|
|
Configure clients as needed:
|
|
|
|
```sh
|
|
# XIM
|
|
export XMODIFIERS=@im=strans
|
|
|
|
# GTK 3 module
|
|
doas make -C gtk install
|
|
export GTK_IM_MODULE=strans
|
|
|
|
# IBus client example
|
|
GLFW_IM_MODULE=ibus kitty
|
|
```
|
|
|
|
Building `gtk/im-strans.so` requires GTK development files. Installing an
|
|
already-built, up-to-date module from this build tree does not: the install
|
|
target first uses an explicit `GTK_MODULE_DIR`, then GTK's pkg-config
|
|
variables, and finally the module directory reported by the GTK runtime's
|
|
`gtk-query-immodules-3.0`. Packagers and cross builds should set
|
|
`GTK_MODULE_DIR` explicitly. A prebuilt module must still match the target
|
|
architecture and library ABI.
|
|
|
|
`DESTDIR` staging is supported and deliberately skips the host module-cache
|
|
update. A native install needs the GTK runtime query utility so it can refresh
|
|
that cache. Remove a native installation with:
|
|
|
|
```sh
|
|
doas make -C gtk uninstall
|
|
```
|
|
|
|
strans provides its own IBus endpoint; `ibus-daemon` and fcitx are not
|
|
required. IBus clients that process keys synchronously — GTK 4, or GTK 3
|
|
with `IBUS_ENABLE_SYNC_MODE=1` — get their commits and preedits through
|
|
`PostProcessKeyEvent`, in order with the key. Without `DISPLAY`, the daemon and IBus frontend still work, but XIM
|
|
is not started and the popup is disabled.
|
|
|
|
## Dictionary data
|
|
|
|
After changing an input source, regenerate and verify the maps and
|
|
dictionaries:
|
|
|
|
```sh
|
|
python3 map/mktelex.py >map/telex.map
|
|
map/mkemoji >map/emoji.dict
|
|
map/mkhanja >map/hanja.dict
|
|
make verify-map
|
|
```
|
|
|
|
See [`map/README`](map/README) for the emoji, Hanja, and Japanese data and
|
|
where it comes from.
|
|
|
|
## Benchmark
|
|
|
|
`make bench` builds `bench/bench`. With the daemon stopped, `./bench.sh` starts
|
|
one build-tree instance, warms it up, and records the workload with Linux
|
|
`perf`. It requires `perf` and permission to profile the daemon, and writes
|
|
`bench/perf.data`.
|
|
|
|
## Licensing
|
|
|
|
Third-party license notices are in [`LICENSES`](LICENSES). The repository does
|
|
not currently declare a license for the strans source as a whole.
|