Keyboard Events and Handlers


Alexa Presentation Language (APL) provides support for keyboard events and handlers.

About keyboard support

KeyUp and KeyDown keyboard events are generated for each press and release of a key on the keyboard. They normally come in pairs; each KeyDown will be followed (eventually) by a matching KeyUp. Please note that:

  • All keys generate KeyUp and KeyDown events. This includes modifier keys such as "shift" or "control".
  • Keyboards (and keys) supporting auto-repeat will generate a series of KeyDown events while the key is held down, followed by a single KeyUp event when the key is released. Not all keys support auto-repeat. For example, the "shift" key does not auto-repeat.
  • Due to operating system implementations we can't guarantee that every KeyDown event will always be followed by a KeyUp event.

KeyUp and KeyDown keyboard events are passed to the currently focused component. A custom keyboard handler attached to the component specifies the specific keys that will trigger command sequences. The custom keyboard handler also decides if the keyboard event should be passed on for additional processing.

Any keyboard events that are not consumed by the custom keyboard handlers are passes on to the next component in the component hierarchy. Events not consumed by component handlers are passed to the document's custom keyboard handler. When no component is in focus, the document keyboard handler receives all keyboard events.

A short example may help clarify this behavior. Consider a Sequence with a series of TouchWrapper buttons arranged vertically. Assume that one of the buttons is in focus. The user presses the w key. The following steps happen:

  1. A KeyDown event with keyboard.key = "w" is created.
  2. The event is passed to the custom keyboard handler of the touch wrapper component, if it exists (we'll assume that it doesn't).
  3. The next component in the hierarchy above this touch wrapper is the sequence.
  4. The event is passed to the custom keyboard handler of the sequence, if it exists (assume that it doesn't).
  5. The event is passed to the custom keyboard handler of the document, if it exists.

A different key (such as MediaPlayPause) would not be handled by the sequence and would next be passed to the custom document key handler.

Keyboard Event

A keyboard event is a message sent to the focused component or to the document. A keyboard event specifies exactly which key on the keyboard was pressed or released to generate the event.

Keyboard events come in two types: keyDown and keyUp. A keyDown event is generated whenever a key is pressed on the keyboard or when a key auto-repeats. A keyDown event is generated for all keys; for example, pressing the "shift" key will generate a keyDown event. A keyUp event is generated whenever a key is released on the keyboard.

The data in the keyboard event includes what key was pressed, if this was due to an auto-repeat, and any modifier keys that were held down when this key was pressed. For example, pressing and holding the "6" key on a keyboard might generate:

{
  "key": "6",
  "code": "Digit6",
  "repeat": true,
  "shiftKey": false,
  "altKey": false,
  "ctrlKey": false
  "metaKey": false,
}

The following properties are reported in the keyboard event:

Name Type Description
altKey Boolean True if the "alt" key was pressed when the event occurred. ("option" on OS X)
code String The string representation of the physical key on keyboard.
ctrlKey Boolean True if the "control" key was pressed when the event occurred.
key String The string representation of key pressed on the keyboard, taking into account modifier keys.
metaKey Boolean True if the "meta" key was pressed when the event occurred. On Windows keyboards this is the "Windows" key. On Macintosh keyboards this is the "command" key.
repeat Boolean True if this key is being held down so it auto-repeats.
shiftKey Boolean True if the "shift" key was pressed when the event occurred.

altKey

The altKey Boolean value is true if the ALT key was pressed when this event occurred. The ALT key in OS X is the "option" key. Please note that pressing the ALT key on a keyboard itself generates a keyboard event. For example, pressing the combination ALT-4 on a OS X keyboard generates the following keyboard events:

KeyDown( code='AltLeft', key='Alt', repeat=false, altKey=true, ctrl/shift/metaKey=false )
KeyDown( code='Digit4', key='¢', repeat=false, altKey=true, ctrl/shift/metaKey=false )
KeyUp( code='Digit4', key='¢', repeat=false, altKey=true, ctrl/shift/metaKey=false )
KeyUp( code='AltLeft', key='Alt', repeat=false, altKey=false, ctrl/shift/metaKey=false )

code

The code property represents a physical key on the keyboard that was pressed. Code values are strings and are defined in the W3C Candidate Recommendation for UI Events KeyboardEvent code values.

Sample code values include:

Digit2               The "2" key
KeyF                 The "F" key
Backslash            The "\" key
Semicolon            The ";" key
AltLeft              The "alt" key to the left of the space bar
ShiftRight           The "shift" key to the right of the space bar
MediaPlayPause       Media play/pause key (normally found on a remote control)
AudioVolumeDown      Audio volume down key

ctrlKey

The ctrlKey Boolean value is true if the control key was pressed when this event occurred. Please note that pressing the control key on a keyboard itself generates a keyboard event. For example, pressing the combination control-m on a OS X keyboard generates the following keyboard events:

KeyDown( code='ControlLeft', key='Control', repeat=false, ctrlKey=true, alt/shift/metaKey=false )
KeyDown( code='KeyM', key='m', repeat=false, ctrlKey=true, alt/shift/metaKey=false )
KeyUp( code='KeyM', key='m', repeat=false, ctrlKey=true, alt/shift/metaKey=false )
KeyUp( code='ControlLeft', key='Control', repeat=false, ctrlKey=false, alt/shift/metaKey=false )

key

The key property is one of the following:

  1. A key string corresponding to the character typed by the user, taking into account locale, modifiers, and any keyboard overrides that are in effect. In this circumstance, one can think of the key property as being the text that would be entered into a text input area.
  2. A named key attribute value, as defined in the W3C candidate recommendation. In this circumstance, one can think of the key property as being a convenient label for what the key would do (such as "Tab").

Key values are strings and are defined in the W3C Candidate Recommendation for UI Events KeyboardEvent key values.

Sample key values include:

6                 The number "6"
&                 The shifted version of the "7" key (on an American keyboard)
¢                 The alt version of the "4" key (on OS X)
Delete            Forward delete
Shift             A shift key (could be either one)
BrightnessDown    A brightness control key
MediaPlayPause    Media play/pause key (normally found on a remote control)

The following key values are reserved for future versions of APL: 'GoBack', 'Enter', 'Tab', 'Tab', 'ArrowUp', 'ArrowDown', 'ArrowRight', 'ArrowLeft', 'Home', 'End'

metaKey

The metaKey Boolean value is true if the meta key was pressed when this event occurred. Please note that pressing the meta key on a keyboard itself generates a keyboard event. For example, pressing the combination meta-/ on a OS X keyboard generates the following keyboard events:

KeyDown( code='MetaLeft', key='Meta', repeat=false, metaKey=true, alt/ctrl/shiftKey=false )
KeyDown( code='Slash', key='/', repeat=false, metaKey=true, alt/ctrl/shiftKey=false )
KeyUp( code='MetaLeft', key='Meta', repeat=false, metaKey=false, alt/ctrl/shiftKey=false )

It's helpful to note in this example that OS X does not deliver a KeyUp event for the slash key; the operating system absorbs the event and it does not get delivered. In general one should be careful about assuming that all KeyUp and KeyDown events will be delivered, particularly when modifier keys are involved.

repeat

The repeat Boolean value is true if a KeyDown event is auto-repeating. The first KeyDown event for a key will have repeat set to false. Each additional KeyDown event for the same key will have repeat set to true.

Note that (a) the repeat rate is controlled by the device, (b) not all devices will send repeat events, and (c) some keys such as modifier keys never send a repeat event.

shiftKey

The shiftKey Boolean value is true if the shift key was pressed when this event occurred. Please note that pressing the shift key on a keyboard itself generates a keyboard event. For example, pressing the combination shift-m on a OS X keyboard generates the following keyboard events:

KeyDown( code='ShiftLeft', key='Shift', repeat=false, shiftKey=true, alt/ctrl/metaKey=false )
KeyDown( code='KeyM', key='M', repeat=false, shiftKey=true, alt/ctrl/metaKey=false )
KeyUp( code='KeyM', key='M', repeat=false, shiftKey=true, alt/ctrl/metaKey=false )
KeyUp( code='ShiftLeft', key='Shift', repeat=false, shiftKey=false, alt/ctrl/metaKey=false )

Keyboard Event Handlers

Keystrokes are handled in two ways in APL documents. The first mechanism is through default behaviors associated with actionable components including TouchWrapper, ScrollView, Sequence, Pager, and focus selection (Actionable component). The second mechanism is through keyboard event handlers assigned to actionable components and the base document.

Each actionable component and the root APL document have the following properties in addition to their standard properties:

Property Type Default Styled Dynamic Description
handleKeyDown Array of key handlers [] No No Handlers to check on key down events.
handleKeyUp Array of key handlers [] No No Handlers to check on key up events.

A single key handler is an object with the following properties:

Property Type Default Description
commands Array of commands [] Commands to run if this handler is invoked.
propagate Boolean false If true, handled events are bubbled up.
when Boolean true If true, invoke this handler

The array of key handlers is checked in order. The first key handler with a true when clause is invoked. The commands in that handler run. If the propagate property is true, the event bubbles to the next component (not the next handler in the array). Please note that the bubbling happens immediately, generally before the commands run.

For example, to support a 2D game-style controller (perhaps to move an image around on the screen), a touch wrapper may be extended as follows:

{
  "type": "TouchWrapper",
  "bind": [
    { "name": "x", "value": 0 },
    { "name": "y", "value": 0 }
  ],
  "handleKeyDown": [
    {
      "when": "${event.keyboard.code == 'KeyW'}",
      "commands": [
        {
          "type": "SetValue",
          "property": "y",
          "value": "${y - 10}"
        },
        {
          "type": "SetValue",
          "property": "transform",
          "value": [ { "translateX": "${x}", "translateY": "${y}" } ]
        }
      ]
    },
    {
      "when": "${event.keyboard.code == 'KeyS'}",
      "commands": [
        {
          "type": "SetValue",
          "property": "y",
          "value": "${y + 10}"
        },
        {
          "type": "SetValue",
          "property": "transform",
          "value": [ { "translateX": "${x}", "translateY": "${y}" } ]
        }
      ]
    },
    {
      "when": "${event.keyboard.code == 'KeyA'}",
      "commands": [
        {
          "type": "SetValue",
          "property": "x",
          "value": "${x - 10}"
        },
        {
          "type": "SetValue",
          "property": "transform",
          "value": [ { "translateX": "${x}", "translateY": "${y}" } ]
        }
      ]
    },
    {
      "when": "${event.keyboard.code == 'KeyD'}",
      "commands": [
        {
          "type": "SetValue",
          "property": "x",
          "value": "${x + 10}"
        },
        {
          "type": "SetValue",
          "property": "transform",
          "value": [ { "translateX": "${x}", "translateY": "${y}" } ]
        }
      ]
    },
    {
      "when": "${event.keyboard.code == 'Enter'}",
      "description": "Block the normal 'enter' behavior"
    }
  ],
  "items": {
    "type": "Image",
    "source": "...."
  }
}

Was this page helpful?

Last updated: Nov 28, 2023