| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public |  | 
| 2  * License, v. 2.0. If a copy of the MPL was not distributed with this |  | 
| 3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |  | 
| 4 |  | 
| 5 Cu.import("resource://gre/modules/Services.jsm"); |  | 
| 6 |  | 
| 7 let validModifiers = Object.create(null); |  | 
| 8 validModifiers.ACCEL = null; |  | 
| 9 validModifiers.CTRL = "control"; |  | 
| 10 validModifiers.CONTROL = "control"; |  | 
| 11 validModifiers.SHIFT = "shift"; |  | 
| 12 validModifiers.ALT = "alt"; |  | 
| 13 validModifiers.META = "meta"; |  | 
| 14 |  | 
| 15 let bindingsKeys = null; |  | 
| 16 (function() |  | 
| 17 { |  | 
| 18   let request = new XMLHttpRequest(); |  | 
| 19   request.open("GET", "chrome://global/content/platformHTMLBindings.xml"); |  | 
| 20   request.addEventListener("load", () => |  | 
| 21   { |  | 
| 22     bindingsKeys = request.responseXML.getElementsByTagName("handler"); |  | 
| 23   }); |  | 
| 24   request.send(); |  | 
| 25 })(); |  | 
| 26 |  | 
| 27 |  | 
| 28 /** |  | 
| 29  * Sets the correct value of validModifiers.ACCEL. |  | 
| 30  */ |  | 
| 31 function initAccelKey() |  | 
| 32 { |  | 
| 33   validModifiers.ACCEL = "control"; |  | 
| 34   try |  | 
| 35   { |  | 
| 36     let accelKey = Services.prefs.getIntPref("ui.key.accelKey"); |  | 
| 37     if (accelKey == Ci.nsIDOMKeyEvent.DOM_VK_CONTROL) |  | 
| 38       validModifiers.ACCEL = "control"; |  | 
| 39     else if (accelKey == Ci.nsIDOMKeyEvent.DOM_VK_ALT) |  | 
| 40       validModifiers.ACCEL = "alt"; |  | 
| 41     else if (accelKey == Ci.nsIDOMKeyEvent.DOM_VK_META) |  | 
| 42       validModifiers.ACCEL = "meta"; |  | 
| 43   } |  | 
| 44   catch(e) |  | 
| 45   { |  | 
| 46     Cu.reportError(e); |  | 
| 47   } |  | 
| 48 } |  | 
| 49 |  | 
| 50 exports.KeySelector = KeySelector; |  | 
| 51 |  | 
| 52 /** |  | 
| 53  * This class provides capabilities to find and use available keyboard shortcut |  | 
| 54  * keys. |  | 
| 55  * @param {ChromeWindow} window   the window where to look up existing shortcut |  | 
| 56  *                                keys |  | 
| 57  * @constructor |  | 
| 58  */ |  | 
| 59 function KeySelector(window) |  | 
| 60 { |  | 
| 61   this._initExistingShortcuts(window); |  | 
| 62 } |  | 
| 63 KeySelector.prototype = |  | 
| 64 { |  | 
| 65   /** |  | 
| 66    * Map listing existing shortcut keys as its keys. |  | 
| 67    * @type Object |  | 
| 68    */ |  | 
| 69   _existingShortcuts: null, |  | 
| 70 |  | 
| 71   /** |  | 
| 72    * Sets up _existingShortcuts property for a window. |  | 
| 73    */ |  | 
| 74   _initExistingShortcuts: function(/**ChromeWindow*/ window) |  | 
| 75   { |  | 
| 76     if (!validModifiers.ACCEL) |  | 
| 77       initAccelKey(); |  | 
| 78 |  | 
| 79     this._existingShortcuts = Object.create(null); |  | 
| 80 |  | 
| 81     let keys = Array.prototype.slice.apply(window.document.getElementsByTagName(
     "key")); |  | 
| 82     if (bindingsKeys) |  | 
| 83       keys.push.apply(keys, bindingsKeys); |  | 
| 84     for (let i = 0; i < keys.length; i++) |  | 
| 85     { |  | 
| 86       let key = keys[i]; |  | 
| 87       let keyData = |  | 
| 88       { |  | 
| 89         shift: false, |  | 
| 90         meta: false, |  | 
| 91         alt: false, |  | 
| 92         control: false, |  | 
| 93         char: null, |  | 
| 94         code: null |  | 
| 95       }; |  | 
| 96 |  | 
| 97       let keyChar = key.getAttribute("key"); |  | 
| 98       if (keyChar && keyChar.length == 1) |  | 
| 99         keyData.char = keyChar.toUpperCase(); |  | 
| 100 |  | 
| 101       let keyCode = key.getAttribute("keycode"); |  | 
| 102       if (keyCode && "DOM_" + keyCode.toUpperCase() in Ci.nsIDOMKeyEvent) |  | 
| 103         keyData.code = Ci.nsIDOMKeyEvent["DOM_" + keyCode.toUpperCase()]; |  | 
| 104 |  | 
| 105       if (!keyData.char && !keyData.code) |  | 
| 106         continue; |  | 
| 107 |  | 
| 108       let keyModifiers = key.getAttribute("modifiers"); |  | 
| 109       if (keyModifiers) |  | 
| 110         for (let modifier of keyModifiers.toUpperCase().match(/\w+/g)) |  | 
| 111           if (modifier in validModifiers) |  | 
| 112             keyData[validModifiers[modifier]] = true; |  | 
| 113 |  | 
| 114       let canonical = [keyData.shift, keyData.meta, keyData.alt, keyData.control
     , keyData.char || keyData.code].join(" "); |  | 
| 115       this._existingShortcuts[canonical] = true; |  | 
| 116     } |  | 
| 117   }, |  | 
| 118 |  | 
| 119   /** |  | 
| 120    * Selects a keyboard shortcut variant that isn't already taken, |  | 
| 121    * parses it into an object. |  | 
| 122    */ |  | 
| 123   selectKey: function(/**String*/ variants) /**Object*/ |  | 
| 124   { |  | 
| 125     for (let variant of variants.split(/\s*,\s*/)) |  | 
| 126     { |  | 
| 127       if (!variant) |  | 
| 128         continue; |  | 
| 129 |  | 
| 130       let keyData = |  | 
| 131       { |  | 
| 132         shift: false, |  | 
| 133         meta: false, |  | 
| 134         alt: false, |  | 
| 135         control: false, |  | 
| 136         char: null, |  | 
| 137         code: null, |  | 
| 138         codeName: null |  | 
| 139       }; |  | 
| 140       for (let part of variant.toUpperCase().split(/\s+/)) |  | 
| 141       { |  | 
| 142         if (part in validModifiers) |  | 
| 143           keyData[validModifiers[part]] = true; |  | 
| 144         else if (part.length == 1) |  | 
| 145           keyData.char = part; |  | 
| 146         else if ("DOM_VK_" + part in Ci.nsIDOMKeyEvent) |  | 
| 147         { |  | 
| 148           keyData.code = Ci.nsIDOMKeyEvent["DOM_VK_" + part]; |  | 
| 149           keyData.codeName = "VK_" + part; |  | 
| 150         } |  | 
| 151       } |  | 
| 152 |  | 
| 153       if (!keyData.char && !keyData.code) |  | 
| 154         continue; |  | 
| 155 |  | 
| 156       let canonical = [keyData.shift, keyData.meta, keyData.alt, keyData.control
     , keyData.char || keyData.code].join(" "); |  | 
| 157       if (canonical in this._existingShortcuts) |  | 
| 158         continue; |  | 
| 159 |  | 
| 160       return keyData; |  | 
| 161     } |  | 
| 162 |  | 
| 163     return null; |  | 
| 164   } |  | 
| 165 }; |  | 
| 166 |  | 
| 167 /** |  | 
| 168  * Creates the text representation for a key. |  | 
| 169  * @static |  | 
| 170  */ |  | 
| 171 KeySelector.getTextForKey = function (/**Object*/ key) /**String*/ |  | 
| 172 { |  | 
| 173   if (!key) |  | 
| 174     return null; |  | 
| 175 |  | 
| 176   if (!("text" in key)) |  | 
| 177   { |  | 
| 178     key.text = null; |  | 
| 179     try |  | 
| 180     { |  | 
| 181       let stringBundle = Services.strings.createBundle("chrome://global-platform
     /locale/platformKeys.properties"); |  | 
| 182       let parts = []; |  | 
| 183       if (key.control) |  | 
| 184         parts.push(stringBundle.GetStringFromName("VK_CONTROL")); |  | 
| 185       if (key.alt) |  | 
| 186         parts.push(stringBundle.GetStringFromName("VK_ALT")); |  | 
| 187       if (key.meta) |  | 
| 188         parts.push(stringBundle.GetStringFromName("VK_META")); |  | 
| 189       if (key.shift) |  | 
| 190         parts.push(stringBundle.GetStringFromName("VK_SHIFT")); |  | 
| 191       if (key.char) |  | 
| 192         parts.push(key.char.toUpperCase()); |  | 
| 193       else |  | 
| 194       { |  | 
| 195         let stringBundle2 = Services.strings.createBundle("chrome://global/local
     e/keys.properties"); |  | 
| 196         parts.push(stringBundle2.GetStringFromName(key.codeName)); |  | 
| 197       } |  | 
| 198       key.text = parts.join(stringBundle.GetStringFromName("MODIFIER_SEPARATOR")
     ); |  | 
| 199     } |  | 
| 200     catch (e) |  | 
| 201     { |  | 
| 202       Cu.reportError(e); |  | 
| 203       return null; |  | 
| 204     } |  | 
| 205   } |  | 
| 206   return key.text; |  | 
| 207 }; |  | 
| 208 |  | 
| 209 /** |  | 
| 210  * Tests whether a keypress event matches the given key. |  | 
| 211  * @static |  | 
| 212  */ |  | 
| 213 KeySelector.matchesKey = function(/**Event*/ event, /**Object*/ key) /**Boolean*
     / |  | 
| 214 { |  | 
| 215   if (event.defaultPrevented || !key) |  | 
| 216     return false; |  | 
| 217   if (key.shift != event.shiftKey || key.alt != event.altKey) |  | 
| 218     return false; |  | 
| 219   if (key.meta != event.metaKey || key.control != event.ctrlKey) |  | 
| 220     return false; |  | 
| 221 |  | 
| 222   if (key.char && event.charCode && String.fromCharCode(event.charCode).toUpperC
     ase() == key.char) |  | 
| 223     return true; |  | 
| 224   if (key.code && event.keyCode && event.keyCode == key.code) |  | 
| 225     return true; |  | 
| 226   return false; |  | 
| 227 }; |  | 
| OLD | NEW | 
|---|