A complete Japanese reading showed its candidates with the first row highlighted, yet Enter committed the reading unless the user had moved to a candidate: the highlight lied. Now sel is -1 while nothing is chosen, and it alone says what Enter commits; candidatechosen goes. Every key that ends a composition — Enter, Tab, a language switch, a special key, a modifier chord, typing on — now commits the chosen candidate through one flush; before, only Enter and Tab did, and Ctrl+S after choosing 漢字 committed かんじ. Space in a Japanese mode is the conversion key, as in every other Japanese IME: it steps through the candidates (Shift+Space backwards, both wrapping) and commits a reading that has none, without typing a space. Backspace and Escape on a chosen candidate go back to the reading first. Tab in a search wraps through the same cyclekouho. reset() no longer forgets the caret: a chosen candidate confirmed by typing on would otherwise redraw the next reading at the pointer.
191 lines
6.8 KiB
Markdown
191 lines
6.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 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` on a reading without candidates commits it and
|
|
types nothing. `Backspace` and `Esc` on a chosen candidate go back to the
|
|
reading. In a temporary Emoji or Hanja search, `Enter` commits the
|
|
highlighted result and `Tab`/`Shift-Tab` wrap through the results. Leaving
|
|
the field or clicking elsewhere commits what is pending; `Esc` cancels it.
|
|
|
|
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. `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.
|