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