OLD | NEW |
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 * Works with KeyboardEvent and KeyEvent to determine how to expose information |
9 * about Key(board)Events. This class functions like an EventListenerList, and | 9 * about Key(board)Events. This class functions like an EventListenerList, and |
10 * provides a consistent interface for the Dart | 10 * provides a consistent interface for the Dart |
(...skipping 19 matching lines...) Expand all Loading... |
30 | 30 |
31 /** The type of KeyEvent we are tracking (keyup, keydown, keypress). */ | 31 /** The type of KeyEvent we are tracking (keyup, keydown, keypress). */ |
32 String _type; | 32 String _type; |
33 | 33 |
34 /** The element we are watching for events to happen on. */ | 34 /** The element we are watching for events to happen on. */ |
35 EventTarget _target; | 35 EventTarget _target; |
36 | 36 |
37 // The distance to shift from upper case alphabet Roman letters to lower case. | 37 // The distance to shift from upper case alphabet Roman letters to lower case. |
38 final int _ROMAN_ALPHABET_OFFSET = "a".charCodes[0] - "A".charCodes[0]; | 38 final int _ROMAN_ALPHABET_OFFSET = "a".charCodes[0] - "A".charCodes[0]; |
39 | 39 |
40 // Instance members referring to the internal event handlers because closures | 40 StreamSubscription _keyUpSubscription, _keyDownSubscription, |
41 // are not hashable. | 41 _keyPressSubscription; |
42 var _keyUp, _keyDown, _keyPress; | |
43 | 42 |
44 /** | 43 /** |
45 * An enumeration of key identifiers currently part of the W3C draft for DOM3 | 44 * An enumeration of key identifiers currently part of the W3C draft for DOM3 |
46 * and their mappings to keyCodes. | 45 * and their mappings to keyCodes. |
47 * http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set | 46 * http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set |
48 */ | 47 */ |
49 static Map<String, int> _keyIdentifier = { | 48 static Map<String, int> _keyIdentifier = { |
50 'Up': KeyCode.UP, | 49 'Up': KeyCode.UP, |
51 'Down': KeyCode.DOWN, | 50 'Down': KeyCode.DOWN, |
52 'Left': KeyCode.LEFT, | 51 'Left': KeyCode.LEFT, |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 } | 87 } |
89 | 88 |
90 /** | 89 /** |
91 * General constructor, performs basic initialization for our improved | 90 * General constructor, performs basic initialization for our improved |
92 * KeyboardEvent controller. | 91 * KeyboardEvent controller. |
93 */ | 92 */ |
94 _KeyboardEventController(EventTarget target, String type) { | 93 _KeyboardEventController(EventTarget target, String type) { |
95 _callbacks = []; | 94 _callbacks = []; |
96 _type = type; | 95 _type = type; |
97 _target = target; | 96 _target = target; |
98 _keyDown = processKeyDown; | |
99 _keyUp = processKeyUp; | |
100 _keyPress = processKeyPress; | |
101 } | 97 } |
102 | 98 |
103 /** | 99 /** |
104 * Hook up all event listeners under the covers so we can estimate keycodes | 100 * Hook up all event listeners under the covers so we can estimate keycodes |
105 * and charcodes when they are not provided. | 101 * and charcodes when they are not provided. |
106 */ | 102 */ |
107 void _initializeAllEventListeners() { | 103 void _initializeAllEventListeners() { |
108 _keyDownList = []; | 104 _keyDownList = []; |
109 _target.on.keyDown.add(_keyDown, true); | 105 if (_keyDownSubscription == null) { |
110 _target.on.keyPress.add(_keyPress, true); | 106 _keyDownSubscription = Element.keyDownEvent.forTarget( |
111 _target.on.keyUp.add(_keyUp, true); | 107 _target, useCapture: true).listen(processKeyDown); |
| 108 _keyPressSubscription = Element.keyPressEvent.forTarget( |
| 109 _target, useCapture: true).listen(processKeyUp); |
| 110 _keyUpSubscription = Element.keyUpEvent.forTarget( |
| 111 _target, useCapture: true).listen(processKeyPress); |
| 112 } |
112 } | 113 } |
113 | 114 |
114 /** Add a callback that wishes to be notified when a KeyEvent occurs. */ | 115 /** Add a callback that wishes to be notified when a KeyEvent occurs. */ |
115 void add(void callback(KeyEvent)) { | 116 void add(void callback(KeyEvent)) { |
116 if (_callbacks.length == 0) { | 117 if (_callbacks.length == 0) { |
117 _initializeAllEventListeners(); | 118 _initializeAllEventListeners(); |
118 } | 119 } |
119 _callbacks.add(callback); | 120 _callbacks.add(callback); |
120 } | 121 } |
121 | 122 |
(...skipping 13 matching lines...) Expand all Loading... |
135 } | 136 } |
136 | 137 |
137 /** Remove the given callback from the listeners list. */ | 138 /** Remove the given callback from the listeners list. */ |
138 void remove(void callback(KeyEvent)) { | 139 void remove(void callback(KeyEvent)) { |
139 var index = _callbacks.indexOf(callback); | 140 var index = _callbacks.indexOf(callback); |
140 if (index != -1) { | 141 if (index != -1) { |
141 _callbacks.removeAt(index); | 142 _callbacks.removeAt(index); |
142 } | 143 } |
143 if (_callbacks.length == 0) { | 144 if (_callbacks.length == 0) { |
144 // If we have no listeners, don't bother keeping track of keypresses. | 145 // If we have no listeners, don't bother keeping track of keypresses. |
145 _target.on.keyDown.remove(_keyDown); | 146 _keyDownSubscription.cancel(); |
146 _target.on.keyPress.remove(_keyPress); | 147 _keyDownSubscription = null; |
147 _target.on.keyUp.remove(_keyUp); | 148 _keyPressSubscription.cancel(); |
| 149 _keyPressSubscription = null; |
| 150 _keyUpSubscription.cancel(); |
| 151 _keyUpSubscription = null; |
148 } | 152 } |
149 } | 153 } |
150 | 154 |
151 /** Determine if caps lock is one of the currently depressed keys. */ | 155 /** Determine if caps lock is one of the currently depressed keys. */ |
152 bool get _capsLockOn => | 156 bool get _capsLockOn => |
153 _keyDownList.any((var element) => element.keyCode == KeyCode.CAPS_LOCK); | 157 _keyDownList.any((var element) => element.keyCode == KeyCode.CAPS_LOCK); |
154 | 158 |
155 /** | 159 /** |
156 * Given the previously recorded keydown key codes, see if we can determine | 160 * Given the previously recorded keydown key codes, see if we can determine |
157 * the keycode of this keypress [event]. (Generally browsers only provide | 161 * the keycode of this keypress [event]. (Generally browsers only provide |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 _keyDownList.where((element) => element != toRemove).toList(); | 401 _keyDownList.where((element) => element != toRemove).toList(); |
398 } else if (_keyDownList.length > 0) { | 402 } else if (_keyDownList.length > 0) { |
399 // This happens when we've reached some international keyboard case we | 403 // This happens when we've reached some international keyboard case we |
400 // haven't accounted for or we haven't correctly eliminated all browser | 404 // haven't accounted for or we haven't correctly eliminated all browser |
401 // inconsistencies. Filing bugs on when this is reached is welcome! | 405 // inconsistencies. Filing bugs on when this is reached is welcome! |
402 _keyDownList.removeLast(); | 406 _keyDownList.removeLast(); |
403 } | 407 } |
404 _dispatch(e); | 408 _dispatch(e); |
405 } | 409 } |
406 } | 410 } |
OLD | NEW |