1 /** 2 * Copyright (C) 2012-2013 KO GmbH <copyright@kogmbh.com> 3 * 4 * @licstart 5 * This file is part of WebODF. 6 * 7 * WebODF is free software: you can redistribute it and/or modify it 8 * under the terms of the GNU Affero General Public License (GNU AGPL) 9 * as published by the Free Software Foundation, either version 3 of 10 * the License, or (at your option) any later version. 11 * 12 * WebODF is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU Affero General Public License for more details. 16 * 17 * You should have received a copy of the GNU Affero General Public License 18 * along with WebODF. If not, see <http://www.gnu.org/licenses/>. 19 * @licend 20 * 21 * @source: http://www.webodf.org/ 22 * @source: https://github.com/kogmbh/WebODF/ 23 */ 24 25 /*global gui, runtime */ 26 /*jslint bitwise: true*/ 27 28 /** 29 * @constructor 30 * @return {?} 31 */ 32 gui.KeyboardHandler = function KeyboardHandler() { 33 "use strict"; 34 var modifier = gui.KeyboardHandler.Modifier, 35 /**@type{?function(!KeyboardEvent):boolean}*/ 36 defaultBinding = null, 37 /**@type{!Object.<string,function():boolean>}*/ 38 bindings = {}; 39 40 /** 41 * @param {!KeyboardEvent} e 42 * @return {!number} 43 */ 44 function getModifiers(e) { 45 var modifiers = modifier.None; 46 if (e.metaKey) { modifiers |= modifier.Meta; } 47 if (e.ctrlKey) { modifiers |= modifier.Ctrl; } 48 if (e.altKey) { modifiers |= modifier.Alt; } 49 if (e.shiftKey) { modifiers |= modifier.Shift; } 50 return modifiers; 51 } 52 53 /** 54 * @param {!number} keyCode 55 * @param {!number} modifiers 56 * @return {!string} 57 */ 58 function getKeyCombo(keyCode, modifiers) { 59 if (!modifiers) { 60 modifiers = modifier.None; 61 } 62 // When a modifier key is pressed on it's own, different browsers + platforms 63 // may report the state of the corresponding modifier flag as trailing the event. 64 // For example, pressing the ctrl key in FF on Linux will report (ctrlKey:false) 65 // in the keydown event, while Chrome on Linux will report (ctrlKey:true) in the 66 // keydown event. 67 // 68 // Easiest way to cope with this is to manually normalize these events. 69 switch (keyCode) { 70 case gui.KeyboardHandler.KeyCode.LeftMeta: 71 case gui.KeyboardHandler.KeyCode.RightMeta: 72 case gui.KeyboardHandler.KeyCode.MetaInMozilla: 73 modifiers |= modifier.Meta; 74 break; 75 case gui.KeyboardHandler.KeyCode.Ctrl: 76 modifiers |= modifier.Ctrl; 77 break; 78 case gui.KeyboardHandler.KeyCode.Alt: 79 modifiers |= modifier.Alt; 80 break; 81 case gui.KeyboardHandler.KeyCode.Shift: 82 modifiers |= modifier.Shift; 83 break; 84 } 85 86 return keyCode + ':' + modifiers; 87 } 88 89 /** 90 * @param {?Function} callback 91 */ 92 this.setDefault = function (callback) { 93 defaultBinding = callback; 94 }; 95 96 /** 97 * Bind to the specified keycode + modifiers. To bind directly to one of the modifiers, simply 98 * pass in the modifier as the keyCode (e.g., Keycode.Ctrl), and set the modifiers to Modifier.None. 99 * This class will take care of binding to the appropriate modifiers to ensure the keybinding works as 100 * expected. 101 * 102 * @param {!number} keyCode 103 * @param {!number} modifiers 104 * @param {!Function} callback 105 * @param {boolean=} overwrite Set to true to force a binding to be overwritten 106 */ 107 this.bind = function (keyCode, modifiers, callback, overwrite) { 108 var keyCombo = getKeyCombo(keyCode, modifiers); 109 runtime.assert(overwrite || bindings.hasOwnProperty(keyCombo) === false, 110 "tried to overwrite the callback handler of key combo: " + keyCombo); 111 bindings[keyCombo] = callback; 112 }; 113 114 /** 115 * @param {!number} keyCode 116 * @param {!number} modifiers 117 */ 118 this.unbind = function (keyCode, modifiers) { 119 var keyCombo = getKeyCombo(keyCode, modifiers); 120 delete bindings[keyCombo]; 121 }; 122 123 /* 124 * removes all the bindings includes the default binding 125 */ 126 this.reset = function () { 127 defaultBinding = null; 128 bindings = {}; 129 }; 130 131 /** 132 * @param {!KeyboardEvent} e 133 */ 134 this.handleEvent = function (e) { 135 var keyCombo = getKeyCombo(e.keyCode, getModifiers(e)), 136 /**@type{function():boolean|undefined}*/ 137 callback = bindings[keyCombo], 138 handled = false; 139 140 if (callback) { 141 handled = callback(); 142 } else if (defaultBinding !== null) { 143 handled = defaultBinding(e); 144 } 145 146 if (handled) { 147 if (e.preventDefault) { 148 e.preventDefault(); 149 } else { 150 e.returnValue = false; 151 } 152 } 153 }; 154 }; 155 156 /**@const*/ 157 gui.KeyboardHandler.Modifier = { 158 None: 0, 159 Meta: 1, 160 Ctrl: 2, 161 Alt: 4, 162 CtrlAlt: 6, 163 Shift: 8, 164 MetaShift: 9, 165 CtrlShift: 10, 166 AltShift: 12 167 }; 168 169 /**@const*/ 170 gui.KeyboardHandler.KeyCode = { 171 Backspace: 8, 172 Tab: 9, 173 Clear: 12, 174 Enter: 13, 175 Shift: 16, 176 Ctrl: 17, 177 Alt: 18, 178 End: 35, 179 Home: 36, 180 Left: 37, 181 Up: 38, 182 Right: 39, 183 Down: 40, 184 Delete: 46, 185 A: 65, 186 B: 66, 187 C: 67, 188 D: 68, 189 E: 69, 190 F: 70, 191 G: 71, 192 H: 72, 193 I: 73, 194 J: 74, 195 K: 75, 196 L: 76, 197 M: 77, 198 N: 78, 199 O: 79, 200 P: 80, 201 Q: 81, 202 R: 82, 203 S: 83, 204 T: 84, 205 U: 85, 206 V: 86, 207 W: 87, 208 X: 88, 209 Y: 89, 210 Z: 90, 211 LeftMeta: 91, 212 RightMeta: 93, 213 MetaInMozilla: 224 214 }; 215