Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / ui / keyboard / resources / inputview_adapter.js
blob6955d71d86bb5bb909e283f9dd5a7078e3794c36
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 var CLOSURE_NO_DEPS=true;
7 var controller;
9 /**
10  * Armed callback to be triggered when a keyset changes.
11  * @type {{string:target function:callback}}
12  * @private
13  */
14 var keysetChangeListener_;
16 /**
17  * Registers a function, which may override a preexisting implementation.
18  * @param {string} path Full path for the function name.
19  * @param {function=} opt_fn Optional function definition. If not specified,
20  *     the default implementation prettyprints the method call with arguments.
21  * @return {function} Registered function, which may be a mock implementation.
22  */
23 function registerFunction(path, opt_fn) {
24   var parts = path.split('.');
25   var base = window;
26   var part = null;
27   var fn = opt_fn;
28   if (!fn) {
29     fn = function() {
30       var prettyprint = function(arg) {
31         if (arg instanceof Array) {
32           var terms = [];
33           for (var i = 0; i < arg.length; i++) {
34             terms.push(prettyprint(arg[i]));
35           }
36           return '[' + terms.join(', ') + ']';
37         } else if (typeof arg == 'object') {
38           var properties = [];
39           for (var key in arg) {
40              properties.push(key + ': ' + prettyprint(arg[key]));
41           }
42           return '{' + properties.join(', ') + '}';
43         } else {
44           return arg;
45         }
46       };
47       // The property 'arguments' is an array-like object. Convert to a true
48       // array for prettyprinting.
49       var args = Array.prototype.slice.call(arguments);
50       console.log('Call to ' + path + ': ' + prettyprint(args));
51     };
52   }
53   for (var i = 0; i < parts.length - 1; i++) {
54     part = parts[i];
55     if (!base[part]) {
56       base[part] = {};
57     }
58     base = base[part];
59   }
60   base[parts[parts.length - 1]] = fn;
61   return fn;
64 /**
65  * The chrome.i18n API is not compatible with component extensions due to the
66  * way component extensions are loaded (crbug/66834).
67  */
68 function overrideGetMessage() {
69   var originalGetMessage = chrome.i18n.getMessage;
71   /**
72    * Localize a string resource.
73    * @param {string} key The message key to localize.
74    * @return {string} Translated resource.
75    */
76   chrome.i18n.getMessage = function(key) {
77     if (key.indexOf('@@') == 0)
78       return originalGetMessage(key);
80     // TODO(kevers): Add support for other locales.
81     var table = i18n.input.chrome.inputview.TranslationTable;
82     var entry = table[key];
83     if (!entry)
84       entry = table[key.toLowerCase()];
85     return entry ? entry.message || '' : '';
86   };
89 /**
90  * Overrides call to switch keysets in order to catch when the keyboard
91  * is ready for input. Used to synchronize the start of automated
92  * virtual keyboard tests.
93  */
94 function overrideSwitchToKeyset() {
95   var KeyboardContainer = i18n.input.chrome.inputview.KeyboardContainer;
96   var switcher = KeyboardContainer.prototype.switchToKeyset;
97   KeyboardContainer.prototype.switchToKeyset = function() {
98     var success = switcher.apply(this, arguments);
99     if (success) {
100       // The first resize call forces resizing of the keyboard window.
101       // The second resize call forces a clean layout for chrome://keyboard.
102       controller.resize(false);
103       controller.resize(true);
104       var settings = controller.model_.settings;
105       settings.supportCompact = true;
106       if (keysetChangeListener_ &&
107           keysetChangeListener_.target == arguments[0]) {
108         var callback = keysetChangeListener_.callback;
109         keysetChangeListener_ = undefined;
110         callback();
111       }
112     }
113     return success;
114   };
118  * Arms a one time callback to invoke when the VK switches to the target keyset.
119  * Only one keyset change callback may be armed at any time. Used to synchronize
120  * tests and to track initial load time for the virtual keyboard.
121  * @param {string} keyset The target keyset.
122  * @param {function} callback The callback to invoke when the keyset becomes
123  *     active.
124  */
125 function onSwitchToKeyset(keyset, callback) {
126   if (keysetChangeListener_) {
127     console.error('A keyset change listener is already armed.');
128     return;
129   }
130   keysetChangeListener_ = {
131     target: keyset,
132     callback: callback
133   };
137  * Spatial data is used in conjunction with a language model to offer
138  * corrections for 'fat finger' typing and is not needed for the system VK.
139  */
140 function overrideGetSpatialData() {
141   var Controller = i18n.input.chrome.inputview.Controller;
142   Controller.prototype.getSpatialData_ = function() {};
145 // Plug in for API calls.
146 function registerInputviewApi() {
148   // Flag values for ctrl, alt and shift as defined by EventFlags
149   // in "event_constants.h".
150   // @enum {number}
151   var Modifier = {
152     NONE: 0,
153     ALT: 8,
154     CONTROL: 4,
155     SHIFT: 2
156   };
158   // Mapping from keyName to keyCode
159   var nonAlphaNumericKeycodes = {
160     Backspace: 0x08,
161     Tab: 0x09,
162     Enter: 0x0D,
163   };
165   /**
166    * Displays a console message containing the last runtime error.
167    * @private
168    */
169   function logIfError_() {
170     if (chrome.runtime.lastError) {
171       console.log(chrome.runtime.lastError);
172     }
173   }
175   /**
176    * Retrieve the preferred keyboard configuration.
177    * @param {function} callback The callback function for processing the
178    *     keyboard configuration.
179    * @private
180    */
181   function getKeyboardConfig_(callback) {
182     chrome.virtualKeyboardPrivate.getKeyboardConfig(callback);
183   }
185   /**
186    * Retrieve a list of all enabled input methods.
187    * @param {function} callback The callback function for processing the list
188    *     of enabled input methods.
189    * @private
190    */
191   function getInputMethods_(callback) {
192     if (chrome.inputMethodPrivate)
193       chrome.inputMethodPrivate.getInputMethods(callback);
194     else
195       callback([]);
196   }
198   /**
199    * Retrieve the name of the active input method.
200    * @param {function} callback The callback function for processing the
201    *     name of the active input mehtod.
202    * @private
203    */
204   function getCurrentInputMethod_(callback) {
205     if (chrome.inputMethodPrivate)
206       chrome.inputMethodPrivate.getCurrentInputMethod(callback);
207     else
208       callback('');
209   }
211   /**
212    * Changes the active input method.
213    * @param {string} inputMethodId The id of the input method to activate.
214    * @private
215    */
216   function switchToInputMethod_(inputMethodId) {
217     if (chrome.inputMethodPrivate)
218       chrome.inputMethodPrivate.setCurrentInputMethod(inputMethodId)
219   }
221   /**
222    * Opens the language settings for specifying and configuring input methods.
223    * @private
224    */
225   function openSettings_() {
226     chrome.virtualKeyboardPrivate.openSettings();
227   }
229   /**
230    * Dispatches a virtual key event. The system VK does not use the IME
231    * API as its primary role is to work in conjunction with a non-VK aware
232    * IME. Some reformatting of the key data is required to work with the
233    * virtualKeyboardPrivate API.
234    * @param {!Object} keyData Description of the key event.
235    */
236   function sendKeyEvent_(keyData) {
237     keyData.forEach(function(data) {
238       var charValue = data.key.length == 1 ? data.key.charCodeAt(0) : 0;
239       var keyCode = data.keyCode ? data.keyCode :
240           getKeyCode_(data.key, data.code);
241       var event = {
242         type: data.type,
243         charValue: charValue,
244         keyCode: keyCode,
245         keyName: data.code,
246         modifiers: Modifier.NONE
247       };
248       if (data.altKey)
249         event.modifers |= Modifier.ALT;
250       if (data.ctrlKey)
251         event.modifiers |= Modifier.CTRL;
252       if (data.shiftKey || data.capsLock)
253         event.modifiers |= Modifier.SHIFT;
254       chrome.virtualKeyboardPrivate.sendKeyEvent(event, logIfError_);
255     });
256   }
258   /**
259    * Computes keyCodes based on the US-101 keyboard for common keys.  Required
260    * to properly handle special keys such as backspace.
261    * @param {string} keyChar Character being typed.
262    * @param {string} keyName w3c name of the character.
263    */
264   function getKeyCode_(keyChar, keyName) {
265     var keyCode = nonAlphaNumericKeycodes[keyName];
266     if (keyCode)
267       return keyCode;
268     if (keyChar.length == 1) {
269       if (keyChar >= 'a' && keyChar <= 'z')
270         return keyChar.charCodeAt(0) - 32;
271       if (keyChar >= 'A' && keyChar <= 'Z')
272         return keyChar.charCodeAt(0);
273       if (keyChar >= '0' && keyChar <= '9')
274         return keyChar.charCodeAt(0);
275     }
276     return 0;
277   }
279   window.inputview = {
280     getKeyboardConfig: getKeyboardConfig_,
281     getInputMethods: getInputMethods_,
282     getCurrentInputMethod: getCurrentInputMethod_,
283     switchToInputMethod: switchToInputMethod_,
284     openSettings: openSettings_
285   };
287   registerFunction('chrome.input.ime.hideInputView', function() {
288     chrome.virtualKeyboardPrivate.hideKeyboard();
289     chrome.virtualKeyboardPrivate.lockKeyboard(false);
290   });
292   var defaultSendMessage = registerFunction('chrome.runtime.sendMessage');
293   registerFunction('chrome.runtime.sendMessage', function(message) {
294     if (message.type == 'send_key_event')
295       sendKeyEvent_(message.keyData);
296     else
297       defaultSendMessage(message);
298   });
303 registerFunction('chrome.runtime.getBackgroundPage', function() {
304   var callback = arguments[0];
305   callback();
307 registerFunction('chrome.runtime.sendMessage');
308 registerFunction('chrome.runtime.onMessage.addListener');
310 if (!chrome.i18n) {
311   chrome.i18n = {};
312   chrome.i18n.getMessage = function(name) {
313     return name;
314   }
318  * Trigger loading the virtual keyboard on completion of page load.
319  */
320 window.onload = function() {
321   var params = {};
322   var matches = window.location.href.match(/[#?].*$/);
323   if (matches && matches.length > 0) {
324     matches[0].slice(1).split('&').forEach(function(s) {
325       var pair = s.split('=');
326       params[pair[0]] = pair[1];
327     });
328   }
330   var keyset = params['id'] || 'us.compact.qwerty';
331   var languageCode = params['language'] || 'en';
332   var passwordLayout = params['passwordLayout'] || 'us';
333   var name = params['name'] || 'English';
335   overrideGetMessage();
336   overrideSwitchToKeyset();
337   overrideGetSpatialData();
338   registerInputviewApi();
339   i18n.input.chrome.inputview.Controller.DEV = true;
341   if (keyset != 'none') {
342     window.initializeVirtualKeyboard(keyset, languageCode, passwordLayout,
343         name);
344   }
348  * Run cleanup tasks.
349  */
350 window.onbeforeunload = function() {
351   if (controller)
352     goog.dispose(controller);
356  * Loads a virtual keyboard. If a keyboard was previously loaded, it is
357  * reinitialized with the new configuration.
358  * @param {string} keyset The keyboard keyset.
359  * @param {string} languageCode The language code for this keyboard.
360  * @param {string} passwordLayout The layout for password box.
361  * @param {string} name The input tool name.
362  * @param {Object=} opt_config Optional configuration settings.
363  */
364 window.initializeVirtualKeyboard = function(keyset, languageCode,
365     passwordLayout, name, opt_config) {
366   var Controller = i18n.input.chrome.inputview.Controller;
367   Controller.DISABLE_HWT = !(opt_config && opt_config.enableHwtForTesting);
368   onSwitchToKeyset(keyset, function() {
369     chrome.virtualKeyboardPrivate.keyboardLoaded();
370   });
371   if (controller)
372     controller.initialize(keyset, languageCode, passwordLayout, name);
373   else
374     controller = new Controller(keyset, languageCode, passwordLayout, name);