OLD | NEW |
---|---|
1 /** | 1 /** |
2 * A custom KeyboardEvent that attempts to eliminate cross-browser | 2 * A custom KeyboardEvent that attempts to eliminate cross-browser |
3 * inconsistencies, and also provide both keyCode and charCode information | 3 * inconsistencies, and also provide both keyCode and charCode information |
4 * for all key events (when such information can be determined). | 4 * for all key events (when such information can be determined). |
5 * | 5 * |
6 * KeyEvent tries to provide a higher level, more polished keyboard event | 6 * KeyEvent tries to provide a higher level, more polished keyboard event |
7 * information on top of the "raw" [KeyboardEvent]. | 7 * information on top of the "raw" [KeyboardEvent]. |
8 * | 8 * |
9 * This class is very much a work in progress, and we'd love to get information | 9 * This class is very much a work in progress, and we'd love to get information |
10 * on how we can make this class work with as many international keyboards as | 10 * on how we can make this class work with as many international keyboards as |
11 * possible. Bugs welcome! | 11 * possible. Bugs welcome! |
12 */ | 12 */ |
13 @Experimental() | |
13 class KeyEvent extends _WrappedEvent implements KeyboardEvent { | 14 class KeyEvent extends _WrappedEvent implements KeyboardEvent { |
14 /** The parent KeyboardEvent that this KeyEvent is wrapping and "fixing". */ | 15 /** The parent KeyboardEvent that this KeyEvent is wrapping and "fixing". */ |
15 KeyboardEvent _parent; | 16 KeyboardEvent _parent; |
16 | 17 |
17 /** The "fixed" value of whether the alt key is being pressed. */ | 18 /** The "fixed" value of whether the alt key is being pressed. */ |
18 bool _shadowAltKey; | 19 bool _shadowAltKey; |
19 | 20 |
20 /** Caculated value of what the estimated charCode is for this event. */ | 21 /** Caculated value of what the estimated charCode is for this event. */ |
21 int _shadowCharCode; | 22 int _shadowCharCode; |
22 | 23 |
(...skipping 14 matching lines...) Expand all Loading... | |
37 | 38 |
38 /** Accessor to the underlying keyCode value is the parent event. */ | 39 /** Accessor to the underlying keyCode value is the parent event. */ |
39 int get _realKeyCode => JS('int', '#.keyCode', _parent); | 40 int get _realKeyCode => JS('int', '#.keyCode', _parent); |
40 | 41 |
41 /** Accessor to the underlying charCode value is the parent event. */ | 42 /** Accessor to the underlying charCode value is the parent event. */ |
42 int get _realCharCode => JS('int', '#.charCode', _parent); | 43 int get _realCharCode => JS('int', '#.charCode', _parent); |
43 | 44 |
44 /** Accessor to the underlying altKey value is the parent event. */ | 45 /** Accessor to the underlying altKey value is the parent event. */ |
45 bool get _realAltKey => JS('bool', '#.altKey', _parent); | 46 bool get _realAltKey => JS('bool', '#.altKey', _parent); |
46 | 47 |
48 /** Shadows on top of the parent's currentTarget. */ | |
49 EventTarget _currentTarget; | |
50 | |
51 /** | |
52 * The value we want to use for this object's dispatch. Created here so it is | |
53 * only invoked once. | |
54 */ | |
55 static final _keyboardEventDispatchRecord = _makeRecord(); | |
56 | |
57 /** Helper to statically create the dispatch record. */ | |
58 _makeRecord() { | |
59 // TODO(efortuna): Use better way to get interceptor and remove _private() | |
sra1
2013/10/07 18:46:10
I'd make this TODO(13873)
Emily Fortuna
2013/10/07 19:29:06
Okay. Just curious, when did this format change? F
| |
60 // constructors; Issue 13873. | |
61 var interceptor = new KeyboardEvent._private(); | |
62 return makeLeafDispatchRecord(interceptor); | |
63 } | |
64 | |
47 /** Construct a KeyEvent with [parent] as the event we're emulating. */ | 65 /** Construct a KeyEvent with [parent] as the event we're emulating. */ |
48 KeyEvent(KeyboardEvent parent): super(parent) { | 66 KeyEvent.wrap(KeyboardEvent parent): super(parent) { |
49 _parent = parent; | 67 _parent = parent; |
50 _shadowAltKey = _realAltKey; | 68 _shadowAltKey = _realAltKey; |
51 _shadowCharCode = _realCharCode; | 69 _shadowCharCode = _realCharCode; |
52 _shadowKeyCode = _realKeyCode; | 70 _shadowKeyCode = _realKeyCode; |
71 _currentTarget = _parent.currentTarget; | |
72 } | |
73 | |
74 /** Programmatically create a new KeyEvent (and KeyboardEvent). */ | |
75 factory KeyEvent(String type, | |
76 {Window view, bool canBubble: true, bool cancelable: true, int keyCode: 0, | |
77 int charCode: 0, int keyLocation: 1, bool ctrlKey: false, | |
78 bool altKey: false, bool shiftKey: false, bool metaKey: false, | |
79 bool altGraphKey: false, EventTarget currentTarget}) { | |
80 if (view == null) { | |
81 view = window; | |
82 } | |
83 | |
84 var eventObj; | |
85 // In these two branches we create an underlying native KeyboardEvent, but | |
86 // we set it with our specified values. Because we are doing custom setting | |
87 // of certain values (charCode/keyCode, etc) only in this class (as opposed | |
88 // to KeyboardEvent) and the way we set these custom values depends on the | |
89 // type of underlying JS object, we do all the contruction for the | |
90 // underlying KeyboardEvent here. | |
91 if (canUseDispatchEvent) { | |
92 // Currently works in everything but Internet Explorer. | |
93 eventObj = new Event.eventType('Event', type, | |
94 canBubble: canBubble, cancelable: cancelable); | |
95 | |
96 JS('void', '#.keyCode = #', eventObj, keyCode); | |
97 JS('void', '#.which = #', eventObj, keyCode); | |
98 JS('void', '#.charCode = #', eventObj, charCode); | |
99 | |
100 JS('void', '#.keyLocation = #', eventObj, keyLocation); | |
101 JS('void', '#.ctrlKey = #', eventObj, ctrlKey); | |
102 JS('void', '#.altKey = #', eventObj, altKey); | |
103 JS('void', '#.shiftKey = #', eventObj, shiftKey); | |
104 JS('void', '#.metaKey = #', eventObj, metaKey); | |
105 JS('void', '#.altGraphKey = #', eventObj, altGraphKey); | |
106 } else { | |
107 // Currently this works on everything but Safari. Safari throws an | |
108 // "Attempting to change access mechanism for an unconfigurable property" | |
109 // TypeError when trying to do the Object.defineProperty hack, so we avoid | |
110 // this branch if possible. | |
111 // Also, if we want this branch to work in FF, we also need to modify | |
112 // _initKeyboardEvent to also take charCode and keyCode values to | |
113 // initialize initKeyEvent. | |
114 | |
115 eventObj = new Event.eventType('KeyboardEvent', type, | |
116 canBubble: canBubble, cancelable: cancelable); | |
117 | |
118 // Chromium Hack | |
119 JS('void', "Object.defineProperty(#, 'keyCode', {" | |
120 " get : function() { return this.keyCodeVal; } })", eventObj); | |
121 JS('void', "Object.defineProperty(#, 'which', {" | |
122 " get : function() { return this.keyCodeVal; } })", eventObj); | |
123 JS('void', "Object.defineProperty(#, 'charCode', {" | |
124 " get : function() { return this.charCodeVal; } })", eventObj); | |
125 | |
126 var keyIdentifier = _convertToHexString(charCode, keyCode); | |
127 eventObj._initKeyboardEvent(type, canBubble, cancelable, view, | |
128 keyIdentifier, keyLocation, ctrlKey, altKey, shiftKey, metaKey, | |
129 altGraphKey); | |
130 JS('void', '#.keyCodeVal = #', eventObj, keyCode); | |
131 JS('void', '#.charCodeVal = #', eventObj, charCode); | |
132 } | |
133 // Tell dart2js that it smells like a KeyboardEvent! | |
134 setDispatchProperty(eventObj, _keyboardEventDispatchRecord); | |
135 | |
136 var keyEvent = new KeyEvent.wrap(eventObj); | |
137 if (keyEvent._currentTarget == null) { | |
138 keyEvent._currentTarget = currentTarget == null ? window : currentTarget; | |
139 } | |
140 return keyEvent; | |
141 } | |
142 | |
143 // Currently known to work on all browsers but IE. | |
144 static bool get canUseDispatchEvent => | |
145 JS('bool', | |
146 '(typeof document.body.dispatchEvent == "function")' | |
147 '&& document.body.dispatchEvent.length > 0'); | |
148 | |
149 /** The currently registered target for this event. */ | |
150 EventTarget get currentTarget => _currentTarget; | |
151 | |
152 // This is an experimental method to be sure. | |
153 static String _convertToHexString(int charCode, int keyCode) { | |
154 if (charCode != -1) { | |
155 var hex = charCode.toRadixString(16); // Convert to hexadecimal. | |
156 StringBuffer sb = new StringBuffer('U+'); | |
157 for (int i = 0; i < 4 - hex.length; i++) sb.write('0'); | |
158 sb.write(hex); | |
159 return sb.toString(); | |
160 } else { | |
161 return KeyCode._convertKeyCodeToKeyName(keyCode); | |
162 } | |
53 } | 163 } |
54 | 164 |
55 // TODO(efortuna): If KeyEvent is sufficiently successful that we want to make | 165 // TODO(efortuna): If KeyEvent is sufficiently successful that we want to make |
56 // it the default keyboard event handling, move these methods over to Element. | 166 // it the default keyboard event handling, move these methods over to Element. |
57 /** Accessor to provide a stream of KeyEvents on the desired target. */ | 167 /** Accessor to provide a stream of KeyEvents on the desired target. */ |
58 static EventStreamProvider<KeyEvent> keyDownEvent = | 168 static EventStreamProvider<KeyEvent> keyDownEvent = |
59 new _KeyboardEventHandler('keydown'); | 169 new _KeyboardEventHandler('keydown'); |
60 /** Accessor to provide a stream of KeyEvents on the desired target. */ | 170 /** Accessor to provide a stream of KeyEvents on the desired target. */ |
61 static EventStreamProvider<KeyEvent> keyUpEvent = | 171 static EventStreamProvider<KeyEvent> keyUpEvent = |
62 new _KeyboardEventHandler('keyup'); | 172 new _KeyboardEventHandler('keyup'); |
63 /** Accessor to provide a stream of KeyEvents on the desired target. */ | 173 /** Accessor to provide a stream of KeyEvents on the desired target. */ |
64 static EventStreamProvider<KeyEvent> keyPressEvent = | 174 static EventStreamProvider<KeyEvent> keyPressEvent = |
65 new _KeyboardEventHandler('keypress'); | 175 new _KeyboardEventHandler('keypress'); |
66 | 176 |
67 /** True if the altGraphKey is pressed during this event. */ | 177 /** True if the altGraphKey is pressed during this event. */ |
68 bool get altGraphKey => _parent.altGraphKey; | 178 bool get altGraphKey => _parent.altGraphKey; |
69 /** Accessor to the clipboardData available for this event. */ | 179 /** Accessor to the clipboardData available for this event. */ |
70 DataTransfer get clipboardData => _parent.clipboardData; | 180 DataTransfer get clipboardData => _parent.clipboardData; |
71 /** True if the ctrl key is pressed during this event. */ | 181 /** True if the ctrl key is pressed during this event. */ |
72 bool get ctrlKey => _parent.ctrlKey; | 182 bool get ctrlKey => _parent.ctrlKey; |
73 int get detail => _parent.detail; | 183 int get detail => _parent.detail; |
74 /** | 184 /** |
75 * Accessor to the part of the keyboard that the key was pressed from (one of | 185 * Accessor to the part of the keyboard that the key was pressed from (one of |
(...skipping 20 matching lines...) Expand all Loading... | |
96 throw new UnsupportedError("keyIdentifier is unsupported."); | 206 throw new UnsupportedError("keyIdentifier is unsupported."); |
97 } | 207 } |
98 void _initKeyboardEvent(String type, bool canBubble, bool cancelable, | 208 void _initKeyboardEvent(String type, bool canBubble, bool cancelable, |
99 Window view, String keyIdentifier, int keyLocation, bool ctrlKey, | 209 Window view, String keyIdentifier, int keyLocation, bool ctrlKey, |
100 bool altKey, bool shiftKey, bool metaKey, | 210 bool altKey, bool shiftKey, bool metaKey, |
101 bool altGraphKey) { | 211 bool altGraphKey) { |
102 throw new UnsupportedError( | 212 throw new UnsupportedError( |
103 "Cannot initialize a KeyboardEvent from a KeyEvent."); | 213 "Cannot initialize a KeyboardEvent from a KeyEvent."); |
104 } | 214 } |
105 } | 215 } |
OLD | NEW |