Keyboard events in Firefox OS TV

Getting started

The behavior of input events via hardware keys in Firefox OS varies widely from app to app. Early smartphones came with a limited number of keys — Power, Home, Volume up, Volume down — so it was easy for the software to determine an appropriate response for each keypress event. However, Smart TV remotes now come with many hardware keys, and defining the appropriate behavior when a key is pressed has become an important issue on the Firefox OS TV platform. If a hardware key on a smart remote can be used both by apps and by the system, it’s important to determine which response is triggered when the key is pressed.

This post will introduce the challenges of programming a TV remote to manage keyboard events on the Firefox OS Smart TV platform. We’ll classify keyboard events into four scenarios and describe these dispatch scenarios and how they interact. This is the first of two posts about keyboard events for Firefox OS Smart TV. In a followup Part 2 post, we’ll drill down into the implementation details and and take a look at sample code for event handling on the TV remote.

f1

[Fig 1]

We begin with the ‘Info’ key on a TV remote. Often, it’s used by the hardware to display system information, although it’s possible for an application to use the same key to display app information. When a user presses the key, what action will be shown on screen — system info or app info?

Four keyboard event scenarios

To determine the appropriate behavior when hardware keys are pressed, we start by describing four scenarios for keyboard events.

Scenario Description Event order
SYSTEM-ONLY For keys which should be handled by mozbrowser-iframe-host-page only. system
SYSTEM-FIRST For keys which can be handled by mozbrowser-iframe-host-page first and can then also be handled by mozbrowser-iframe-embedded-page. system->app
APP-CANCELLED For keys which should be handled by the mozbrowser-iframe-embedded-page only. app
APP-FIRST For keys which can be handled by mozbrowser-iframe-embedded-page first and can then also be handled by mozbrowser-iframe-host-page. app->system

[Table 1]

[Fig 2]

[Fig 2]

The mozbrowser-iframe-host-page and mozbrowser-iframe-embedded-page mentioned in Table 1 are illustrated in Fig.2 above. If A.html represents a host page whose source is B.html, then A.html is the mozbrowser-iframe-host-page, and B.html is mozbrowser-iframe-embedded-page. mozbrowser uses the non-standard Firefox Browser API, built for the implementation of key features and content experiences in Firefox OS apps. Learn more about mozbrowser on MDN.

Suitable responses for any given keyboard event depend on the scenario. In the case illustrated above, let’s suppose that the ‘Info’ keyboard event is categorized as APP-FIRST and the default action set by system is to show system information. Thus, when we press the ‘Info’ key with app Z in the foreground, there are two possible results:

    1. If app Z has an event handler that tells the ‘Info’ key to show app information, then app information will appear on screen when the user presses the ‘Info’ key on the remote.
    2. If app Z doesn’t set an event handler for the ‘Info’ key, the default action is triggered. That is, the screen will show the system information.

How to implement the four scenarios

To implement the four keyboard event scenarios described above, we’ve introduced four new keyboard events:

      • mozbrowserbeforekeydown – fired before the keydown event
      • mozbrowserafterkeydown – fired after the keydown event
      • mozbrowserbeforekeyup – fired before the keyup event
      • mozbrowserafterkeyup – fired after the keyup event

These four keyboard events are only received by the window that embeds a mozbrowser-iframe.

The keyboard events occur in a specific sequence over time: mozbrowserbeforekeydown, mozbrowserafterkeydown, mozbrowserbeforekeyup, keyup, mozbrowserafterkeyup.

This gives developers a way to implement the four scenarios mentioned above. Conceptually, the scenarios SYSTEM-ONLY, SYSTEM-FIRST and APP-CANCELLED, APP-FIRST can be implemented by setting proper handlers for the mozbrowserbeforekey* and mozbrowserafterkey* events. The SYSTEM-ONLY and SYSTEM-FIRST scenarios can be implemented by setting proper handlers for mozbrowserbeforekey* events and the APP-CANCELLED and APP-FIRST scenarios can be implemented via mozbrowserafterkey* events.

iframe structure in Firefox OS

[Fig 3]

[Fig 3]

To understand how to implement the four scenarios, let’s first take a look at iframe structure in Firefox OS. The outermost iframe in Firefox OS is shell.html. It embeds an in-process iframe which is sourced from system/index.html. The system app (system/index.html) contains several web apps (essentially iframes) which can be in-process (remote=”false”) or out-of-process (remote=”true”). As a result, the relationship of these three layers can be displayed in the following table:

mozbrowser iframe host page mozbrowser iframe embedded page
shell.html system/index.html
system/index.html web apps(essentially iframes)

[Table 2]

Dispatch order of keyboard events

[Fig 4]

[Fig 4]

When a keydown event is sent to some element in a mozbrowser-iframe-embedded-page, the owner of the embedded iframe, i.e., the mozbrowser-iframe-host-page, will receive the mozbrowserbeforekeydown event before the keydown event is sent and the mozbrowserafterkeydown event after the event is sent to the mozbrowser-iframe-embedded-page.

In Gecko, once there is one keydown event with the target in an out-of-process iframe embedded in an HTML document, the keydown event is duplicated to the HTML document as well. The target of this duplicated event is set as the embedded iframe element.

This results in the keyboard event sequence shown in Fig 4. It illustrates all related keydown events and their relationship when a keydown event with a target in a mozbrowser-iframe-embedded-page needs to be dispatched. In brief, events follow this sequence:

      1. Before dispatching any keydown event, the mozbrowserbeforekeydown event is first dispatched to the window of mozbrowser-iframe-host-page.
      2. Then, the original keydown event (with a target in a mozbrowser-iframe-embedded-page) will be duplicated to the mozbrowser-iframe-host-page HTML document. Its target will be set to be the iframe that contains the mozbrowser-iframe-embedded-page.
      3. Next, the original keydown event will be dispatched to its target.
      4. After the original keydown event dispatch is complete, the mozbrowserafterkeydown event will be dispatched to the window of mozbrowser-iframe-host-page.

Notice that the event dispatch process described above follows the DOM tree event flow. Event sequence and event targets can be organized into the following table:

Order event target
1 mozbrowserbeforekeydown window in mozbrowser-iframe-host-page
2 keydown iframe that contains the mozbrowser-iframe-embedded-page in mozbrowser-iframe-host-page
3 keydown original one in mozbrowser-iframe-embedded-page
4 mozbrowserafterkeydown window in mozbrowser-iframe-host-page

[Table 3]

f5

[Fig 5]

The keyboard events mozbrowserbeforekeydown, keydown, and mozbrowserafterkeydown, can be extended to nested mozbrowser iframes, like the iframe structure in Firefox OS described in Table 2. In this case, the mozbrowserbeforekeydown and mozbrowserafterkeydown events will be dispatched to the innermost mozbrowser-iframe-host-page as well as the outer one. Thus, in Firefox OS, mozbrowserkeydown and mozbrowserafterkeydown will be dispatched to the window of system/index.html and the window of shell.html. Fig. 5 illustrates the whole dispatch sequence of related events when a keydown event is dispatched to a web app. The sequence of events is demonstrated in Table 4.

Order event target
1 mozbrowserbeforekeydown window in shell.html
2 mozbrowserbeforekeydown window in system/index.html
3 keydown iframe that contains the web app in system/index.html
4 keydown original one in web app
5 mozbrowserafterkeydown window in system/index.html
6 mozbrowserafterkeydown window in shell.html

[Table 4]

f6

[Fig 6]

Although the keyup event must be fired after keydown, the keydown event and the keyup event are independent of each other. Moreover, the path mozbrowserbeforekeyup, keyup, mozbrowserafterkeyup is independent of the path mozbrowserbeforekeydown, keydown, mozbrowserafterkeydown. Therefore, it’s possible for these two paths to cross each other. The mozbrowserbeforekeyup may arrive before the keydown event.

In Firefox OS, most apps run out-of-process. This means that the app runs on its own process, not on the main process. After dispatching a given key* event (the duplicate) to the system app, it takes time to send the original key* event to the process where the mozbrowser-iframe-embedded-page is located. In a similar manner, after a given key* event is dispatched to the mozbrowser-iframe-embedded-page’s process, time is required to send mozbrowserafterkey* back to the process where the mozbrowser-iframe-host-page is located.

Consequently, the mozbrowserbeforekeyup event may arrive in the main Firefox OS process (where the system app lives), before the keydown event is dispatched to the app’s own process. Common results of the order of the key* events are demonstrated above in Fig. 6. The yellow series represents the keydown path, and the blue series show the keyup path. And yes, these two paths may cross each other.

Next steps

If you’re looking for implementation details for the four scenarios we’ve described, as well as event handler sample code to help with your implementation of keyboard events for smart TV remotes, keep an eye out for the followup post, and stay tuned for more complete documentation arriving very soon on MDN.

About Chun-Min Chang

More articles by Chun-Min Chang…

About Shiqi Gao

More articles by Shiqi Gao…


One comment

  1. Miguel

    Hi there,

    that’s an interesting post. Thank you for that. I wrote about a similar topic on the blog of the company I work for: http://blog.hubii.com/firefox-os-tv-how-to-get-events-from-remote-controller/

    We’ve developed the one of the first FirefoxOS TV apps for Panasonic. :)

    August 26th, 2015 at 07:48

Comments are closed for this article.