| 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 static _makeRecord() { |
| 59 var interceptor = findInterceptorForType(KeyboardEvent); |
| 60 return makeLeafDispatchRecord(interceptor); |
| 61 } |
| 62 |
| 47 /** Construct a KeyEvent with [parent] as the event we're emulating. */ | 63 /** Construct a KeyEvent with [parent] as the event we're emulating. */ |
| 48 KeyEvent(KeyboardEvent parent): super(parent) { | 64 KeyEvent.wrap(KeyboardEvent parent): super(parent) { |
| 49 _parent = parent; | 65 _parent = parent; |
| 50 _shadowAltKey = _realAltKey; | 66 _shadowAltKey = _realAltKey; |
| 51 _shadowCharCode = _realCharCode; | 67 _shadowCharCode = _realCharCode; |
| 52 _shadowKeyCode = _realKeyCode; | 68 _shadowKeyCode = _realKeyCode; |
| 69 _currentTarget = _parent.currentTarget; |
| 70 } |
| 71 |
| 72 /** Programmatically create a new KeyEvent (and KeyboardEvent). */ |
| 73 factory KeyEvent(String type, |
| 74 {Window view, bool canBubble: true, bool cancelable: true, int keyCode: 0, |
| 75 int charCode: 0, int keyLocation: 1, bool ctrlKey: false, |
| 76 bool altKey: false, bool shiftKey: false, bool metaKey: false, |
| 77 bool altGraphKey: false, EventTarget currentTarget}) { |
| 78 if (view == null) { |
| 79 view = window; |
| 80 } |
| 81 |
| 82 var eventObj; |
| 83 // In these two branches we create an underlying native KeyboardEvent, but |
| 84 // we set it with our specified values. Because we are doing custom setting |
| 85 // of certain values (charCode/keyCode, etc) only in this class (as opposed |
| 86 // to KeyboardEvent) and the way we set these custom values depends on the |
| 87 // type of underlying JS object, we do all the contruction for the |
| 88 // underlying KeyboardEvent here. |
| 89 if (canUseDispatchEvent) { |
| 90 // Currently works in everything but Internet Explorer. |
| 91 eventObj = new Event.eventType('Event', type, |
| 92 canBubble: canBubble, cancelable: cancelable); |
| 93 |
| 94 JS('void', '#.keyCode = #', eventObj, keyCode); |
| 95 JS('void', '#.which = #', eventObj, keyCode); |
| 96 JS('void', '#.charCode = #', eventObj, charCode); |
| 97 |
| 98 JS('void', '#.keyLocation = #', eventObj, keyLocation); |
| 99 JS('void', '#.ctrlKey = #', eventObj, ctrlKey); |
| 100 JS('void', '#.altKey = #', eventObj, altKey); |
| 101 JS('void', '#.shiftKey = #', eventObj, shiftKey); |
| 102 JS('void', '#.metaKey = #', eventObj, metaKey); |
| 103 JS('void', '#.altGraphKey = #', eventObj, altGraphKey); |
| 104 } else { |
| 105 // Currently this works on everything but Safari. Safari throws an |
| 106 // "Attempting to change access mechanism for an unconfigurable property" |
| 107 // TypeError when trying to do the Object.defineProperty hack, so we avoid |
| 108 // this branch if possible. |
| 109 // Also, if we want this branch to work in FF, we also need to modify |
| 110 // _initKeyboardEvent to also take charCode and keyCode values to |
| 111 // initialize initKeyEvent. |
| 112 |
| 113 eventObj = new Event.eventType('KeyboardEvent', type, |
| 114 canBubble: canBubble, cancelable: cancelable); |
| 115 |
| 116 // Chromium Hack |
| 117 JS('void', "Object.defineProperty(#, 'keyCode', {" |
| 118 " get : function() { return this.keyCodeVal; } })", eventObj); |
| 119 JS('void', "Object.defineProperty(#, 'which', {" |
| 120 " get : function() { return this.keyCodeVal; } })", eventObj); |
| 121 JS('void', "Object.defineProperty(#, 'charCode', {" |
| 122 " get : function() { return this.charCodeVal; } })", eventObj); |
| 123 |
| 124 var keyIdentifier = _convertToHexString(charCode, keyCode); |
| 125 eventObj._initKeyboardEvent(type, canBubble, cancelable, view, |
| 126 keyIdentifier, keyLocation, ctrlKey, altKey, shiftKey, metaKey, |
| 127 altGraphKey); |
| 128 JS('void', '#.keyCodeVal = #', eventObj, keyCode); |
| 129 JS('void', '#.charCodeVal = #', eventObj, charCode); |
| 130 } |
| 131 // Tell dart2js that it smells like a KeyboardEvent! |
| 132 setDispatchProperty(eventObj, _keyboardEventDispatchRecord); |
| 133 |
| 134 var keyEvent = new KeyEvent.wrap(eventObj); |
| 135 if (keyEvent._currentTarget == null) { |
| 136 keyEvent._currentTarget = currentTarget == null ? window : currentTarget; |
| 137 } |
| 138 return keyEvent; |
| 139 } |
| 140 |
| 141 // Currently known to work on all browsers but IE. |
| 142 static bool get canUseDispatchEvent => |
| 143 JS('bool', |
| 144 '(typeof document.body.dispatchEvent == "function")' |
| 145 '&& document.body.dispatchEvent.length > 0'); |
| 146 |
| 147 /** The currently registered target for this event. */ |
| 148 EventTarget get currentTarget => _currentTarget; |
| 149 |
| 150 // This is an experimental method to be sure. |
| 151 static String _convertToHexString(int charCode, int keyCode) { |
| 152 if (charCode != -1) { |
| 153 var hex = charCode.toRadixString(16); // Convert to hexadecimal. |
| 154 StringBuffer sb = new StringBuffer('U+'); |
| 155 for (int i = 0; i < 4 - hex.length; i++) sb.write('0'); |
| 156 sb.write(hex); |
| 157 return sb.toString(); |
| 158 } else { |
| 159 return KeyCode._convertKeyCodeToKeyName(keyCode); |
| 160 } |
| 53 } | 161 } |
| 54 | 162 |
| 55 // TODO(efortuna): If KeyEvent is sufficiently successful that we want to make | 163 // 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. | 164 // it the default keyboard event handling, move these methods over to Element. |
| 57 /** Accessor to provide a stream of KeyEvents on the desired target. */ | 165 /** Accessor to provide a stream of KeyEvents on the desired target. */ |
| 58 static EventStreamProvider<KeyEvent> keyDownEvent = | 166 static EventStreamProvider<KeyEvent> keyDownEvent = |
| 59 new _KeyboardEventHandler('keydown'); | 167 new _KeyboardEventHandler('keydown'); |
| 60 /** Accessor to provide a stream of KeyEvents on the desired target. */ | 168 /** Accessor to provide a stream of KeyEvents on the desired target. */ |
| 61 static EventStreamProvider<KeyEvent> keyUpEvent = | 169 static EventStreamProvider<KeyEvent> keyUpEvent = |
| 62 new _KeyboardEventHandler('keyup'); | 170 new _KeyboardEventHandler('keyup'); |
| 63 /** Accessor to provide a stream of KeyEvents on the desired target. */ | 171 /** Accessor to provide a stream of KeyEvents on the desired target. */ |
| 64 static EventStreamProvider<KeyEvent> keyPressEvent = | 172 static EventStreamProvider<KeyEvent> keyPressEvent = |
| 65 new _KeyboardEventHandler('keypress'); | 173 new _KeyboardEventHandler('keypress'); |
| 66 | 174 |
| 67 /** True if the altGraphKey is pressed during this event. */ | 175 /** True if the altGraphKey is pressed during this event. */ |
| 68 bool get altGraphKey => _parent.altGraphKey; | 176 bool get altGraphKey => _parent.altGraphKey; |
| 69 /** Accessor to the clipboardData available for this event. */ | 177 /** Accessor to the clipboardData available for this event. */ |
| 70 DataTransfer get clipboardData => _parent.clipboardData; | 178 DataTransfer get clipboardData => _parent.clipboardData; |
| 71 /** True if the ctrl key is pressed during this event. */ | 179 /** True if the ctrl key is pressed during this event. */ |
| 72 bool get ctrlKey => _parent.ctrlKey; | 180 bool get ctrlKey => _parent.ctrlKey; |
| 73 int get detail => _parent.detail; | 181 int get detail => _parent.detail; |
| 74 /** | 182 /** |
| 75 * Accessor to the part of the keyboard that the key was pressed from (one of | 183 * 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."); | 204 throw new UnsupportedError("keyIdentifier is unsupported."); |
| 97 } | 205 } |
| 98 void _initKeyboardEvent(String type, bool canBubble, bool cancelable, | 206 void _initKeyboardEvent(String type, bool canBubble, bool cancelable, |
| 99 Window view, String keyIdentifier, int keyLocation, bool ctrlKey, | 207 Window view, String keyIdentifier, int keyLocation, bool ctrlKey, |
| 100 bool altKey, bool shiftKey, bool metaKey, | 208 bool altKey, bool shiftKey, bool metaKey, |
| 101 bool altGraphKey) { | 209 bool altGraphKey) { |
| 102 throw new UnsupportedError( | 210 throw new UnsupportedError( |
| 103 "Cannot initialize a KeyboardEvent from a KeyEvent."); | 211 "Cannot initialize a KeyboardEvent from a KeyEvent."); |
| 104 } | 212 } |
| 105 } | 213 } |
| OLD | NEW |