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;
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
125 function onSwitchToKeyset(keyset, callback) {
126 if (keysetChangeListener_) {
127 console.error('A keyset change listener is already armed.');
130 keysetChangeListener_ = {
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.
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".
158 // Mapping from keyName to keyCode
159 var nonAlphaNumericKeycodes = {
166 * Displays a console message containing the last runtime error.
169 function logIfError_() {
170 if (chrome.runtime.lastError) {
171 console.log(chrome.runtime.lastError);
176 * Retrieve the preferred keyboard configuration.
177 * @param {function} callback The callback function for processing the
178 * keyboard configuration.
181 function getKeyboardConfig_(callback) {
182 chrome.virtualKeyboardPrivate.getKeyboardConfig(callback);
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.
191 function getInputMethods_(callback) {
192 if (chrome.inputMethodPrivate)
193 chrome.inputMethodPrivate.getInputMethods(callback);
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.
204 function getCurrentInputMethod_(callback) {
205 if (chrome.inputMethodPrivate)
206 chrome.inputMethodPrivate.getCurrentInputMethod(callback);
212 * Changes the active input method.
213 * @param {string} inputMethodId The id of the input method to activate.
216 function switchToInputMethod_(inputMethodId) {
217 if (chrome.inputMethodPrivate)
218 chrome.inputMethodPrivate.setCurrentInputMethod(inputMethodId)
222 * Opens the language settings for specifying and configuring input methods.
225 function openSettings_() {
226 chrome.virtualKeyboardPrivate.openSettings();
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.
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);
243 charValue: charValue,
246 modifiers: Modifier.NONE
249 event.modifers |= Modifier.ALT;
251 event.modifiers |= Modifier.CTRL;
252 if (data.shiftKey || data.capsLock)
253 event.modifiers |= Modifier.SHIFT;
254 chrome.virtualKeyboardPrivate.sendKeyEvent(event, logIfError_);
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.
264 function getKeyCode_(keyChar, keyName) {
265 var keyCode = nonAlphaNumericKeycodes[keyName];
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);
280 getKeyboardConfig: getKeyboardConfig_,
281 getInputMethods: getInputMethods_,
282 getCurrentInputMethod: getCurrentInputMethod_,
283 switchToInputMethod: switchToInputMethod_,
284 openSettings: openSettings_
287 registerFunction('chrome.input.ime.hideInputView', function() {
288 chrome.virtualKeyboardPrivate.hideKeyboard();
289 chrome.virtualKeyboardPrivate.lockKeyboard(false);
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);
297 defaultSendMessage(message);
303 registerFunction('chrome.runtime.getBackgroundPage', function() {
304 var callback = arguments[0];
307 registerFunction('chrome.runtime.sendMessage');
308 registerFunction('chrome.runtime.onMessage.addListener');
312 chrome.i18n.getMessage = function(name) {
318 * Trigger loading the virtual keyboard on completion of page load.
320 window.onload = function() {
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];
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,
350 window.onbeforeunload = function() {
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.
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();
372 controller.initialize(keyset, languageCode, passwordLayout, name);
374 controller = new Controller(keyset, languageCode, passwordLayout, name);