From 3acce003eb6824fd043d8094ce47eebee610e15f Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 19 Jun 2023 11:14:35 +0100 Subject: [PATCH 1/4] Create keyboard-accessibility.md This mostly describes the status-quo with a few suggestions for change. --- input/keyboard-accessibility.md | 100 ++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 input/keyboard-accessibility.md diff --git a/input/keyboard-accessibility.md b/input/keyboard-accessibility.md new file mode 100644 index 0000000..465c87e --- /dev/null +++ b/input/keyboard-accessibility.md @@ -0,0 +1,100 @@ +Keyboard accessibility +====================== + +- Pull request: TODO + +**Scope:** keyboard navigation, focus, mnemonics, shortcuts + +**Status:** partial implementation + +Introduction +------------ + +This is a specific sub-set of accessibility, including: + +- Tab-key navigation +- Focus-specific key handling (e.g. use of arrow keys to move a slider) +- Mnemonics (e.g. pressing Alt+F to open the File menu) +- Context-sensitive shortcuts (e.g. Ctrl+C to copy the focussed/selected item) +- Global shortcuts (e.g. Ctrl+P to print a page) +- Following platform conventions (e.g. Ctrl+C on Linux/Windows, Command+C on MacOS) + +Excluded: + +- Screen reader and use of other external accessibility tools (this is a separate issue) +- Focus indication: this comes under theme design + +This document discusses what interaction should be supported and the implementation status, with minimal discussion of how. + + +Tab-key navigation +------------------ + +### Requirements + +- That there is a *keyboard focus* (implemented: `EventState::nav_focus`) +- That widgets can define whether they are a valid navigation target (implemented: `navigation` method/property) +- Pressing Tab advances to the next valid widget, and Shift+Tab does the reverse (implemented) +- That container widgets can specify the navigation order of their children (implemented: `Widget::nav_next` method) +- That special UIs (e.g. a small `calculator` or a spreadsheet) can disable Tab-key navigation (implemented) +- That when a widget receives navigation focus it is notified (implemented: `Event::NavFocus`) and made visible (implemented: special handling of `Event::NavFocus` to scroll as required; is a bit hacky) + +### Large containers + +If e.g. a 1000-element list has navigable items, this interacts poorly with Tab-key navigation. Applicable Kas examples are `data-list`, `data-list-view` and `times-tables`. Some apps (e.g. spreadsheets) will provide their own navigation for such cases, but we should aim to provide a decent experience by default. + +The status quo: + +- The `List` widget (used in `data-list`) is not intended for very long lists and interacts with Tab-navigation like other containers +- The `ListView` and `MatrixView` widgets (used in `data-list-view` and `times-tables`) have several special features: + - Tab-navigation where the prior focus is not a child jumps to the first mapped item (i.e. the first visible item, or only just outside the visible range). + - Tab-navigation where the prior focus is a child scrolls as necessary to focus the next item, until the end of the list (the "obvious" behaviour). + - The navigation keys Home, End, arrow-keys, PageUp, PageDown may be used to navigate the list + +### Interaction with mouse/touch + +Clicking on / touching a widget will assign navigation focus to that widget. + + +Focus-specific key handling +--------------------------- + +It is expected that e.g. a slider with navigation focus may be adjusted with the arrow keys and that Home may be used to navigate a list. + +This is implemented, roughly as follows: + +- If any widget (usually an `EditField`) has claimed keyboard input focus, key events go there; otherwise... +- A sub-set of keyboard keys map to a special enum, [`Command`](https://docs.rs/kas/latest/kas/event/enum.Command.html) +- A `Command` is sent to the widget with navigation focus (e.g. if Home is pressed and the focus is a `Slider`, that widget handles the event) +- If unused, the [event handling model](https://docs.rs/kas/latest/kas/event/index.html#event-handling-model) gives each ancestor a chance to use the event during unwinding (so e.g. if Home is pressed but the focussed widget does not use it, but is part of a `ListView`, then that may navigate to the start of the list) + + +Mnemonics +--------- + +Mnemonics are supported by [`AccelString`](https://docs.rs/kas/latest/kas/text/struct.AccelString.html) used in [`AccelLabel`](https://docs.rs/kas/latest/kas/widgets/struct.AccelLabel.html). + +So far, mnemonics function by registering themselves during configure/init. All mnemonics in the current "page" are active. This is likely to change (see below). + + +Shortcuts +--------- + +Context-local shortcuts are implemented by using a platform-specific map to convert the key-sequence to a [`Command`](https://docs.rs/kas/latest/kas/event/enum.Command.html), then sending that `Command` to the keyboard focus (see above). + +This system is under-developed, especially regarding custom (app-specific) shortcuts and global shortcuts. + + +Alternatives +------------ + +Probably Tab-navigation on a `ListView` should jump to the first visible item, not the first mapped item (which may be just outside the visible range). This is a small bug/TODO. + +Possibly mnemonics should be supported by all labels instead of just `AccelLabel`. + +Mnemonics should be restricted to only visible widgets and not require registration. Proposal: + +- Add a method to iterate over all visible descendants +- When any mnemonic key is pressed (Alt + letter/number), iterate over visible widgets to find a possible handler. This should be fast enough since the number of widgets visible on screen is typically quite limited. It fixes the current issue that a mnemonic from a different page of a `TabStack` could activate. It *might* need special casing for scrolling (e.g. if a menu or configuration page has to be scrolled). + +Alternative: mnemonics should show an underline whenever Alt is pressed; they could temporarily register themselves when this happens (as part of the draw call?). Probably not a good alternative. From 3097347297f073aff3dc6dbdc0ecdf801ec4f413 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 19 Jun 2023 11:15:53 +0100 Subject: [PATCH 2/4] Fix PR link --- input/keyboard-accessibility.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input/keyboard-accessibility.md b/input/keyboard-accessibility.md index 465c87e..6354e98 100644 --- a/input/keyboard-accessibility.md +++ b/input/keyboard-accessibility.md @@ -1,7 +1,7 @@ Keyboard accessibility ====================== -- Pull request: TODO +- Pull request: https://github.com/kas-gui/design/pull/4 **Scope:** keyboard navigation, focus, mnemonics, shortcuts From 2596de997898ddb7634d9629e93fd23009c33566 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 19 Jun 2023 11:31:25 +0100 Subject: [PATCH 3/4] Add alternative Tab-navigation behaviour --- input/keyboard-accessibility.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/input/keyboard-accessibility.md b/input/keyboard-accessibility.md index 6354e98..ecd267b 100644 --- a/input/keyboard-accessibility.md +++ b/input/keyboard-accessibility.md @@ -90,6 +90,26 @@ Alternatives Probably Tab-navigation on a `ListView` should jump to the first visible item, not the first mapped item (which may be just outside the visible range). This is a small bug/TODO. +### Alternate Tab-navigation style + +A short press of Tab or Shift+Tab behaves like usual. Holding Tab instead activates a special "navigation mode": + +- While Tab is held, focus is indicated via an extra box/highlight. Focus does not move (no key repeat). +- Tab+Esc moves focus to the parent (or none) +- Tab + arrow keys moves focus in the appropriate direction (requires a new method, `spatial_nav`) +- Tab + Home/kbd> or End moves focus to the first/last child of its container (possibly using event-handling's unwinding, i.e. the first ancestor to handle `TabHome` moves focus). +- Tab + PageUp/kbd> or PageDown moves focus within a container + +Advantage: if well implemented this might be intuitive and much easier to use, at least in some cases. + +Disadvantage: non-standard. + +Disadvantage: not trivial to implement (but should be viable). + +Disadvantage: it is possible that some widgets would be hard or impossible reach. A few cases might cause problems, e.g. floats (widgets on top of one another). + +### Mnemonics alternatives + Possibly mnemonics should be supported by all labels instead of just `AccelLabel`. Mnemonics should be restricted to only visible widgets and not require registration. Proposal: From db0847aaec465e44fe320229f37ca8fb83b1f285 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Wed, 30 Aug 2023 15:20:02 +0100 Subject: [PATCH 4/4] Remove mnemonics which are covered by a separate PR --- input/keyboard-accessibility.md | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/input/keyboard-accessibility.md b/input/keyboard-accessibility.md index ecd267b..6466312 100644 --- a/input/keyboard-accessibility.md +++ b/input/keyboard-accessibility.md @@ -3,7 +3,7 @@ Keyboard accessibility - Pull request: https://github.com/kas-gui/design/pull/4 -**Scope:** keyboard navigation, focus, mnemonics, shortcuts +**Scope:** keyboard navigation, focus, shortcuts **Status:** partial implementation @@ -72,9 +72,7 @@ This is implemented, roughly as follows: Mnemonics --------- -Mnemonics are supported by [`AccelString`](https://docs.rs/kas/latest/kas/text/struct.AccelString.html) used in [`AccelLabel`](https://docs.rs/kas/latest/kas/widgets/struct.AccelLabel.html). - -So far, mnemonics function by registering themselves during configure/init. All mnemonics in the current "page" are active. This is likely to change (see below). +See [#8: Access Keys](https://github.com/kas-gui/design/pull/8). Shortcuts @@ -107,14 +105,3 @@ Disadvantage: non-standard. Disadvantage: not trivial to implement (but should be viable). Disadvantage: it is possible that some widgets would be hard or impossible reach. A few cases might cause problems, e.g. floats (widgets on top of one another). - -### Mnemonics alternatives - -Possibly mnemonics should be supported by all labels instead of just `AccelLabel`. - -Mnemonics should be restricted to only visible widgets and not require registration. Proposal: - -- Add a method to iterate over all visible descendants -- When any mnemonic key is pressed (Alt + letter/number), iterate over visible widgets to find a possible handler. This should be fast enough since the number of widgets visible on screen is typically quite limited. It fixes the current issue that a mnemonic from a different page of a `TabStack` could activate. It *might* need special casing for scrolling (e.g. if a menu or configuration page has to be scrolled). - -Alternative: mnemonics should show an underline whenever Alt is pressed; they could temporarily register themselves when this happens (as part of the draw call?). Probably not a good alternative.