The emoji search folded the keys for its lookup and then showed and committed the folded copy: SMILE became smile in the text. And it showed the transliteration only while that alone matched, so a Korean query flipped between 웃 and key soup as it grew. Now the query shown is the keys while they match anything, else what they type in the current language, both as typed; only the lookups fold. Space in a search picks the highlighted result as Enter does, instead of adding a space no alias needs.
205 lines
7.8 KiB
Markdown
205 lines
7.8 KiB
Markdown
# strans
|
|
|
|
strans is a small, single-user input method for Korean, Japanese, English,
|
|
emoji, and symbols. It provides one engine for IBus, 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.
|
|
|
|
A complete Japanese reading shows its Kanji candidates with none chosen.
|
|
`Space` chooses the first and then steps on, wrapping (`Shift+Space` steps
|
|
back); `Up`/`Down` and `PageUp`/`PageDown` move without wrapping. An
|
|
unmodified `1`-`9` commits that row of the current page. `Enter` and `Tab`
|
|
commit 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.
|
|
Japanese consumes the confirming key; Korean and Vietnamese pass it on to
|
|
the application. `Space` adds the reading in Katakana as the last
|
|
candidate, so a word the dictionary lacks converts to Katakana with one
|
|
`Space`. `Backspace` and `Esc` on a chosen candidate go back to the
|
|
reading. In a temporary Emoji or Hanja search, `Enter` or `Space` commits the
|
|
highlighted result and `Tab`/`Shift-Tab` wrap through the results. Leaving
|
|
the field or clicking elsewhere commits what is pending. `Esc` cancels a
|
|
Japanese reading or a search; in Korean and Vietnamese it commits the
|
|
syllable and goes on to the application, so it still leaves insert mode.
|
|
|
|
Hiragana mode composes a complete reading before offering Kanji candidates.
|
|
Katakana mode does not perform Kanji conversion. Emoji and Hanja searches
|
|
return to the previous mode after use; switching language during a search
|
|
commits the shown query; `Esc` in a Hanja search gives the syllable back
|
|
to the composition. 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; the Hanja dictionary lists one modern Hangul syllable at a time.
|
|
|
|
## 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 |
|
|
|
|
XIM text travels as `COMPOUND_TEXT`, which carries any UTF-8. A client that
|
|
sends `XNSpotLocation` gets the popup at that spot whatever its preedit
|
|
style; 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-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. 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 dictionaries:
|
|
|
|
```sh
|
|
map/mkemoji >map/emoji.dict
|
|
map/mkhanja >map/hanja.dict
|
|
make verify-map
|
|
```
|
|
|
|
See [`map/README`](map/README) for Hanja import and Japanese dictionary
|
|
generation.
|
|
|
|
## 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.
|