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

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

Issue 12419011: Modern-ify KeyEvent handling. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: \ Created 7 years, 9 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
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 * Works with KeyboardEvent and KeyEvent to determine how to expose information 8 * Internal class that does the actual calculations to determine keyCode and
9 * about Key(board)Events. This class functions like an EventListenerList, and 9 * charCode for keydown, keypress, and keyup events for all browsers.
10 * provides a consistent interface for the Dart
11 * user, despite the fact that a multitude of browsers that have varying
12 * keyboard default behavior.
13 *
14 * This class is very much a work in progress, and we'd love to get information
15 * on how we can make this class work with as many international keyboards as
16 * possible. Bugs welcome!
17 */ 10 */
18 class KeyboardEventController { 11 class _KeyboardEventHandler implements EventStreamProvider<KeyEvent> {
19 // This code inspired by Closure's KeyHandling library. 12 // This code inspired by Closure's KeyHandling library.
20 // 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
21 14
22 /** 15 /**
23 * 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
24 * corresponding keyup event. 17 * corresponding keyup event.
25 */ 18 */
26 List<KeyboardEvent> _keyDownList; 19 List<KeyboardEvent> _keyDownList;
27 20
28 /** The set of functions that wish to be notified when a KeyEvent happens. */ 21 /** The set of functions that wish to be notified when a KeyEvent happens. */
29 List<Function> _callbacks; 22 List<Function> _callbacks;
30 23
31 /** The type of KeyEvent we are tracking (keyup, keydown, keypress). */ 24 /** The type of KeyEvent we are tracking (keyup, keydown, keypress). */
32 String _type; 25 String _type;
33 26
34 /** The element we are watching for events to happen on. */ 27 /** The element we are watching for events to happen on. */
35 EventTarget _target; 28 EventTarget _target;
36 29
37 // The distance to shift from upper case alphabet Roman letters to lower case. 30 // The distance to shift from upper case alphabet Roman letters to lower case.
38 final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0]; 31 final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0];
39 32
40 StreamSubscription _keyUpSubscription, _keyDownSubscription, 33 /** Controller to produce KeyEvents for the stream. */
41 _keyPressSubscription; 34 StreamController _controller;
42 35
43 /** 36 /**
44 * An enumeration of key identifiers currently part of the W3C draft for DOM3 37 * An enumeration of key identifiers currently part of the W3C draft for DOM3
45 * and their mappings to keyCodes. 38 * and their mappings to keyCodes.
46 * http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set 39 * http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set
47 */ 40 */
48 static Map<String, int> _keyIdentifier = { 41 static Map<String, int> _keyIdentifier = {
49 'Up': KeyCode.UP, 42 'Up': KeyCode.UP,
50 'Down': KeyCode.DOWN, 43 'Down': KeyCode.DOWN,
51 'Left': KeyCode.LEFT, 44 'Left': KeyCode.LEFT,
(...skipping 12 matching lines...) Expand all
64 'F11': KeyCode.F11, 57 'F11': KeyCode.F11,
65 'F12': KeyCode.F12, 58 'F12': KeyCode.F12,
66 'U+007F': KeyCode.DELETE, 59 'U+007F': KeyCode.DELETE,
67 'Home': KeyCode.HOME, 60 'Home': KeyCode.HOME,
68 'End': KeyCode.END, 61 'End': KeyCode.END,
69 'PageUp': KeyCode.PAGE_UP, 62 'PageUp': KeyCode.PAGE_UP,
70 'PageDown': KeyCode.PAGE_DOWN, 63 'PageDown': KeyCode.PAGE_DOWN,
71 'Insert': KeyCode.INSERT 64 'Insert': KeyCode.INSERT
72 }; 65 };
73 66
74 /** Named constructor to add an onKeyPress event listener to our handler. */ 67 /**
75 KeyboardEventController.keypress(EventTarget target) { 68 * Gets the type of the event which this would listen for on the specified
76 _KeyboardEventController(target, 'keypress'); 69 * event target.
77 } 70 */
71 String getEventType(EventTarget target) => 'KeyEvent';
78 72
79 /** Named constructor to add an onKeyUp event listener to our handler. */ 73 /** Return a stream for KeyEvents for the specified target. */
80 KeyboardEventController.keyup(EventTarget target) { 74 Stream<KeyEvent> forTarget(EventTarget e, {bool useCapture: false}) {
81 _KeyboardEventController(target, 'keyup'); 75 _initializeAllEventListeners(e);
82 } 76 return _controller.stream;
83
84 /** Named constructor to add an onKeyDown event listener to our handler. */
85 KeyboardEventController.keydown(EventTarget target) {
86 _KeyboardEventController(target, 'keydown');
87 } 77 }
88 78
89 /** 79 /**
90 * General constructor, performs basic initialization for our improved 80 * General constructor, performs basic initialization for our improved
91 * KeyboardEvent controller. 81 * KeyboardEvent controller.
92 */ 82 */
93 _KeyboardEventController(EventTarget target, String type) { 83 _KeyboardEventHandler(String type) {
84 _type = type;
85 _controller = new StreamController.broadcast();
94 _callbacks = []; 86 _callbacks = [];
95 _type = type;
96 _target = target;
97 } 87 }
98 88
99 /** 89 /**
100 * Hook up all event listeners under the covers so we can estimate keycodes 90 * Hook up all event listeners under the covers so we can estimate keycodes
101 * and charcodes when they are not provided. 91 * and charcodes when they are not provided.
102 */ 92 */
103 void _initializeAllEventListeners() { 93 _initializeAllEventListeners(EventTarget target) {
94 _target = target;
104 _keyDownList = []; 95 _keyDownList = [];
105 if (_keyDownSubscription == null) { 96 Element.keyDownEvent.forTarget(_target, useCapture: true).listen(
106 _keyDownSubscription = Element.keyDownEvent.forTarget( 97 processKeyDown);
107 _target, useCapture: true).listen(processKeyDown); 98 Element.keyPressEvent.forTarget(_target, useCapture: true).listen(
108 _keyPressSubscription = Element.keyPressEvent.forTarget( 99 processKeyPress);
109 _target, useCapture: true).listen(processKeyUp); 100 Element.keyUpEvent.forTarget(_target, useCapture: true).listen(
110 _keyUpSubscription = Element.keyUpEvent.forTarget( 101 processKeyUp);
111 _target, useCapture: true).listen(processKeyPress);
112 }
113 }
114
115 /** Add a callback that wishes to be notified when a KeyEvent occurs. */
116 void add(void callback(KeyEvent)) {
117 if (_callbacks.length == 0) {
118 _initializeAllEventListeners();
119 }
120 _callbacks.add(callback);
121 } 102 }
122 103
123 /** 104 /**
124 * Notify all callback listeners that a KeyEvent of the relevant type has 105 * Notify all callback listeners that a KeyEvent of the relevant type has
125 * occurred. 106 * occurred.
126 */ 107 */
127 bool _dispatch(KeyEvent event) { 108 bool _dispatch(KeyEvent event) {
128 if (event.type == _type) { 109 if (event.type == _type)
129 // Make a copy of the listeners in case a callback gets removed while 110 _controller.add(event);
130 // dispatching from the list.
131 List callbacksCopy = new List.from(_callbacks);
132 for(var callback in callbacksCopy) {
133 callback(event);
134 }
135 }
136 }
137
138 /** Remove the given callback from the listeners list. */
139 void remove(void callback(KeyEvent)) {
140 var index = _callbacks.indexOf(callback);
141 if (index != -1) {
142 _callbacks.removeAt(index);
143 }
144 if (_callbacks.length == 0) {
145 // If we have no listeners, don't bother keeping track of keypresses.
146 _keyDownSubscription.cancel();
147 _keyDownSubscription = null;
148 _keyPressSubscription.cancel();
149 _keyPressSubscription = null;
150 _keyUpSubscription.cancel();
151 _keyUpSubscription = null;
152 }
153 } 111 }
154 112
155 /** Determine if caps lock is one of the currently depressed keys. */ 113 /** Determine if caps lock is one of the currently depressed keys. */
156 bool get _capsLockOn => 114 bool get _capsLockOn =>
157 _keyDownList.any((var element) => element.keyCode == KeyCode.CAPS_LOCK); 115 _keyDownList.any((var element) => element.keyCode == KeyCode.CAPS_LOCK);
158 116
159 /** 117 /**
160 * Given the previously recorded keydown key codes, see if we can determine 118 * Given the previously recorded keydown key codes, see if we can determine
161 * the keycode of this keypress [event]. (Generally browsers only provide 119 * the keycode of this keypress [event]. (Generally browsers only provide
162 * charCode information for keypress events, but with a little 120 * charCode information for keypress events, but with a little
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 _keyDownList.where((element) => element != toRemove).toList(); 359 _keyDownList.where((element) => element != toRemove).toList();
402 } else if (_keyDownList.length > 0) { 360 } else if (_keyDownList.length > 0) {
403 // This happens when we've reached some international keyboard case we 361 // This happens when we've reached some international keyboard case we
404 // haven't accounted for or we haven't correctly eliminated all browser 362 // haven't accounted for or we haven't correctly eliminated all browser
405 // inconsistencies. Filing bugs on when this is reached is welcome! 363 // inconsistencies. Filing bugs on when this is reached is welcome!
406 _keyDownList.removeLast(); 364 _keyDownList.removeLast();
407 } 365 }
408 _dispatch(e); 366 _dispatch(e);
409 } 367 }
410 } 368 }
369
370
371 /**
372 * Records KeyboardEvents that occur on a particular element, and provides a
373 * stream of outgoing KeyEvents with cross-browser consistent keyCode and
374 * charCode values despite the fact that a multitude of browsers that have
375 * varying keyboard default behavior.
376 *
377 * Example usage:
378 *
379 * new KeyboardEventStream.onKeyDown(document.body).listen(
380 * keydownHandlerTest);
381 *
382 * This class is very much a work in progress, and we'd love to get information
383 * on how we can make this class work with as many international keyboards as
384 * possible. Bugs welcome!
385 */
386 class KeyboardEventStream extends Stream<KeyEvent> {
387
388 /** Named constructor to produce a stream for onKeyPress events. */
389 factory KeyboardEventStream.onKeyPress(EventTarget target) =>
390 new _KeyboardEventHandler('keypress').forTarget(target);
391
392 /** Named constructor to produce a stream for onKeyUp events. */
393 factory KeyboardEventStream.onKeyUp(EventTarget target) =>
394 new _KeyboardEventHandler('keyup').forTarget(target);
395
396 /** Named constructor to produce a stream for onKeyDown events. */
397 factory KeyboardEventStream.onKeyDown(EventTarget target) =>
398 new _KeyboardEventHandler('keydown').forTarget(target);
399 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698