on-screen keyboard
git clone https://git.lucas.co/cce-keyboard.git
CLAUDE.md (3.4K)
1 # cce-keyboard
2
3 The on-screen keyboard. Read the workspace guide (`../cce-compositor/WORKSPACE.md`)
4 first; this file covers only what is particular to this crate.
5
6 ## Shape
7
8 - `src/main.rs` — the `Application`: an Overlay-layer surface anchored to the
9 bottom edge, `keyboard_interactivity none`, root plate with one control
10 plate per key (raised keycap at rest, flush while held or latched, rim lit
11 while locked). Single instance via `cce_ui::ipc::instance`;
12 `cce-keyboard [toggle|show|hide]`, and hiding exits.
13 - `src/layout.rs` — the key table (evdev codes, unit widths, the Fn layer)
14 and the pure geometry (`place`, `hit`). Unit-tested; no Wayland.
15 - `src/keymap.rs` — compiles the session's default keymap with
16 libxkbcommon (empty RMLVO, the same defaults `cce-compositor`'s
17 `xkb_config.rs` uses) and reads the character keys' labels from it.
18 - `src/vkbd.rs` — `zwp_virtual_keyboard_v1` on a **second Wayland
19 connection** of its own. The protocol has no events, so nothing needs
20 dispatching, and keeping it off the runner's `EngineState` means cce-ui
21 needed no change.
22
23 ## Things that are deliberate
24
25 - **No key repeat here.** The compositor gives virtual keyboards repeat info
26 (`keyboard.rs` `DEFAULT_REPEAT_*`) and the focused client repeats a held
27 key itself; the board just keeps the key down while the pointer does.
28 - **Modifiers are pressed lazily**, around the next key, not when latched.
29 A latched Super must not hold the compositor in its Super-held adjust mode.
30 Both the modifier key events and an explicit `modifiers` mask are sent.
31 - **The board fits the smallest output** (`Config::fit`, via `ccectl outputs
32 --json`): the compositor *destroys* a layer surface whose exclusive zone
33 leaves less than half the output (`layer_shell.rs`, river's rule). A
34 280px board on a 360px-tall scale-2 shadow output vanished on map before
35 this.
36 - **The key gap is capped at 15% of the row pitch**, never wider than the
37 ladder's `control_gap()`: the ladder spaces rows of buttons, and on a
38 dense grid its gap ate a third of every key.
39
40 ## Shown by a touched field
41
42 The compositor runs `cce-keyboard show` when a touch activates a
43 text-input-v3 field and `cce-keyboard hide` when that field lets go
44 (`cce-compositor`'s `osk.rs`; `window_manager { osk_on_touch }`). cce-ui
45 widgets announce their fields through `cce_ui::text_input::claim`. The board
46 does not have to do anything for this: it stays a virtual keyboard, and a
47 tap on it does not take focus, so the field stays enabled while it types.
48
49 ## Depends on a compositor fix
50
51 A click on a layer surface used to give it keyboard focus whatever its
52 `keyboard_interactivity` (`cursor.rs`, button and touch paths), which took
53 focus off the window being typed into on the first key. Fixed by
54 `layer_takes_click_focus` in cce-compositor; a session on an older `cce-fx`
55 shows the board, latches modifiers, and types nothing.
56
57 ## Verifying
58
59 Shadow only (never run a build from the plain shell):
60
61 ```sh
62 cce-shadow start --new --bin /abs/path/target/release/cce-fx
63 cce-shadow spawn /home/lsgalante/.local/bin/cce-text-editor
64 cce-shadow spawn env CCE_FONTS_DIR=… CCE_ICONS_DIR=… /abs/path/target/release/cce-keyboard
65 cce-shadow ctl pointer-move-to <x> <y>; cce-shadow ctl pointer-click
66 ```
67
68 Check `ctl windows` still shows the editor `focused=true` after clicking keys,
69 and do a `--scale 2` pass (pointer coords are logical: shot px ÷ 2).