Skip to main content

Crate denise_keyboard

Crate denise_keyboard 

Source
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.