It does not matter the language, I hate keyboard events in the browser.
To date, I have been unsuccessful in testing keyboard events in Dart—mostly because it is very hard, if not impossible, to simulate keyboard events in Dart. And, of course, JavaScript DOM events stink to high heaven: the character is in the
keyCode
property for keyup and keydown events, but it is the uppercase version of the character no matter what, and the character is in the charCode
property for keypress events, but both keyCode
and charCode
are deprecated for key
which is deprecated for which
which is not implemented anywhere. And of course none of it works in all browsers.Anyhow…
Dart is supposed to normalize bizarre behaviors across browsers, but I am still using the same raw values that JavaScript uses. In the ICE Code Editor project, I handle keyboard shortcuts by querying the
$dom_keyIdentifier
property: _keyDownSubscription = document.onKeyDown.listen((e) {
if (!e.ctrlKey) return;
switch(e.$dom_keyIdentifier) {
case 'n':
case 'U+004E':
new NewProjectDialog(this).open();
e.preventDefault();
break;
case 'o':
case 'U+004F':
new OpenDialog(this).open();
e.preventDefault();
break;
case 'h':
case 'U+0048':
if (e.shiftKey) toggleCode();
e.preventDefault();
break;
}
});
Don't even get me started on keyIdentifier
, but it seems to have the best support in the various browsers that I am targeting and has limited testability in Dart. But let's face it, that kind of stinks.As I have been mucking with events in Dartover the past few nights, I came across the
KeyEvent
class. This class is supposed to normalize the wackiness of cross-browser key events. I give it a try with the KeyboardEventStream.onKeyDown()
static method, which ought to give me a stream of KeyEvent
objects: _keyDownSubscription = KeyboardEventStream.onKeyDown(document).listen((e) {
if (!e.ctrlKey) return;
switch(e.keyCode) {
// ...
}
});
When I try that out in the browser, I get:Exception: Unsupported operation: keyIdentifier is unsupported. /mnt/data/b/build/slave/dartium-lucid64-full-trunk/build/src/dart/tools/dom/src/dartium_KeyEvent.dart:40 KeyEvent.$dom_keyIdentifier /mnt/data/b/build/slave/dartium-lucid64-full-trunk/build/src/dart/tools/dom/src/dartium_KeyEvent.dart:40 KeyEvent._shadowKeyIdentifier /mnt/data/b/build/slave/dartium-lucid64-full-trunk/build/src/dart/tools/dom/src/dartium_KeyEvent.dart:36 _KeyboardEventHandler.processKeyPress /mnt/data/b/build/slave/dartium-lucid64-full-trunk/build/src/dart/tools/dom/src/KeyboardEventStream.dart:138 processKeyDown /mnt/data/b/build/slave/dartium-lucid64-full-trunk/build/src/dart/tools/dom/src/KeyboardEventStream.dart:121Sigh. A quick search reveals that a bug has already been reported for this (
KeyEvent
objects with the control key active). Well, that is unfortunate. It seems that I am stuck with $dom_keyIdentifier
until the M6 release of Dart (at least).Before calling it a night, I would like to catalog the behavior of
$dom_keyIdentfier
across clients.In Dart unittests, I can create keyboard events with data using the
KeyboardEvent
class: document.activeElement.dispatchEvent(
new KeyboardEvent(
'keydown',
keyIdentifier: char,
ctrlKey: true
)
);
When char
is "n"
the value of $dom_keyIdentifier
is also "n"
.When I try pressing Ctrl+n in Dartium,
$dom_keyIdentifier
returns the rather absurd string of "U+004E"
. Note that is the string "U", the string "+", the string "0", etc. and not a unicode integer. I have little room to complain since I am using a raw DOM getter. Well, I supposed I am entitled to complain a little bit since it is such an incredible pain to create keyboard events with data in Dart, but I won't.When I compile to JavaScript, Chrome also returns the string
"U+004E"
.Unfortunately, Firefox returns
null
for this value.Similarly, Internet Explorer also returns
null
for $dom_keyIdentifier
.In all browsers, the
keyCode
value is set properly (decimal 78 for N
), but I have no way to set the keyCode
property in the KeyboardEvent
constructor or via a setter on the resultant object. The keyCode
value is final—intended only for the native browser event to set.For posterity:
Env | $dom_keyIdentifer for “N” | keyCode for “N” |
---|---|---|
unittest | n | 0 |
Dartium | "U+004E" | 78 |
Chrome | "U+004E" | 78 |
Firefox | null | 78 |
Internet Explorer | null | 78 |
In other words, I am left with two choices: make it work across all browser via the
keyCode
property or leave it testable (albeit poorly) with $dom_keyIdentifier
and only support Chrome.I think for ICE, it makes the most sense to leave it testable and to support Chrome only. The main reason is that I value testing that highly. If I cannot test it, I cannot guarantee that future changes will not introduce regressions. Also, once
KeyEvent
improves, I have a drop-in place for the code to go and tests will ensure that it works. The second reason that I stick with Chrome-only is that ICE's primary use is for programmers reading 3D Game Programming for Kids. Even though ICE will work in all browsers, the book requires Chrome for easier support, better WebGL support, and so that I can have readers check the Chrome console for errors.Still, all I want for Christmas is better keyboard event support and testability in Dart. Please?
Day #836
No comments:
Post a Comment