| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| var CLOSURE_NO_DEPS=true; |
| |
| var controller; |
| |
| /** |
| * Armed callback to be triggered when a keyset changes. |
| * @type {{string:target function:callback}} |
| * @private |
| */ |
| var keysetChangeListener_; |
| |
| /** |
| * Registers a function, which may override a preexisting implementation. |
| * @param {string} path Full path for the function name. |
| * @param {function=} opt_fn Optional function definition. If not specified, |
| * the default implementation prettyprints the method call with arguments. |
| * @return {function} Registered function, which may be a mock implementation. |
| */ |
| function registerFunction(path, opt_fn) { |
| var parts = path.split('.'); |
| var base = window; |
| var part = null; |
| var fn = opt_fn; |
| if (!fn) { |
| fn = function() { |
| var prettyprint = function(arg) { |
| if (arg instanceof Array) { |
| var terms = []; |
| for (var i = 0; i < arg.length; i++) { |
| terms.push(prettyprint(arg[i])); |
| } |
| return '[' + terms.join(', ') + ']'; |
| } else if (typeof arg == 'object') { |
| var properties = []; |
| for (var key in arg) { |
| properties.push(key + ': ' + prettyprint(arg[key])); |
| } |
| return '{' + properties.join(', ') + '}'; |
| } else { |
| return arg; |
| } |
| }; |
| // The property 'arguments' is an array-like object. Convert to a true |
| // array for prettyprinting. |
| var args = Array.prototype.slice.call(arguments); |
| console.log('Call to ' + path + ': ' + prettyprint(args)); |
| }; |
| } |
| for (var i = 0; i < parts.length - 1; i++) { |
| part = parts[i]; |
| if (!base[part]) { |
| base[part] = {}; |
| } |
| base = base[part]; |
| } |
| base[parts[parts.length - 1]] = fn; |
| return fn; |
| } |
| |
| /** |
| * The chrome.i18n API is not compatible with component extensions due to the |
| * way component extensions are loaded (crbug/66834). |
| */ |
| function overrideGetMessage() { |
| var originalGetMessage = chrome.i18n.getMessage; |
| |
| /** |
| * Localize a string resource. |
| * @param {string} key The message key to localize. |
| * @return {string} Translated resource. |
| */ |
| chrome.i18n.getMessage = function(key) { |
| if (key.startsWith('@@')) |
| return originalGetMessage(key); |
| |
| // TODO(kevers): Add support for other locales. |
| var table = i18n.input.chrome.inputview.TranslationTable; |
| var entry = table[key]; |
| if (!entry) |
| entry = table[key.toLowerCase()]; |
| return entry ? entry.message || '' : ''; |
| }; |
| }; |
| |
| /** |
| * Overrides call to switch keysets in order to catch when the keyboard |
| * is ready for input. Used to synchronize the start of automated |
| * virtual keyboard tests. |
| */ |
| function overrideSwitchToKeyset() { |
| var KeyboardContainer = i18n.input.chrome.inputview.KeyboardContainer; |
| var switcher = KeyboardContainer.prototype.switchToKeyset; |
| KeyboardContainer.prototype.switchToKeyset = function() { |
| var success = switcher.apply(this, arguments); |
| if (success) { |
| // The first resize call forces resizing of the keyboard window. |
| // The second resize call forces a clean layout for chrome://keyboard. |
| controller.resize(false); |
| controller.resize(true); |
| var settings = controller.model_.settings; |
| settings.supportCompact = true; |
| if (keysetChangeListener_ && |
| keysetChangeListener_.target == arguments[0]) { |
| var callback = keysetChangeListener_.callback; |
| keysetChangeListener_ = undefined; |
| // TODO (rsadam): Get rid of this hack. Currently this is needed to |
| // ensure the keyset was fully loaded before carrying on with the test. |
| setTimeout(callback, 0); |
| } |
| } |
| return success; |
| }; |
| } |
| |
| /** |
| * Arms a one time callback to invoke when the VK switches to the target keyset. |
| * Only one keyset change callback may be armed at any time. Used to synchronize |
| * tests and to track initial load time for the virtual keyboard. |
| * @param {string} keyset The target keyset. |
| * @param {function} callback The callback to invoke when the keyset becomes |
| * active. |
| */ |
| function onSwitchToKeyset(keyset, callback) { |
| if (keysetChangeListener_) { |
| console.error('A keyset change listener is already armed.'); |
| return; |
| } |
| keysetChangeListener_ = { |
| target: keyset, |
| callback: callback |
| }; |
| } |
| |
| /** |
| * Spatial data is used in conjunction with a language model to offer |
| * corrections for 'fat finger' typing and is not needed for the system VK. |
| */ |
| function overrideGetSpatialData() { |
| var Controller = i18n.input.chrome.inputview.Controller; |
| Controller.prototype.getSpatialData_ = function() {}; |
| } |
| |
| /** |
| * Return the most recently used US layout. By default, this will return the |
| * compact layout. |
| */ |
| function getDefaultUsLayout() { |
| return window.localStorage['vkDefaultLayoutIsFull'] |
| ? 'us' : 'us.compact.qwerty'; |
| } |
| |
| // Plug in for API calls. |
| function registerInputviewApi() { |
| |
| // Flag values for ctrl, alt and shift as defined by EventFlags |
| // in "event_constants.h". |
| // @enum {number} |
| var Modifier = { |
| NONE: 0, |
| ALT: 8, |
| CONTROL: 4, |
| SHIFT: 2, |
| CAPSLOCK: 256 |
| }; |
| |
| // Mapping from keyName to keyCode (see ui::KeyEvent). |
| var nonAlphaNumericKeycodes = { |
| Backquote: 0xC0, |
| Backslash: 0xDC, |
| Backspace: 0x08, |
| BracketLeft: 0xDB, |
| BracketRight: 0xDD, |
| Comma: 0xBC, |
| Enter: 0x0D, |
| Period: 0xBE, |
| Quote: 0xBF, |
| Semicolon: 0xBA, |
| Slash: 0xBF, |
| Space: 0x20, |
| Tab: 0x09 |
| }; |
| |
| /** |
| * Displays a console message containing the last runtime error. |
| * @private |
| */ |
| function logIfError_() { |
| if (chrome.runtime.lastError) { |
| console.log(chrome.runtime.lastError); |
| } |
| } |
| |
| function commitText_(text) { |
| chrome.virtualKeyboardPrivate.insertText(text, logIfError_); |
| } |
| |
| /** |
| * Retrieve the preferred keyboard configuration. |
| * @param {function} callback The callback function for processing the |
| * keyboard configuration. |
| * @private |
| */ |
| function getKeyboardConfig_(callback) { |
| chrome.virtualKeyboardPrivate.getKeyboardConfig(callback); |
| } |
| |
| /** |
| * Retrieve a list of all enabled input methods. |
| * @param {function} callback The callback function for processing the list |
| * of enabled input methods. |
| * @private |
| */ |
| function getInputMethods_(callback) { |
| if (chrome.inputMethodPrivate) |
| chrome.inputMethodPrivate.getInputMethods(callback); |
| else |
| callback([]); |
| } |
| |
| /** |
| * Retrieve the name of the active input method. |
| * @param {function} callback The callback function for processing the |
| * name of the active input mehtod. |
| * @private |
| */ |
| function getCurrentInputMethod_(callback) { |
| if (chrome.inputMethodPrivate) |
| chrome.inputMethodPrivate.getCurrentInputMethod(callback); |
| else |
| callback(''); |
| } |
| |
| /** |
| * Retrieve the current display size in inches. |
| * @param {function} callback |
| * @private |
| */ |
| function getDisplayInInches_(callback) { |
| callback(0); |
| } |
| |
| /** |
| * Retrieve the current input method configuration. |
| * @param {function} callback The callback function for processing the |
| * name of the active input mehtod. |
| * @private |
| */ |
| function getInputMethodConfig_(callback) { |
| if (chrome.inputMethodPrivate) |
| chrome.inputMethodPrivate.getInputMethodConfig(callback); |
| else |
| callback(''); |
| } |
| |
| /** |
| * Changes the active input method. |
| * @param {string} inputMethodId The id of the input method to activate. |
| * @private |
| */ |
| function switchToInputMethod_(inputMethodId) { |
| if (chrome.inputMethodPrivate) |
| chrome.inputMethodPrivate.setCurrentInputMethod(inputMethodId) |
| } |
| |
| /** |
| * Opens the language settings for specifying and configuring input methods. |
| * @private |
| */ |
| function openSettings_() { |
| chrome.virtualKeyboardPrivate.openSettings(); |
| } |
| |
| /** |
| * Dispatches a virtual key event. The system VK does not use the IME |
| * API as its primary role is to work in conjunction with a non-VK aware |
| * IME. Some reformatting of the key data is required to work with the |
| * virtualKeyboardPrivate API. |
| * @param {!Object} keyData Description of the key event. |
| */ |
| function sendKeyEvent_(keyData) { |
| keyData.forEach(function(data) { |
| var charValue = data.key.length == 1 ? data.key.charCodeAt(0) : 0; |
| var keyCode = data.keyCode ? data.keyCode : |
| getKeyCode_(data.key, data.code); |
| var event = { |
| type: data.type, |
| charValue: charValue, |
| keyCode: keyCode, |
| keyName: data.code, |
| modifiers: Modifier.NONE |
| }; |
| if (data.altKey) |
| event.modifiers |= Modifier.ALT; |
| if (data.ctrlKey) |
| event.modifiers |= Modifier.CONTROL; |
| if (data.shiftKey) |
| event.modifiers |= Modifier.SHIFT; |
| if (data.capsLock) |
| event.modifiers |= Modifier.CAPSLOCK; |
| |
| chrome.virtualKeyboardPrivate.sendKeyEvent(event, logIfError_); |
| }); |
| } |
| |
| /** |
| * Computes keyCodes for use with ui::KeyEvent. |
| * @param {string} keyChar Character being typed. |
| * @param {string} keyName w3c name of the character. |
| */ |
| function getKeyCode_(keyChar, keyName) { |
| var keyCode = nonAlphaNumericKeycodes[keyName]; |
| if (keyCode) |
| return keyCode; |
| |
| var match = /Key([A-Z])/.exec(keyName); |
| if (match) |
| return match[1].charCodeAt(0); |
| |
| match = /Digit([0-9])/.exec(keyName); |
| if (match) |
| return match[1].charCodeAt(0); |
| |
| if (keyChar.length == 1) { |
| if (keyChar >= 'a' && keyChar <= 'z') |
| return keyChar.charCodeAt(0) - 32; |
| if (keyChar >= 'A' && keyChar <= 'Z') |
| return keyChar.charCodeAt(0); |
| if (keyChar >= '0' && keyChar <= '9') |
| return keyChar.charCodeAt(0); |
| } |
| return 0; |
| } |
| |
| window.inputview = { |
| commitText: commitText_, |
| getKeyboardConfig: getKeyboardConfig_, |
| getInputMethods: getInputMethods_, |
| getCurrentInputMethod: getCurrentInputMethod_, |
| getInputMethodConfig: getInputMethodConfig_, |
| switchToInputMethod: switchToInputMethod_, |
| getDisplayInInches: getDisplayInInches_, |
| openSettings: openSettings_ |
| }; |
| |
| registerFunction('chrome.input.ime.hideInputView', function() { |
| chrome.virtualKeyboardPrivate.hideKeyboard(); |
| chrome.virtualKeyboardPrivate.lockKeyboard(false); |
| }); |
| |
| var defaultSendMessage = registerFunction('chrome.runtime.sendMessage'); |
| registerFunction('chrome.runtime.sendMessage', function(message) { |
| if (message.type == 'send_key_event') |
| sendKeyEvent_(message.keyData); |
| else if (message.type == 'commit_text') |
| commitText_(message.text); |
| else |
| defaultSendMessage(message); |
| }); |
| } |
| |
| registerFunction('chrome.runtime.getBackgroundPage', function() { |
| var callback = arguments[0]; |
| callback(); |
| }); |
| registerFunction('chrome.runtime.sendMessage'); |
| registerFunction('chrome.runtime.onMessage.addListener'); |
| |
| if (!chrome.i18n) { |
| chrome.i18n = {}; |
| chrome.i18n.getMessage = function(name) { |
| return name; |
| } |
| } |
| |
| /** |
| * Trigger loading the virtual keyboard on completion of page load. |
| */ |
| window.onload = function() { |
| var params = {}; |
| var matches = window.location.href.match(/[#?].*$/); |
| if (matches && matches.length > 0) { |
| matches[0].slice(1).split('&').forEach(function(s) { |
| var pair = s.split('='); |
| params[pair[0]] = pair[1]; |
| }); |
| } |
| |
| var keyset = params['id'] || getDefaultUsLayout(); |
| var languageCode = params['language'] || 'en'; |
| var passwordLayout = params['passwordLayout'] || 'us'; |
| var name = params['name'] || 'English'; |
| |
| overrideGetMessage(); |
| overrideSwitchToKeyset(); |
| overrideGetSpatialData(); |
| registerInputviewApi(); |
| i18n.input.chrome.inputview.Controller.DEV = true; |
| i18n.input.chrome.inputview.Adapter.prototype.isSwitching = function() { |
| return false; |
| }; |
| |
| if (keyset != 'none') { |
| window.initializeVirtualKeyboard(keyset, languageCode, passwordLayout, |
| name); |
| } |
| }; |
| |
| /** |
| * Run cleanup tasks. |
| */ |
| window.onbeforeunload = function() { |
| if (controller) |
| goog.dispose(controller); |
| }; |
| |
| /** |
| * Loads a virtual keyboard. If a keyboard was previously loaded, it is |
| * reinitialized with the new configuration. |
| * @param {string} keyset The keyboard keyset. |
| * @param {string} languageCode The language code for this keyboard. |
| * @param {string} passwordLayout The layout for password box. |
| * @param {string} name The input tool name. |
| * @param {Object=} opt_config Optional configuration settings. |
| */ |
| window.initializeVirtualKeyboard = function(keyset, languageCode, |
| passwordLayout, name, opt_config) { |
| var Controller = i18n.input.chrome.inputview.Controller; |
| Controller.DISABLE_HWT = !(opt_config && opt_config.enableHwtForTesting); |
| onSwitchToKeyset(keyset, function() { |
| chrome.virtualKeyboardPrivate.keyboardLoaded(); |
| }); |
| if (controller) |
| controller.initialize(keyset, languageCode, passwordLayout, name); |
| else |
| controller = new Controller(keyset, languageCode, passwordLayout, name); |
| }; |