Input method
Type CJK or composed text. It is off by default: if you type Chinese, Japanese, Korean or rely on compose, enable the engine; otherwise leave it off.
programs.scoot.desktop = { enable = true; # An engine for CJK and compose (nothing runs until you set this): inputMethod.enable = true; # Pinyin beside the built-in keyboard layouts: # inputMethod.addons = with pkgs.qt6Packages; [ fcitx5-chinese-addons ];};What runs: fcitx5 as scoot-input-method. in
scoot-session. (so no other desktop starts it), owning the
input-method-v2 seat the compositor’s
text-input clients
talk to. The engine holds nothing periodic: no polling, no watchers. It wakes
on protocol events and D-Bus calls only. A look themes its candidate
window (below); without one fcitx5’s own theme stands.
Engines, measured at the pinned rev (8ce4ef6, aarch64-linux): full
closures by nix path-info --closure-size against the binary cache:
| Engine | Version | Full closure | Speaks input-method-v2 |
Verdict |
|---|---|---|---|---|
| fcitx5 | 5.1.21 | 437.4 MiB | yes: its wayland frontend binds the seat (proven live on the M2, below) | the slot |
| ibus | 1.5.34 | 1.10 GiB | no — it speaks its own D-Bus protocol (what GNOME’s compositor integrates with); it never binds the Wayland global | out |
| kime | 3.1.1 | 1.02 GiB | no — Korean-only, and on the v1/virtual-keyboard path, not input-method-v2 |
out |
| uim | 1.9.6 | 432.5 MiB | no — XIM only, so native Wayland clients get nothing | out |
Closure size alone would leave uim standing (about the same as
fcitx5); the protocol decides it. On a pure-Wayland scoot session
only fcitx5 speaks to a native client. The default package is plain
fcitx5 (keyboard layouts, compose and the XIM server for XWayland, no
CJK data); a CJK engine rides inputMethod. beside it (pinyin
costs another ~1.52 GiB of closure at the pinned rev). The
fcitx5-with-addons wrapper (Qt5, Qt6 and GTK input-panel plugins
plus the config GUI) is not the default: its closure is wider than
ibus, while GTK3/4 and Qt 6.8+ talk to the engine over text-input with
no plugin at all.
The toolkit variables, only where a toolkit still needs them (checked against fcitx’s own Using Fcitx 5 on Wayland):
| Variable | Value | Who still needs it |
|---|---|---|
XMODIFIERS |
@im=fcitx |
X11/XWayland clients (XIM is unchanged under XWayland) |
QT_IM_MODULE |
fcitx |
Qt5 and Qt6 before 6.8 (whose Wayland platform speaks only text-input-v2, which no compositor but KWin offers) |
QT_IM_MODULES |
wayland;fcitx |
Qt 6.7 and later (tries the native text-input first, falls back to the fcitx module, so the candidate popup stays compositor-placed where the toolkit allows it) |
GTK_IM_MODULE |
deliberately unset | nobody: with it unset GTK3/4 use their Wayland text-input natively, which is the path the compositor places the popup for |
The variables land in the user-manager environment (so user units
and D-Bus-activated apps inherit them) and in login shells. A value
you set wins over each default. SDL_IM_MODULE stays unset too:
SDL2 on Wayland needs none, and its X11 build reads XIM through
XMODIFIERS.
The candidate window follows the look: a generated scoot-look
classic-UI theme (unselected text in the look’s foreground, the
selected row in its accent with the background on top (the AA
pairing the bar is measured against), the input string in the
accent) plus a two-line classicui. naming it for both the
light and the dark path (fcitx5 follows the portal’s dark scheme
under a prefer-dark look, which is every look but music-desk).
theme. keeps fcitx5’s own style
while the rest follows the look. The Sans faces in the theme
resolve through fontconfig, so with the theme child’s fonts
target they follow the look’s UI sans.
Adding the languages yourself: open the config GUI
(fcitx5-config-qt from qt6Packages.) or edit
~/. by hand, and add the engine to the group,
e.g. pinyin beside keyboard-us:
[Groups/0/Items/1]Name=pinyinLayout=Then trigger the engine (Ctrl+Space by default) and type. The
candidate list opens at the cursor, placed by the compositor over
the text-input surface (protocols).
Every value is an option, applied on rebuild/switch (the unit
restarts into a new theme; a new engine or addon rewrites
ExecStart and restarts it; no re-login):
| Option | Type | Default | Meaning |
|---|---|---|---|
desktop. |
bool | false (opt-in, never with the profile) |
run the engine as a user unit |
desktop. |
enum ("fcitx5") |
"fcitx5" |
the engine behind enable (a future engine widens this enum, the option staying as it is) |
desktop. |
list of packages | [ ] |
CJK engines and toolkit plugins beside the core (pinyin, mozc, hangul, the Qt5 input-panel plugin); empty keeps keyboard layouts, compose and XIM with no CJK data |
desktop. |
package or null | fcitx5 (Linux-only: null off Linux) | point at your own engine build (it must speak input-method-v2); null with the switch on fails evaluation naming it |
desktop. |
bool | true |
theme the candidate window from the look; false keeps fcitx5’s own style |
programs.scoot.desktop = { enable = true; inputMethod.enable = true; # Japanese and Korean beside pinyin: # inputMethod.addons = [ pkgs.fcitx5-mozc pkgs.fcitx5-hangul ]; # The candidate window keeps fcitx5's own theme: # theme.targets.inputMethod.enable = false;};To try it headless, enable the slot with pinyin in addons, start a
headless session, open foot, trigger the engine and type nihao. The
screenshot shows the committed 你好 and, mid-word, the candidate list
at the cursor. The acceptance run below proves
the binding live on the M2. Full CJK typing stays a manual step until
a headless text-input client ships.
Trying it headless
Section titled “Trying it headless”Proven live on the M2 against headless scoot (installed 0.,
IPC protocol 10): fcitx5 5.1.21 started with the slot’s shape (user
unit past the session target, no polling) binds the seat:
- scoot advertises
zwp_input_method_manager_v2(global, version- and fcitx5 binds it (
wl_registry., on the wire underbind WAYLAND_DEBUG=1);
- and fcitx5 binds it (
- fcitx5 loads
waylandimand creates its classic UI for the Wayland display (classicui.).cpp: Created classicui for wayland display
This does not yet prove composing a CJK string through the engine into a client. Do that by hand, once, on any box with a display:
- Enable the slot with pinyin beside the core:
inputMethod.andenable = true inputMethod., rebuild/switch.addons = with pkgs. qt6Packages; [ fcitx5-chinese-addons ]; systemctl --user status scoot-input-methodis active;echo $XMODIFIERSprints@im=fcitx.- Open foot, press
Ctrl+Space(the engine triggers), typenihao: the candidate list opens at the cursor in the look’s colors (scoot-looktheme),1commits 你好. - Repeat in a GTK app (Text Editor) and a Qt app: both commit
over text-input with the popup placed by the compositor; an
XWayland app (e.g.
xterm) commits over XIM instead.
Troubleshooting, by symptom:
- Only US-English types,
Ctrl+Spacedoes nothing. The engine runs but your group holds no CJK engine: the default package ships keyboard layouts only. Add the engine toaddonsand to the fcitx5 group (config GUI or~/., above), then trigger it. Check the unit first:config/fcitx5/profile systemctl --user status scoot-input-method, and that it started with the display (a hand-started session must reachscoot-session.withtarget WAYLAND_DISPLAYimported, on the desktop page). - The candidate list never opens (commits land as plain
ASCII). The client is not on the text-input path: an XWayland
app reads XIM (check
XMODIFIERSin its environment), a Qt5 app reads the fcitx module (checkQT_IM_MODULE, and that its plugin is installed; the Qt5 input-panel plugin ridesaddons, not the default package). GTK3/4 and Qt 6.8+ need neither: with the variables above they commit over text-input. - Candidates open at the wrong place (or blink). Something set
GTK_IM_MODULE=fcitxglobally: GTK then renders the popup in-process instead of letting the compositor place it. Unset it (this slot never sets it) and keep the toolkit default. - The engine runs inside the wrong desktop. It cannot: the unit
is wanted by
scoot-session., which only a scoot session reaches.target systemctl --user status scoot-input-methodshows the scope it started in. - Two engines fight over the seat. Only one client owns
input-method-v2per seat. Turn the other one off (IBus, another fcitx5 from a second session, or a desktop portal’s own daemon); whichever stays owns every text-input client. - Qt6 routes through the fcitx module instead of text-input.
Where
QT_IM_MODULEis read first the module path still commits, andQT_IM_MODULES="wayland;fcitx"prefers the native path on Qt 6.7+. UnsetQT_IM_MODULEfor that app alone if you want the compositor-placed popup unconditionally and never run Qt5 there.
