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.
5 var CLOSURE_NO_DEPS=true;
10 * Armed callback to be triggered when a keyset changes.
11 * @type {{string:target function:callback}}
14 var keysetChangeListener_;
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.
23 function registerFunction(path, opt_fn) {
24 var parts = path.split('.');
30 var prettyprint = function(arg) {
31 if (arg instanceof Array) {
33 for (var i = 0; i < arg.length; i++) {
34 terms.push(prettyprint(arg[i]));
36 return '[' + terms.join(', ') + ']';
37 } else if (typeof arg == 'object') {
39 for (var key in arg) {
40 properties.push(key + ': ' + prettyprint(arg[key]));
42 return '{' + properties.join(', ') + '}';
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));
53 for (var i = 0; i < parts.length - 1; i++) {
60 base[parts[parts.length - 1]] = fn;
65 * The chrome.i18n API is not compatible with component extensions due to the
66 * way component extensions are loaded (crbug/66834).
68 function overrideGetMessage() {
69 var originalGetMessage = chrome.i18n.getMessage;
72 * Localize a string resource.
73 * @param {string} key The message key to localize.
74 * @return {string} Translated resource.
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];
84 entry = table[key.toLowerCase()];
85 return entry ? entry.message || '' : '';
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.
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);
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 // TODO (rsadam): Get rid of this hack. Currently this is needed to
111 // ensure the keyset was fully loaded before carrying on with the test.
112 setTimeout(callback, 0);
120 * Arms a one time callback to invoke when the VK switches to the target keyset.
121 * Only one keyset change callback may be armed at any time. Used to synchronize
122 * tests and to track initial load time for the virtual keyboard.
123 * @param {string} keyset The target keyset.
124 * @param {function} callback The callback to invoke when the keyset becomes
127 function onSwitchToKeyset(keyset, callback) {
128 if (keysetChangeListener_) {
129 console.error('A keyset change listener is already armed.');
132 keysetChangeListener_ = {
139 * Spatial data is used in conjunction with a language model to offer
140 * corrections for 'fat finger' typing and is not needed for the system VK.
142 function overrideGetSpatialData() {
143 var Controller = i18n.input.chrome.inputview.Controller;
144 Controller.prototype.getSpatialData_ = function() {};
147 // Plug in for API calls.
148 function registerInputviewApi() {
150 // Flag values for ctrl, alt and shift as defined by EventFlags
151 // in "event_constants.h".
160 // Mapping from keyName to keyCode (see ui::KeyEvent).
161 var nonAlphaNumericKeycodes = {
177 * Displays a console message containing the last runtime error.
180 function logIfError_() {
181 if (chrome.runtime.lastError) {
182 console.log(chrome.runtime.lastError);
186 function commitText_(text) {
187 chrome.virtualKeyboardPrivate.insertText(text, logIfError_);
191 * Retrieve the preferred keyboard configuration.
192 * @param {function} callback The callback function for processing the
193 * keyboard configuration.
196 function getKeyboardConfig_(callback) {
197 chrome.virtualKeyboardPrivate.getKeyboardConfig(callback);
201 * Retrieve a list of all enabled input methods.
202 * @param {function} callback The callback function for processing the list
203 * of enabled input methods.
206 function getInputMethods_(callback) {
207 if (chrome.inputMethodPrivate)
208 chrome.inputMethodPrivate.getInputMethods(callback);
214 * Retrieve the name of the active input method.
215 * @param {function} callback The callback function for processing the
216 * name of the active input mehtod.
219 function getCurrentInputMethod_(callback) {
220 if (chrome.inputMethodPrivate)
221 chrome.inputMethodPrivate.getCurrentInputMethod(callback);
227 * Retrieve the current input method configuration.
228 * @param {function} callback The callback function for processing the
229 * name of the active input mehtod.
232 function getInputMethodConfig_(callback) {
233 if (chrome.inputMethodPrivate)
234 chrome.inputMethodPrivate.getInputMethodConfig(callback);
240 * Changes the active input method.
241 * @param {string} inputMethodId The id of the input method to activate.
244 function switchToInputMethod_(inputMethodId) {
245 if (chrome.inputMethodPrivate)
246 chrome.inputMethodPrivate.setCurrentInputMethod(inputMethodId)
250 * Opens the language settings for specifying and configuring input methods.
253 function openSettings_() {
254 chrome.virtualKeyboardPrivate.openSettings();
258 * Dispatches a virtual key event. The system VK does not use the IME
259 * API as its primary role is to work in conjunction with a non-VK aware
260 * IME. Some reformatting of the key data is required to work with the
261 * virtualKeyboardPrivate API.
262 * @param {!Object} keyData Description of the key event.
264 function sendKeyEvent_(keyData) {
265 keyData.forEach(function(data) {
266 var charValue = data.key.length == 1 ? data.key.charCodeAt(0) : 0;
267 var keyCode = data.keyCode ? data.keyCode :
268 getKeyCode_(data.key, data.code);
271 charValue: charValue,
274 modifiers: Modifier.NONE
277 event.modifiers |= Modifier.ALT;
279 event.modifiers |= Modifier.CONTROL;
280 if (data.shiftKey || data.capsLock)
281 event.modifiers |= Modifier.SHIFT;
283 chrome.virtualKeyboardPrivate.sendKeyEvent(event, logIfError_);
288 * Computes keyCodes for use with ui::KeyEvent.
289 * @param {string} keyChar Character being typed.
290 * @param {string} keyName w3c name of the character.
292 function getKeyCode_(keyChar, keyName) {
293 var keyCode = nonAlphaNumericKeycodes[keyName];
297 var match = /Key([A-Z])/.exec(keyName);
299 return match[1].charCodeAt(0);
301 match = /Digit([0-9])/.exec(keyName);
303 return match[1].charCodeAt(0);
305 if (keyChar.length == 1) {
306 if (keyChar >= 'a' && keyChar <= 'z')
307 return keyChar.charCodeAt(0) - 32;
308 if (keyChar >= 'A' && keyChar <= 'Z')
309 return keyChar.charCodeAt(0);
310 if (keyChar >= '0' && keyChar <= '9')
311 return keyChar.charCodeAt(0);
317 commitText: commitText_,
318 getKeyboardConfig: getKeyboardConfig_,
319 getInputMethods: getInputMethods_,
320 getCurrentInputMethod: getCurrentInputMethod_,
321 getInputMethodConfig: getInputMethodConfig_,
322 switchToInputMethod: switchToInputMethod_,
323 openSettings: openSettings_
326 registerFunction('chrome.input.ime.hideInputView', function() {
327 chrome.virtualKeyboardPrivate.hideKeyboard();
328 chrome.virtualKeyboardPrivate.lockKeyboard(false);
331 var defaultSendMessage = registerFunction('chrome.runtime.sendMessage');
332 registerFunction('chrome.runtime.sendMessage', function(message) {
333 if (message.type == 'send_key_event')
334 sendKeyEvent_(message.keyData);
335 else if (message.type == 'commit_text')
336 commitText_(message.text);
338 defaultSendMessage(message);
344 registerFunction('chrome.runtime.getBackgroundPage', function() {
345 var callback = arguments[0];
348 registerFunction('chrome.runtime.sendMessage');
349 registerFunction('chrome.runtime.onMessage.addListener');
353 chrome.i18n.getMessage = function(name) {
360 * Trigger loading the virtual keyboard on completion of page load.
362 window.onload = function() {
364 var matches = window.location.href.match(/[#?].*$/);
365 if (matches && matches.length > 0) {
366 matches[0].slice(1).split('&').forEach(function(s) {
367 var pair = s.split('=');
368 params[pair[0]] = pair[1];
372 var keyset = params['id'] || 'us.compact.qwerty';
373 var languageCode = params['language'] || 'en';
374 var passwordLayout = params['passwordLayout'] || 'us';
375 var name = params['name'] || 'English';
377 overrideGetMessage();
378 overrideSwitchToKeyset();
379 overrideGetSpatialData();
380 registerInputviewApi();
381 i18n.input.chrome.inputview.Controller.DEV = true;
382 i18n.input.chrome.inputview.Adapter.prototype.isSwitching = function() {
386 if (keyset != 'none') {
387 window.initializeVirtualKeyboard(keyset, languageCode, passwordLayout,
395 window.onbeforeunload = function() {
397 goog.dispose(controller);
401 * Loads a virtual keyboard. If a keyboard was previously loaded, it is
402 * reinitialized with the new configuration.
403 * @param {string} keyset The keyboard keyset.
404 * @param {string} languageCode The language code for this keyboard.
405 * @param {string} passwordLayout The layout for password box.
406 * @param {string} name The input tool name.
407 * @param {Object=} opt_config Optional configuration settings.
409 window.initializeVirtualKeyboard = function(keyset, languageCode,
410 passwordLayout, name, opt_config) {
411 var Controller = i18n.input.chrome.inputview.Controller;
412 Controller.DISABLE_HWT = !(opt_config && opt_config.enableHwtForTesting);
413 onSwitchToKeyset(keyset, function() {
414 chrome.virtualKeyboardPrivate.keyboardLoaded();
417 controller.initialize(keyset, languageCode, passwordLayout, name);
419 controller = new Controller(keyset, languageCode, passwordLayout, name);