Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / google_input_tools / src / chrome / os / inputview / adapter.js
blob046a5d2a7bd3c351787b692473f616b3e6dc911d
1 // Copyright 2014 The ChromeOS IME Authors. All Rights Reserved.
2 // limitations under the License.
3 // See the License for the specific language governing permissions and
4 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5 // distributed under the License is distributed on an "AS-IS" BASIS,
6 // Unless required by applicable law or agreed to in writing, software
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // You may obtain a copy of the License at
11 // you may not use this file except in compliance with the License.
12 // Licensed under the Apache License, Version 2.0 (the "License");
14 goog.provide('i18n.input.chrome.inputview.Adapter');
16 goog.require('goog.events.Event');
17 goog.require('goog.events.EventHandler');
18 goog.require('goog.events.EventTarget');
19 goog.require('goog.events.EventType');
20 goog.require('goog.object');
21 goog.require('i18n.input.chrome.DataSource');
22 goog.require('i18n.input.chrome.inputview.FeatureName');
23 goog.require('i18n.input.chrome.inputview.FeatureTracker');
24 goog.require('i18n.input.chrome.inputview.ReadyState');
25 goog.require('i18n.input.chrome.inputview.StateType');
26 goog.require('i18n.input.chrome.inputview.events.EventType');
27 goog.require('i18n.input.chrome.inputview.events.MessageEvent');
28 goog.require('i18n.input.chrome.inputview.events.SurroundingTextChangedEvent');
29 goog.require('i18n.input.chrome.message');
30 goog.require('i18n.input.chrome.message.ContextType');
31 goog.require('i18n.input.chrome.message.Name');
32 goog.require('i18n.input.chrome.message.Type');
34 goog.scope(function() {
35 var CandidatesBackEvent = i18n.input.chrome.DataSource.CandidatesBackEvent;
36 var ContextType = i18n.input.chrome.message.ContextType;
37 var FeatureTracker = i18n.input.chrome.inputview.FeatureTracker;
38 var FeatureName = i18n.input.chrome.inputview.FeatureName;
39 var GesturesBackEvent = i18n.input.chrome.DataSource.GesturesBackEvent;
40 var Name = i18n.input.chrome.message.Name;
41 var State = i18n.input.chrome.inputview.ReadyState.State;
42 var Type = i18n.input.chrome.message.Type;
43 var events = i18n.input.chrome.inputview.events;
47 /**
48  * The adapter for interview.
49  *
50  * @param {!i18n.input.chrome.inputview.ReadyState} readyState .
51  * @extends {goog.events.EventTarget}
52  * @constructor
53  */
54 i18n.input.chrome.inputview.Adapter = function(readyState) {
55   goog.base(this);
57   /**
58    * Whether the keyboard is visible.
59    *
60    * @type {boolean}
61    */
62   this.isVisible = !document.webkitHidden;
64   /**
65    * The modifier state map.
66    *
67    * @type {!Object.<i18n.input.chrome.inputview.StateType, boolean>}
68    * @private
69    */
70   this.modifierState_ = {};
73   /**
74    * Tracker for which FeatureName are enabled.
75    *
76    * @type {!FeatureTracker};
77    */
78   this.features = new FeatureTracker();
81   /**
82    * The system ready state.
83    *
84    * @private {!i18n.input.chrome.inputview.ReadyState}
85    */
86   this.readyState_ = readyState;
88   chrome.runtime.onMessage.addListener(this.onMessage_.bind(this));
90   /** @private {!goog.events.EventHandler} */
91   this.handler_ = new goog.events.EventHandler(this);
92   this.handler_.
93       listen(document, 'webkitvisibilitychange', this.onVisibilityChange_).
94       // When screen rotate, will trigger resize event.
95       listen(window, goog.events.EventType.RESIZE, this.onVisibilityChange_);
97   // Notifies the initial visibility change message to background.
98   this.onVisibilityChange_();
100 goog.inherits(i18n.input.chrome.inputview.Adapter,
101     goog.events.EventTarget);
102 var Adapter = i18n.input.chrome.inputview.Adapter;
106  * URL prefixes of common Google sites.
108  * @enum {string}
109  */
110 Adapter.GoogleSites = {
111   // TODO: Add support for spreadsheets.
112   DOCS: 'https://docs.google.com/document/d'
116 /** @type {boolean} */
117 Adapter.prototype.isA11yMode = false;
120 /** @type {boolean} */
121 Adapter.prototype.isVoiceInputEnabled = true;
124 /** @type {boolean} */
125 Adapter.prototype.showGlobeKey = false;
128 /** @type {string} */
129 Adapter.prototype.contextType = ContextType.DEFAULT;
132 /** @type {string} */
133 Adapter.prototype.screen = '';
136 /** @type {boolean} */
137 Adapter.prototype.isChromeVoxOn = false;
140 /** @type {string} */
141 Adapter.prototype.textBeforeCursor = '';
144 /** @type {boolean} */
145 Adapter.prototype.isFloating = false;
149   * Whether the background controller is on switching.
150   *
151   * @private {boolean}
152   */
153 Adapter.prototype.isBgControllerSwitching_ = false;
157  * Callback for updating settings.
159  * @param {!Object} message .
160  * @private
161  */
162 Adapter.prototype.onUpdateSettings_ = function(message) {
163   this.screen = message[Name.SCREEN];
164   this.queryCurrentSite();
165   this.contextType = /** @type {string} */ (message[Name.CONTEXT_TYPE]);
166   // Resets the flag, since when inputview receive the update setting response,
167   // it means the background switching is done.
168   this.isBgControllerSwitching_ = false;
169   this.dispatchEvent(
170       new events.MessageEvent(events.EventType.UPDATE_SETTINGS, message));
175  * Sets the modifier states.
177  * @param {i18n.input.chrome.inputview.StateType} stateType .
178  * @param {boolean} enable True to enable the state, false otherwise.
179  */
180 Adapter.prototype.setModifierState = function(stateType, enable) {
181   this.modifierState_[stateType] = enable;
186  * Clears the modifier states.
187  */
188 Adapter.prototype.clearModifierStates = function() {
189   this.modifierState_ = {};
194  * Simulates to send 'keydown' and 'keyup' event.
196  * @param {string} key
197  * @param {string} code
198  * @param {number=} opt_keyCode The key code.
199  * @param {!Object=} opt_spatialData .
200  * @param {!Object.<{ctrl: boolean, shift: boolean}>=} opt_modifiers .
201  */
202 Adapter.prototype.sendKeyDownAndUpEvent = function(key, code, opt_keyCode,
203     opt_spatialData, opt_modifiers) {
204   this.sendKeyEvent_([
205     this.generateKeyboardEvent_(
206         goog.events.EventType.KEYDOWN,
207         key,
208         code,
209         opt_keyCode,
210         opt_spatialData,
211         opt_modifiers),
212     this.generateKeyboardEvent_(
213         goog.events.EventType.KEYUP,
214         key,
215         code,
216         opt_keyCode,
217         opt_spatialData,
218         opt_modifiers)
219   ]);
224  * Simulates to send 'keydown' event.
226  * @param {string} key
227  * @param {string} code
228  * @param {number=} opt_keyCode The key code.
229  * @param {!Object=} opt_spatialData .
230  */
231 Adapter.prototype.sendKeyDownEvent = function(key, code, opt_keyCode,
232     opt_spatialData) {
233   this.sendKeyEvent_([this.generateKeyboardEvent_(
234       goog.events.EventType.KEYDOWN, key, code, opt_keyCode,
235       opt_spatialData)]);
240  * Sets whether gesture editing is in progress.
242  * @param {boolean} inProgress
243  * @param {?boolean=} opt_isSwipe Whether it was triggered by a swipe.
244  */
245 Adapter.prototype.setGestureEditingInProgress = function(inProgress,
246     opt_isSwipe) {
247   chrome.runtime.sendMessage(
248       goog.object.create(
249           Name.TYPE, Type.SET_GESTURE_EDITING,
250           Name.IN_PROGRESS, inProgress,
251           Name.IS_SWIPE, opt_isSwipe));
256  * Sends a gesture typing event to the backend for decoding.
258  * @param {!Array.<!i18n.input.chrome.inputview.elements.content.
259  *                 GestureCanvasView.Point>} gestureData The gesture data
260  *                 (trail) to send.
261  */
262 Adapter.prototype.sendGestureEvent = function(gestureData) {
263   chrome.runtime.sendMessage(
264       goog.object.create(Name.TYPE, Type.SEND_GESTURE_EVENT, Name.GESTURE_DATA,
265           gestureData));
270  * Simulates to send 'keyup' event.
272  * @param {string} key
273  * @param {string} code
274  * @param {number=} opt_keyCode The key code.
275  * @param {!Object=} opt_spatialData .
276  */
277 Adapter.prototype.sendKeyUpEvent = function(key, code, opt_keyCode,
278     opt_spatialData) {
279   this.sendKeyEvent_([this.generateKeyboardEvent_(
280       goog.events.EventType.KEYUP, key, code, opt_keyCode, opt_spatialData)]);
285  * Use {@code chrome.input.ime.sendKeyEvents} to simulate key events.
287  * @param {!Array.<!Object.<string, string|boolean>>} keyData .
288  * @private
289  */
290 Adapter.prototype.sendKeyEvent_ = function(keyData) {
291   chrome.runtime.sendMessage(
292       goog.object.create(Name.TYPE, Type.SEND_KEY_EVENT, Name.KEY_DATA,
293           keyData));
298  * Sends an updated keyboard layout to the backend gesture typing decoder.
300  * @param {?Object} keyboardLayout The keyboard layout object to send.
301  */
302 Adapter.prototype.sendKeyboardLayout = function(keyboardLayout) {
303   chrome.runtime.sendMessage(
304       goog.object.create(Name.TYPE, Type.SEND_KEYBOARD_LAYOUT,
305           Name.KEYBOARD_LAYOUT, keyboardLayout));
310  * Generates a {@code ChromeKeyboardEvent} by given values.
312  * @param {string} type .
313  * @param {string} key The key.
314  * @param {string} code The code.
315  * @param {number=} opt_keyCode The key code.
316  * @param {!Object=} opt_spatialData .
317  * @param {!Object.<{ctrl: boolean, shift: boolean}>=} opt_modifiers .
318  * @return {!Object.<string, string|boolean>}
319  * @private
320  */
321 Adapter.prototype.generateKeyboardEvent_ = function(
322     type, key, code, opt_keyCode, opt_spatialData, opt_modifiers) {
323   var StateType = i18n.input.chrome.inputview.StateType;
324   var ctrl = !!this.modifierState_[StateType.CTRL];
325   var alt = !!this.modifierState_[StateType.ALT];
326   var shift = !!this.modifierState_[StateType.SHIFT];
328   if (opt_modifiers) {
329     if (opt_modifiers.ctrl)
330       ctrl = opt_modifiers.ctrl;
331     if (opt_modifiers.shift)
332       shift = opt_modifiers.shift;
333   }
335   if (ctrl || alt) {
336     key = '';
337   }
338   var result = {
339     'type': type,
340     'key': key,
341     'code': code,
342     'keyCode': opt_keyCode || 0,
343     'spatialData': opt_spatialData
344   };
346   result['altKey'] = alt;
347   result['ctrlKey'] = ctrl;
348   result['shiftKey'] = shift;
349   result['capsLock'] = !!this.modifierState_[StateType.CAPSLOCK];
351   return result;
356  * Callback when surrounding text is changed.
358  * @param {string} text .
359  * @param {number} anchor .
360  * @param {number} focus .
361  * @private
362  */
363 Adapter.prototype.onSurroundingTextChanged_ = function(text, anchor, focus) {
364   this.textBeforeCursor = text;
365   this.dispatchEvent(new i18n.input.chrome.inputview.events.
366       SurroundingTextChangedEvent(this.textBeforeCursor, anchor, focus));
371  * Gets the context.
373  * @return {string} .
374  */
375 Adapter.prototype.getContext = function() {
376   var matches = this.textBeforeCursor.match(/([a-zA-Z'-Ḁ-ỹÀ-ȳ]+)\s+$/);
377   var text = matches ? matches[1] : '';
378   return text;
383  * Sends request for handwriting.
385  * @param {!Object} payload .
386  */
387 Adapter.prototype.sendHwtRequest = function(payload) {
388   chrome.runtime.sendMessage(goog.object.create(
389       Name.TYPE, Type.HWT_REQUEST, Name.MSG, payload
390       ));
395  * True if it is a password box.
397  * @return {boolean} .
398  */
399 Adapter.prototype.isPasswordBox = function() {
400   return this.contextType == 'password';
405  * Whether the floating virtual keyboard feature is enabled.
407  * @return {boolean}
408  */
409 Adapter.prototype.isFloatingVirtualKeyboardEnabled = function() {
410   // This feature depends on setMode API. The api is a private API and may not
411   // be available all the time.
412   if (!inputview || !inputview.setMode) {
413     return false;
414   }
415   return this.features.isEnabled(FeatureName.FLOATING_VIRTUAL_KEYBOARD);
420  * Callback when blurs in the context.
422  * @private
423  */
424 Adapter.prototype.onContextBlur_ = function() {
425   this.contextType = '';
426   this.dispatchEvent(new goog.events.Event(i18n.input.chrome.inputview.events.
427       EventType.CONTEXT_BLUR));
432  * Asynchronously queries the current site.
433  */
434 Adapter.prototype.queryCurrentSite = function() {
435   var adapter = this;
436   var criteria = {'active': true, 'lastFocusedWindow': true};
437   if (chrome && chrome.tabs) {
438     chrome.tabs.query(criteria, function(tabs) {
439       tabs[0] && adapter.setCurrentSite_(tabs[0].url);
440     });
441   }
446  * Sets the current context URL.
448  * @param {string} url .
449  * @private
450  */
451 Adapter.prototype.setCurrentSite_ = function(url) {
452   if (url != this.currentSite_) {
453     this.currentSite_ = url;
454     this.dispatchEvent(new goog.events.Event(
455         i18n.input.chrome.inputview.events.EventType.URL_CHANGED));
456   }
461  * Returns whether the current context is Google Documents.
463  * @return {boolean} .
464  */
465 Adapter.prototype.isGoogleDocument = function() {
466   return this.currentSite_ &&
467       this.currentSite_.lastIndexOf(Adapter.GoogleSites.DOCS) === 0;
472  * Callback when focus on a context.
474  * @param {!Object<string, *>} message .
475  * @private
476  */
477 Adapter.prototype.onContextFocus_ = function(message) {
478   // URL might have changed.
479   this.queryCurrentSite();
481   this.contextType = /** @type {string} */ (message[Name.CONTEXT_TYPE]);
482   this.dispatchEvent(new goog.events.Event(
483       i18n.input.chrome.inputview.events.EventType.CONTEXT_FOCUS));
488  * Initializes the communication to background page.
490  * @private
491  */
492 Adapter.prototype.initBackground_ = function() {
493   chrome.runtime.getBackgroundPage((function() {
494     this.isBgControllerSwitching_ = true;
495     chrome.runtime.sendMessage(goog.object.create(
496         Name.TYPE, Type.CONNECT,
497         Name.VISIBILITY, this.isVisible));
498   }).bind(this));
503  * Loads the keyboard settings.
504  */
505 Adapter.prototype.initialize = function() {
506   if (chrome.accessibilityFeatures &&
507       chrome.accessibilityFeatures.spokenFeedback) {
508     chrome.accessibilityFeatures.spokenFeedback.get({}, (function(details) {
509       this.isChromeVoxOn = details['value'];
510     }).bind(this));
511     chrome.accessibilityFeatures.spokenFeedback.onChange.addListener((function(
512         details) {
513           if (!this.isChromeVoxOn && details['value']) {
514             this.dispatchEvent(new goog.events.Event(
515                 i18n.input.chrome.inputview.events.EventType.REFRESH));
516           }
517           this.isChromeVoxOn = details['value'];
518         }).bind(this));
519   }
521   this.initBackground_();
523   if (window.inputview) {
524     inputview.getKeyboardConfig((function(config) {
525       this.isA11yMode = !!config['a11ymode'];
526       this.features.initialize(config);
527       this.isVoiceInputEnabled =
528           this.features.isEnabled(FeatureName.VOICE_INPUT);
529       this.readyState_.markStateReady(State.KEYBOARD_CONFIG_READY);
530       this.maybeDispatchSettingsReadyEvent_();
531     }).bind(this));
532     inputview.getInputMethods((function(inputMethods) {
533       // Only show globe key to switching between IMEs when there are more
534       // than one IME.
535       this.showGlobeKey = inputMethods.length > 1;
536       this.readyState_.markStateReady(State.IME_LIST_READY);
537       this.maybeDispatchSettingsReadyEvent_();
538     }).bind(this));
539   } else {
540     this.readyState_.markStateReady(State.IME_LIST_READY);
541     this.readyState_.markStateReady(State.KEYBOARD_CONFIG_READY);
542   }
544   this.maybeDispatchSettingsReadyEvent_();
549  * Dispatch event SETTINGS_READY if all required bits are flipped.
551  * @private
552  */
553 Adapter.prototype.maybeDispatchSettingsReadyEvent_ = function() {
554   var states = [
555     State.KEYBOARD_CONFIG_READY,
556     State.IME_LIST_READY];
557   var ready = true;
558   for (var i = 0; i < states.length; i++) {
559     ready = ready && this.readyState_.isReady(states[i]);
560   }
561   if (ready) {
562     window.setTimeout((function() {
563       this.dispatchEvent(new goog.events.Event(
564           i18n.input.chrome.inputview.events.EventType.SETTINGS_READY));
565     }).bind(this), 0);
566   }
571  * Gets the currently activated input method.
573  * @param {function(string)} callback .
574  */
575 Adapter.prototype.getCurrentInputMethod = function(callback) {
576   if (window.inputview && inputview.getCurrentInputMethod) {
577     inputview.getCurrentInputMethod(callback);
578   } else {
579     callback('DU');
580   }
585  * Gets the list of all activated input methods.
587  * @param {function(Array.<Object>)} callback .
588  */
589 Adapter.prototype.getInputMethods = function(callback) {
590   if (window.inputview && inputview.getInputMethods) {
591     inputview.getInputMethods(callback);
592   } else {
593     // Provides a dummy IME item to enable IME switcher UI.
594     callback([
595       {'indicator': 'DU', 'id': 'DU', 'name': 'Dummy IME', 'command': 1}]);
596   }
601  * Switches to the input method with id equals |inputMethodId|.
603  * @param {!string} inputMethodId .
604  */
605 Adapter.prototype.switchToInputMethod = function(inputMethodId) {
606   if (window.inputview && inputview.switchToInputMethod) {
607     inputview.switchToInputMethod(inputMethodId);
608   }
613  * Callback for visibility change on the input view window.
615  * @private
616  */
617 Adapter.prototype.onVisibilityChange_ = function() {
618   this.isVisible = !document.webkitHidden;
619   this.dispatchEvent(new goog.events.Event(i18n.input.chrome.inputview.
620       events.EventType.VISIBILITY_CHANGE));
621   chrome.runtime.sendMessage(goog.object.create(
622       Name.TYPE, Type.VISIBILITY_CHANGE,
623       Name.VISIBILITY, !document.webkitHidden));
628  * Sends request for completion.
630  * @param {string} query .
631  * @param {!Object=} opt_spatialData .
632  */
633 Adapter.prototype.sendCompletionRequest = function(query, opt_spatialData) {
634   var spatialData = {};
635   if (opt_spatialData) {
636     spatialData[Name.SOURCES] = opt_spatialData.sources;
637     spatialData[Name.POSSIBILITIES] = opt_spatialData.possibilities;
638   }
639   chrome.runtime.sendMessage(goog.object.create(Name.TYPE,
640       Type.COMPLETION, Name.TEXT, query, Name.SPATIAL_DATA, spatialData));
645  * Selects the candidate.
647  * @param {!Object} candidate .
648  */
649 Adapter.prototype.selectCandidate = function(candidate) {
650   chrome.runtime.sendMessage(goog.object.create(
651       Name.TYPE, Type.SELECT_CANDIDATE, Name.CANDIDATE, candidate));
656  * Commits the text.
658  * @param {string} text .
659  */
660 Adapter.prototype.commitText = function(text) {
661   chrome.runtime.sendMessage(goog.object.create(
662       Name.TYPE, Type.COMMIT_TEXT, Name.TEXT, text));
667  * Commits the gesture result.
669  * @param {string} text .
670  */
671 Adapter.prototype.commitGestureResult = function(text) {
672   chrome.runtime.sendMessage(goog.object.create(
673       Name.TYPE, Type.CONFIRM_GESTURE_RESULT, Name.TEXT, text));
678  * Sets the language.
680  * @param {string} language .
681  */
682 Adapter.prototype.setLanguage = function(language) {
683   chrome.runtime.sendMessage(goog.object.create(
684       Name.TYPE, Type.SET_LANGUAGE, Name.LANGUAGE, language));
689  * Callbck when completion is back.
691  * @param {!Object} message .
692  * @private
693  */
694 Adapter.prototype.onCandidatesBack_ = function(message) {
695   var source = message['source'] || '';
696   var candidates = message['candidates'] || [];
697   this.dispatchEvent(new CandidatesBackEvent(source, candidates));
702  * Callbck when completion is back.
704  * @param {!Object} message .
705  * @private
706  */
707 Adapter.prototype.onGesturesBack_ = function(message) {
708   var results = message[Name.GESTURE_RESULTS];
709   this.dispatchEvent(new GesturesBackEvent(results));
714  * Hides the keyboard.
715  */
716 Adapter.prototype.hideKeyboard = function() {
717   chrome.input.ime.hideInputView();
722  * Sends DOUBLE_CLICK_ON_SPACE_KEY message.
723  */
724 Adapter.prototype.doubleClickOnSpaceKey = function() {
725   chrome.runtime.sendMessage(
726       goog.object.create(
727           Name.TYPE,
728           Type.DOUBLE_CLICK_ON_SPACE_KEY));
733  * Sends message to the background when do internal inputtool switch.
735  * @param {boolean} inputToolValue The value of the language flag.
736  */
737 Adapter.prototype.toggleLanguageState = function(inputToolValue) {
738   chrome.runtime.sendMessage(
739       goog.object.create(
740           Name.TYPE,
741           Type.TOGGLE_LANGUAGE_STATE,
742           Name.MSG,
743           inputToolValue));
748  * Processes incoming message from option page or inputview window.
750  * @param {*} request Message from option page or inputview window.
751  * @param {*} sender Information about the script
752  *     context that sent the message.
753  * @param {function(*): void} sendResponse Function to call to send a response.
754  * @return {boolean|undefined} {@code true} to keep the message channel open in
755  *     order to send a response asynchronously.
756  * @private
757  */
758 Adapter.prototype.onMessage_ = function(request, sender, sendResponse) {
759   var type = request[Name.TYPE];
760   var msg = request[Name.MSG];
761   if (!i18n.input.chrome.message.isFromBackground(type)) {
762     return;
763   }
764   switch (type) {
765     case Type.CANDIDATES_BACK:
766       this.onCandidatesBack_(msg);
767       break;
768     case Type.CONTEXT_FOCUS:
769       this.onContextFocus_(msg);
770       break;
771     case Type.CONTEXT_BLUR:
772       this.onContextBlur_();
773       break;
774     case Type.GESTURES_BACK:
775       this.onGesturesBack_(msg);
776       break;
777     case Type.SURROUNDING_TEXT_CHANGED:
778       this.onSurroundingTextChanged_(request[Name.TEXT],
779           request[Name.ANCHOR],
780           request[Name.FOCUS]);
781       break;
782     case Type.UPDATE_SETTINGS:
783       this.onUpdateSettings_(msg);
784       break;
785     case Type.VOICE_STATE_CHANGE:
786       this.dispatchEvent(
787           new events.MessageEvent(events.EventType.VOICE_STATE_CHANGE,
788               msg));
789       break;
790     case Type.HWT_NETWORK_ERROR:
791       this.dispatchEvent(
792           new events.MessageEvent(events.EventType.HWT_NETWORK_ERROR,
793               msg));
794       break;
795     case Type.FRONT_TOGGLE_LANGUAGE_STATE:
796       this.dispatchEvent(
797           new events.MessageEvent(events.EventType.FRONT_TOGGLE_LANGUAGE_STATE,
798               msg));
799       break;
800   }
805  * Sends the voice state to background.
807  * @param {boolean} state .
808  */
809 Adapter.prototype.sendVoiceViewStateChange = function(state) {
810   chrome.runtime.sendMessage(goog.object.create(
811       Name.TYPE, Type.VOICE_VIEW_STATE_CHANGE, Name.MSG, state));
815 /** @override */
816 Adapter.prototype.disposeInternal = function() {
817   goog.dispose(this.handler_);
819   goog.base(this, 'disposeInternal');
824  * Return the background IME switching state.
826  * @return {boolean}
827  */
828 Adapter.prototype.isSwitching = function() {
829   return this.isBgControllerSwitching_;
834  * Set the inputtool.
836  * @param {string} keyset The keyset.
837  * @param {string} languageCode The language code.
838  */
839 Adapter.prototype.setController = function(keyset, languageCode) {
840   chrome.runtime.sendMessage(
841       goog.object.create(
842           Name.TYPE,
843           Type.SET_CONTROLLER,
844           Name.MSG,
845           {'rawkeyset': keyset, 'languageCode': languageCode}));
850  * Unset the inputtool
851  */
852 Adapter.prototype.unsetController = function() {
853   chrome.runtime.sendMessage(
854       goog.object.create(
855           Name.TYPE,
856           Type.UNSET_CONTROLLER));
858 });  // goog.scope