Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(295)

Side by Side Diff: tools/dom/src/KeyboardEventStream.dart

Issue 26334002: "Reverting 28321" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/dom/src/KeyName.dart ('k') | tools/dom/src/dart2js_KeyEvent.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of html; 5 part of html;
6 6
7 /** 7 /**
8 * Internal class that does the actual calculations to determine keyCode and 8 * Internal class that does the actual calculations to determine keyCode and
9 * charCode for keydown, keypress, and keyup events for all browsers. 9 * charCode for keydown, keypress, and keyup events for all browsers.
10 */ 10 */
11 class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> { 11 class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> {
12 // This code inspired by Closure's KeyHandling library. 12 // This code inspired by Closure's KeyHandling library.
13 // http://closure-library.googlecode.com/svn/docs/closure_goog_events_keyhandl er.js.source.html 13 // http://closure-library.googlecode.com/svn/docs/closure_goog_events_keyhandl er.js.source.html
14 14
15 /** 15 /**
16 * The set of keys that have been pressed down without seeing their 16 * The set of keys that have been pressed down without seeing their
17 * corresponding keyup event. 17 * corresponding keyup event.
18 */ 18 */
19 final List<KeyboardEvent> _keyDownList = <KeyboardEvent>[]; 19 final List<KeyboardEvent> _keyDownList = <KeyboardEvent>[];
20 20
21 /** The type of KeyEvent we are tracking (keyup, keydown, keypress). */ 21 /** The type of KeyEvent we are tracking (keyup, keydown, keypress). */
22 final String _type; 22 final String _type;
23 23
24 /** The element we are watching for events to happen on. */ 24 /** The element we are watching for events to happen on. */
25 final EventTarget _target; 25 final EventTarget _target;
26 26
27 // The distance to shift from upper case alphabet Roman letters to lower case. 27 // The distance to shift from upper case alphabet Roman letters to lower case.
28 static final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0]; 28 static final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0];
29 29
30 /** Custom Stream (Controller) to produce KeyEvents for the stream. */ 30 /** Controller to produce KeyEvents for the stream. */
31 _CustomKeyEventStreamImpl _stream; 31 final StreamController _controller = new StreamController(sync: true);
32 32
33 static const _EVENT_TYPE = 'KeyEvent'; 33 static const _EVENT_TYPE = 'KeyEvent';
34 34
35 /** 35 /**
36 * An enumeration of key identifiers currently part of the W3C draft for DOM3 36 * An enumeration of key identifiers currently part of the W3C draft for DOM3
37 * and their mappings to keyCodes. 37 * and their mappings to keyCodes.
38 * http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set 38 * http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set
39 */ 39 */
40 static const Map<String, int> _keyIdentifier = const { 40 static const Map<String, int> _keyIdentifier = const {
41 'Up': KeyCode.UP, 41 'Up': KeyCode.UP,
(...skipping 15 matching lines...) Expand all
57 'F12': KeyCode.F12, 57 'F12': KeyCode.F12,
58 'U+007F': KeyCode.DELETE, 58 'U+007F': KeyCode.DELETE,
59 'Home': KeyCode.HOME, 59 'Home': KeyCode.HOME,
60 'End': KeyCode.END, 60 'End': KeyCode.END,
61 'PageUp': KeyCode.PAGE_UP, 61 'PageUp': KeyCode.PAGE_UP,
62 'PageDown': KeyCode.PAGE_DOWN, 62 'PageDown': KeyCode.PAGE_DOWN,
63 'Insert': KeyCode.INSERT 63 'Insert': KeyCode.INSERT
64 }; 64 };
65 65
66 /** Return a stream for KeyEvents for the specified target. */ 66 /** Return a stream for KeyEvents for the specified target. */
67 // Note: this actually functions like a factory constructor. 67 Stream<KeyEvent> forTarget(EventTarget e, {bool useCapture: false}) {
68 CustomStream<KeyEvent> forTarget(EventTarget e, {bool useCapture: false}) { 68 return new _KeyboardEventHandler.initializeAllEventListeners(
69 var handler = new _KeyboardEventHandler.initializeAllEventListeners( 69 _type, e).stream;
70 _type, e); 70 }
71 return handler._stream; 71
72 /**
73 * Accessor to the stream associated with a particular KeyboardEvent
74 * EventTarget.
75 *
76 * [forTarget] must be called to initialize this stream to listen to a
77 * particular EventTarget.
78 */
79 Stream<KeyEvent> get stream {
80 if(_target != null) {
81 return _controller.stream;
82 } else {
83 throw new StateError("Not initialized. Call forTarget to access a stream "
84 "initialized with a particular EventTarget.");
85 }
72 } 86 }
73 87
74 /** 88 /**
75 * General constructor, performs basic initialization for our improved 89 * General constructor, performs basic initialization for our improved
76 * KeyboardEvent controller. 90 * KeyboardEvent controller.
77 */ 91 */
78 _KeyboardEventHandler(this._type): super(_EVENT_TYPE), 92 _KeyboardEventHandler(this._type) :
79 _stream = new _CustomKeyEventStreamImpl('event'); 93 _target = null, super(_EVENT_TYPE) {
94 }
80 95
81 /** 96 /**
82 * Hook up all event listeners under the covers so we can estimate keycodes 97 * Hook up all event listeners under the covers so we can estimate keycodes
83 * and charcodes when they are not provided. 98 * and charcodes when they are not provided.
84 */ 99 */
85 _KeyboardEventHandler.initializeAllEventListeners(this._type, this._target) : 100 _KeyboardEventHandler.initializeAllEventListeners(this._type, this._target) :
86 super(_EVENT_TYPE) { 101 super(_EVENT_TYPE) {
87 Element.keyDownEvent.forTarget(_target, useCapture: true).listen( 102 Element.keyDownEvent.forTarget(_target, useCapture: true).listen(
88 processKeyDown); 103 processKeyDown);
89 Element.keyPressEvent.forTarget(_target, useCapture: true).listen( 104 Element.keyPressEvent.forTarget(_target, useCapture: true).listen(
90 processKeyPress); 105 processKeyPress);
91 Element.keyUpEvent.forTarget(_target, useCapture: true).listen( 106 Element.keyUpEvent.forTarget(_target, useCapture: true).listen(
92 processKeyUp); 107 processKeyUp);
93 _stream = new _CustomKeyEventStreamImpl(_type); 108 }
109
110 /**
111 * Notify all callback listeners that a KeyEvent of the relevant type has
112 * occurred.
113 */
114 bool _dispatch(KeyEvent event) {
115 if (event.type == _type)
116 _controller.add(event);
94 } 117 }
95 118
96 /** Determine if caps lock is one of the currently depressed keys. */ 119 /** Determine if caps lock is one of the currently depressed keys. */
97 bool get _capsLockOn => 120 bool get _capsLockOn =>
98 _keyDownList.any((var element) => element.keyCode == KeyCode.CAPS_LOCK); 121 _keyDownList.any((var element) => element.keyCode == KeyCode.CAPS_LOCK);
99 122
100 /** 123 /**
101 * Given the previously recorded keydown key codes, see if we can determine 124 * Given the previously recorded keydown key codes, see if we can determine
102 * the keycode of this keypress [event]. (Generally browsers only provide 125 * the keycode of this keypress [event]. (Generally browsers only provide
103 * charCode information for keypress events, but with a little 126 * charCode information for keypress events, but with a little
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 // before we've caught a key-up event. If the last-key was one of these 297 // before we've caught a key-up event. If the last-key was one of these
275 // we reset the state. 298 // we reset the state.
276 if (_keyDownList.length > 0 && 299 if (_keyDownList.length > 0 &&
277 (_keyDownList.last.keyCode == KeyCode.CTRL && !e.ctrlKey || 300 (_keyDownList.last.keyCode == KeyCode.CTRL && !e.ctrlKey ||
278 _keyDownList.last.keyCode == KeyCode.ALT && !e.altKey || 301 _keyDownList.last.keyCode == KeyCode.ALT && !e.altKey ||
279 Device.userAgent.contains('Mac') && 302 Device.userAgent.contains('Mac') &&
280 _keyDownList.last.keyCode == KeyCode.META && !e.metaKey)) { 303 _keyDownList.last.keyCode == KeyCode.META && !e.metaKey)) {
281 _keyDownList.clear(); 304 _keyDownList.clear();
282 } 305 }
283 306
284 var event = new KeyEvent.wrap(e); 307 var event = new KeyEvent(e);
285 event._shadowKeyCode = _normalizeKeyCodes(event); 308 event._shadowKeyCode = _normalizeKeyCodes(event);
286 // Technically a "keydown" event doesn't have a charCode. This is 309 // Technically a "keydown" event doesn't have a charCode. This is
287 // calculated nonetheless to provide us with more information in giving 310 // calculated nonetheless to provide us with more information in giving
288 // as much information as possible on keypress about keycode and also 311 // as much information as possible on keypress about keycode and also
289 // charCode. 312 // charCode.
290 event._shadowCharCode = _findCharCodeKeyDown(event); 313 event._shadowCharCode = _findCharCodeKeyDown(event);
291 if (_keyDownList.length > 0 && event.keyCode != _keyDownList.last.keyCode && 314 if (_keyDownList.length > 0 && event.keyCode != _keyDownList.last.keyCode &&
292 !_firesKeyPressEvent(event)) { 315 !_firesKeyPressEvent(event)) {
293 // Some browsers have quirks not firing keypress events where all other 316 // Some browsers have quirks not firing keypress events where all other
294 // browsers do. This makes them more consistent. 317 // browsers do. This makes them more consistent.
295 processKeyPress(e); 318 processKeyPress(e);
296 } 319 }
297 _keyDownList.add(event); 320 _keyDownList.add(event);
298 _stream.add(event); 321 _dispatch(event);
299 } 322 }
300 323
301 /** Handle keypress events. */ 324 /** Handle keypress events. */
302 void processKeyPress(KeyboardEvent event) { 325 void processKeyPress(KeyboardEvent event) {
303 var e = new KeyEvent.wrap(event); 326 var e = new KeyEvent(event);
304 // IE reports the character code in the keyCode field for keypress events. 327 // IE reports the character code in the keyCode field for keypress events.
305 // There are two exceptions however, Enter and Escape. 328 // There are two exceptions however, Enter and Escape.
306 if (Device.isIE) { 329 if (Device.isIE) {
307 if (e.keyCode == KeyCode.ENTER || e.keyCode == KeyCode.ESC) { 330 if (e.keyCode == KeyCode.ENTER || e.keyCode == KeyCode.ESC) {
308 e._shadowCharCode = 0; 331 e._shadowCharCode = 0;
309 } else { 332 } else {
310 e._shadowCharCode = e.keyCode; 333 e._shadowCharCode = e.keyCode;
311 } 334 }
312 } else if (Device.isOpera) { 335 } else if (Device.isOpera) {
313 // Opera reports the character code in the keyCode field. 336 // Opera reports the character code in the keyCode field.
314 e._shadowCharCode = KeyCode.isCharacterKey(e.keyCode) ? e.keyCode : 0; 337 e._shadowCharCode = KeyCode.isCharacterKey(e.keyCode) ? e.keyCode : 0;
315 } 338 }
316 // Now we guestimate about what the keycode is that was actually 339 // Now we guestimate about what the keycode is that was actually
317 // pressed, given previous keydown information. 340 // pressed, given previous keydown information.
318 e._shadowKeyCode = _determineKeyCodeForKeypress(e); 341 e._shadowKeyCode = _determineKeyCodeForKeypress(e);
319 342
320 // Correct the key value for certain browser-specific quirks. 343 // Correct the key value for certain browser-specific quirks.
321 if (e._shadowKeyIdentifier != null && 344 if (e._shadowKeyIdentifier != null &&
322 _keyIdentifier.containsKey(e._shadowKeyIdentifier)) { 345 _keyIdentifier.containsKey(e._shadowKeyIdentifier)) {
323 // This is needed for Safari Windows because it currently doesn't give a 346 // This is needed for Safari Windows because it currently doesn't give a
324 // keyCode/which for non printable keys. 347 // keyCode/which for non printable keys.
325 e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier]; 348 e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier];
326 } 349 }
327 e._shadowAltKey = _keyDownList.any((var element) => element.altKey); 350 e._shadowAltKey = _keyDownList.any((var element) => element.altKey);
328 _stream.add(e); 351 _dispatch(e);
329 } 352 }
330 353
331 /** Handle keyup events. */ 354 /** Handle keyup events. */
332 void processKeyUp(KeyboardEvent event) { 355 void processKeyUp(KeyboardEvent event) {
333 var e = new KeyEvent.wrap(event); 356 var e = new KeyEvent(event);
334 KeyboardEvent toRemove = null; 357 KeyboardEvent toRemove = null;
335 for (var key in _keyDownList) { 358 for (var key in _keyDownList) {
336 if (key.keyCode == e.keyCode) { 359 if (key.keyCode == e.keyCode) {
337 toRemove = key; 360 toRemove = key;
338 } 361 }
339 } 362 }
340 if (toRemove != null) { 363 if (toRemove != null) {
341 _keyDownList.removeWhere((element) => element == toRemove); 364 _keyDownList.removeWhere((element) => element == toRemove);
342 } else if (_keyDownList.length > 0) { 365 } else if (_keyDownList.length > 0) {
343 // This happens when we've reached some international keyboard case we 366 // This happens when we've reached some international keyboard case we
344 // haven't accounted for or we haven't correctly eliminated all browser 367 // haven't accounted for or we haven't correctly eliminated all browser
345 // inconsistencies. Filing bugs on when this is reached is welcome! 368 // inconsistencies. Filing bugs on when this is reached is welcome!
346 _keyDownList.removeLast(); 369 _keyDownList.removeLast();
347 } 370 }
348 _stream.add(e); 371 _dispatch(e);
349 } 372 }
350 } 373 }
351 374
352 375
353 /** 376 /**
354 * Records KeyboardEvents that occur on a particular element, and provides a 377 * Records KeyboardEvents that occur on a particular element, and provides a
355 * stream of outgoing KeyEvents with cross-browser consistent keyCode and 378 * stream of outgoing KeyEvents with cross-browser consistent keyCode and
356 * charCode values despite the fact that a multitude of browsers that have 379 * charCode values despite the fact that a multitude of browsers that have
357 * varying keyboard default behavior. 380 * varying keyboard default behavior.
358 * 381 *
359 * Example usage: 382 * Example usage:
360 * 383 *
361 * KeyboardEventStream.onKeyDown(document.body).listen( 384 * KeyboardEventStream.onKeyDown(document.body).listen(
362 * keydownHandlerTest); 385 * keydownHandlerTest);
363 * 386 *
364 * This class is very much a work in progress, and we'd love to get information 387 * This class is very much a work in progress, and we'd love to get information
365 * on how we can make this class work with as many international keyboards as 388 * on how we can make this class work with as many international keyboards as
366 * possible. Bugs welcome! 389 * possible. Bugs welcome!
367 */ 390 */
368 class KeyboardEventStream { 391 class KeyboardEventStream {
369 392
370 /** Named constructor to produce a stream for onKeyPress events. */ 393 /** Named constructor to produce a stream for onKeyPress events. */
371 static CustomStream<KeyEvent> onKeyPress(EventTarget target) => 394 static Stream<KeyEvent> onKeyPress(EventTarget target) =>
372 new _KeyboardEventHandler('keypress').forTarget(target); 395 new _KeyboardEventHandler('keypress').forTarget(target);
373 396
374 /** Named constructor to produce a stream for onKeyUp events. */ 397 /** Named constructor to produce a stream for onKeyUp events. */
375 static CustomStream<KeyEvent> onKeyUp(EventTarget target) => 398 static Stream<KeyEvent> onKeyUp(EventTarget target) =>
376 new _KeyboardEventHandler('keyup').forTarget(target); 399 new _KeyboardEventHandler('keyup').forTarget(target);
377 400
378 /** Named constructor to produce a stream for onKeyDown events. */ 401 /** Named constructor to produce a stream for onKeyDown events. */
379 static CustomStream<KeyEvent> onKeyDown(EventTarget target) => 402 static Stream<KeyEvent> onKeyDown(EventTarget target) =>
380 new _KeyboardEventHandler('keydown').forTarget(target); 403 new _KeyboardEventHandler('keydown').forTarget(target);
381 } 404 }
OLDNEW
« no previous file with comments | « tools/dom/src/KeyName.dart ('k') | tools/dom/src/dart2js_KeyEvent.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698