Expand description
An on-screen keyboard for panels that have no other one.
§It is not a special case
The point of this crate is that nothing downstream of it can tell the
difference between a key tapped here and a key pressed on a keyboard plugged
into the machine. denise splits keyboard input into two events —
InputEvent::Key, a physical position, and InputEvent::Text, a
character somebody meant to insert — and the hardware path in denise-evdev
emits the first followed by whatever the second turns out to be.
Keyboard::press emits the same two events, in the same order, produced by
the same Composer from the same Layout tables. The application hands
them to Ui::handle, which is the call the hardware path’s events arrive
through as well. So a TextInput inserts them without knowing, a key
binding on Enter fires exactly as it would, and every widget that already
handles keys handles these.
That is worth stating because the alternative is so tempting: a method on the text field that inserts a character directly. It would work, and then Enter would do nothing, Escape would do nothing, and every widget that is not a text field would be deaf to the keyboard.
§It is built from widgets
Every key is a Button — Button::no_focus, so pressing one does not
move the caret out of the field being typed into. They sit on a
Ui::push_shelf, which slides up from the bottom without pushing a scene,
so the field keeps focus while the keyboard is up. Neither of those is a
keyboard feature; they are toolkit features this is the first user of.
§Modifiers
Shift is a one-shot: armed by a tap and spent by the next key. There is no clock in the press path, so no double-tap window could latch it — and none is wanted, because Caps Lock has a key of its own where Caps Lock goes.
Caps is a latch and not a held Shift: it applies to letters and leaves the
digit row alone, which is the difference between a locked keyboard typing
1 and typing !, and caps over shift gives lower case the way a hand
expects. The Composer models that already, so it is latched with a
CapsLock key rather than reimplemented here. Ctrl is a one-shot too, and
reaches the events it modifies.
Every key that changes what the next press means says which state it is
in, and the number and punctuation keys carry what Shift would give in a
small second legend — the ! over the 1. Letters do not: a capital Q
over a q is not news.
The keys whose meaning is a name are drawn rather than lettered — see
icons — which is why they look the same on a machine with no fonts
installed as on one with DejaVu.
The third level is the layout’s own AltGr rather than a page of symbols
chosen here, because there is no such page to choose: @ is AltGr+2 on a
Norwegian keyboard and Shift+2 on a US one, and a fixed grid would be
wrong on one of them. It latches, since a finger cannot hold one key and
press another.
§Layouts
Keyboard::from_system starts from whatever the machine is configured
for, which is the answer the hardware path starts from too — so a panel with
a keyboard plugged into it and one without agree about what the ; position
types. It hands back a LayoutSource, and
LayoutSource::Unknown is the one
worth showing somebody: the system asked for a layout there is no table for
and got US.
The layout key walks the built-ins. Switching reletters the keys where
they stand rather than rebuilding them, because a position does not move
when the layout changes — KeyCode::Semicolon is where ø lives on
Norwegian and ö on German, and it is the same key.
Switching the keyboard does not switch a physical keyboard attached to the
same machine. An application that wants both in step calls
InputBackend::set_layout as well; the toolkit does not couple them,
because it does not know the two are meant to agree.
§The shape of it
A compact physical keyboard rather than a phone one: fourteen columns,
Backspace top right, Tab opening the second row, Enter closing the home row,
Shift at both ends of the bottom one. A panel is something somebody stands
in front of and types an address into, so the digits stay on screen instead
of going behind a 123 page, and Tab is how a form gets crossed.
The width is what makes the layouts complete — see ROWS for which
positions carry what, and why a narrower grid could not type å.
§Holding a key
Backspace repeats while it is held and nothing else does, which is what a
phone does and what stops a slow finger typing aaaaaa. Keyboard::tick
collects what a held key has earned, once a frame; it costs nothing when
nobody is touching one, because a repeating key asks the tree to wake it
only between its press and its release.
Holding a letter offers its alternates instead — é è ê ë over the e,
in a framed strip above the key, chosen by where the finger lifts. The
characters come from the layout, so they change when it does. That gesture
needs the application’s help for one call: see Keyboard::handle.
A field focused under the keyboard is scrolled clear of it where it sits in
something that scrolls; where it does not, Keyboard::occluded says what
to move it clear of.
Modules§
- icons
- The keys’ pictures, drawn rather than looked up in a font.
Structs§
- Key
- One key in the grid.
- Keyboard
- An on-screen keyboard, and the composition state that goes with it.
- Row
- One row of keys.
Enums§
- Shift
- What the Shift key is currently doing.
Constants§
- HOLD_MS
- How long a letter is held before it offers its alternates.
- KEY_GAP
- Space between keys, and around the edge of the shelf.
- KEY_
HEIGHT - Height of one key, in logical pixels.
- REPEAT_
DELAY_ MS - How long Backspace waits before it starts deleting on its own.
- REPEAT_
INTERVAL_ MS - How often it deletes after that.
Statics§
- ROWS
- The grid, top row first.