ReadiumJS Apps Conflicts Between Shortcut Keys and Interactive Content
This issue is a:
- Bug report
- Enhancement suggestion
Related issue(s), pull request(s)
#578
Expected behaviour
Interactive content should be able to receive keystrokes when the content has received the focus. It's reasonable that the user might have to click once inside the content (or at least move the pointer to over the content), but once the content has the focus, Readium should not keep taking the focus back and force the user to keep clicking in the content to keep the focus there.
This behaviour may not be too surprising, but it isn't reasonable for people creating interactive content to have to know what all the shortcuts are that Readium uses and avoid them. IMO, we need a pattern in which embedded content can get and keep the focus and that the user can then give the focus back to the enclosing book or user interface chrome.
Observed behaviour
By clicking on the content, the content apparently gets the focus, but only for one keystroke. Then the user has to click again in the content to get the focus again. Note that this is only for keystrokes for which there is a Readium shortcut key (e.g. T for the TOC, etc.)
Steps to reproduce
- Load the test file in the Chrome Extension (same behaviour in the Cloud Reader)
- Navigate to Chapter 7. Go to the demo page.
- Press the T key. TOC opens. Close it.
- Click the mouse on the Content.
- Press the T key. The texture on screen changes.
- Press T again. The TOC opens.
- Press the F key repeatedly. The texture filters cycle through (since there is no F shortcut in Readium)
Test file(s)
Test-file is here.
Product
- Readium Chrome extension ** latest official version available from the Chrome Web Store
- Readium cloud reader app
** local build
Web browser
Tested only with Chrome Version 49.0.2623.87 (64-bit)
Operating system
OSX 10.10
Additional information
Problem does not occur in OSX. ...
Add this HTML snippet to any of your test EPUBs (one with reflowable spine item document containing several pages / columns):
<input type="text" value="readium"/>
Now, mouse-click inside the text field, and hit the 'o' key, or use the keyboard left/right arrows to move the cursor. With Chrome and Firefox, Readium does not open the options dialog, and does not turn the pages. With Internet Explorer and Edge, Readium does interfere with the HTML text input control.
To harmonize this, we may need to:
(1) ask authors to be clever and use event.stopPropagation() and
event.preventDefault() in order to manage the event flow in their
code.
(2) implement clever routines in Readium to ensure that the app's
keyboard shortcuts (and touch gesture handlers) do not interfere with
typical HTML input controls (but note that we can't reliably
figure-out where authors put mouse/keyboard listeners in their HTML
divs/etc. ... so there's only so much we can do => thus (1))
PS: some browsers bring keyboard focus where the mouse is clicked, others don't. The iframe content (spine item document) and the app UI (chrome) are separate keyboard focusable areas, with their own cycling scope, tab index, etc. It's a pain to manage
CC @becka11y
For comparison, iBooks has issues as well. Pressing T does roll through the textures without having to give the content focus, but it beeps an error (but doesn't say what). And the layout is poor, to boot. But iBooks doesn't support any "naked" shortcut keys. Only with the Command key.
Yes, single-key keyboard shortcuts can be more problematic than combos. But then typical CTRL+SHIFT+ALT combinations tend to be interfered with by web browsers' own keyboard schemes...it's hard to get right, especially with the nested iframe which we have to artificially "bubble" events from (more like event forwarding).
Understood. But a very common pattern and one used in most WebGL/JavaScript implementations where there is little or no HTML and it is all JavaScript, is to instantiate an event listener such as
document.addEventListener("keydown", onDocumentKeyDown, false);
and
function onDocumentKeyDown(event) {
var keyCode = event.which;
if (keyCode ...)
As you say, using stopPropagation and preventDefault may help. I'll try some experiments.
I simply added event.stopPropagation() to the bottom of my eventListener and Readium now behaves as I expected it to. All keystrokes activate the appropriate shortcuts (I didn't actually test them all, just some of the ones that were conflicting). If one clicks on the content, the content then captures all the keystrokes until one clicks outside the content again, at which point Readium receives all the keystrokes.
Tested on Readium Chrome Extension and CloudReader 2.23-alpha.