| Index: third_party/google_input_tools/src/chrome/os/inputview/controller.js
|
| diff --git a/third_party/google_input_tools/src/chrome/os/inputview/controller.js b/third_party/google_input_tools/src/chrome/os/inputview/controller.js
|
| index 9c4d6ce0d9257ed2e216e19a5b2636c7ff44e3ac..3c52b078ddb6232dc123c5ffb94fd008487eb936 100644
|
| --- a/third_party/google_input_tools/src/chrome/os/inputview/controller.js
|
| +++ b/third_party/google_input_tools/src/chrome/os/inputview/controller.js
|
| @@ -22,15 +22,19 @@ goog.require('goog.events.Event');
|
| goog.require('goog.events.EventHandler');
|
| goog.require('goog.events.EventType');
|
| goog.require('goog.events.KeyCodes');
|
| +goog.require('goog.fx.easing');
|
| goog.require('goog.i18n.bidi');
|
| +goog.require('goog.math.Coordinate');
|
| goog.require('goog.object');
|
| goog.require('i18n.input.chrome.DataSource');
|
| +goog.require('i18n.input.chrome.ElementType');
|
| +goog.require('i18n.input.chrome.FeatureName');
|
| goog.require('i18n.input.chrome.Statistics');
|
| +goog.require('i18n.input.chrome.events.KeyCodes');
|
| goog.require('i18n.input.chrome.inputview.Adapter');
|
| goog.require('i18n.input.chrome.inputview.CandidatesInfo');
|
| goog.require('i18n.input.chrome.inputview.ConditionName');
|
| goog.require('i18n.input.chrome.inputview.Css');
|
| -goog.require('i18n.input.chrome.inputview.FeatureName');
|
| goog.require('i18n.input.chrome.inputview.KeyboardContainer');
|
| goog.require('i18n.input.chrome.inputview.M17nModel');
|
| goog.require('i18n.input.chrome.inputview.Model');
|
| @@ -41,13 +45,11 @@ goog.require('i18n.input.chrome.inputview.SizeSpec');
|
| goog.require('i18n.input.chrome.inputview.SpecNodeName');
|
| goog.require('i18n.input.chrome.inputview.StateType');
|
| goog.require('i18n.input.chrome.inputview.SwipeDirection');
|
| -goog.require('i18n.input.chrome.inputview.elements.ElementType');
|
| goog.require('i18n.input.chrome.inputview.elements.content.Candidate');
|
| goog.require('i18n.input.chrome.inputview.elements.content.CandidateView');
|
| goog.require('i18n.input.chrome.inputview.elements.content.ExpandedCandidateView');
|
| goog.require('i18n.input.chrome.inputview.elements.content.MenuView');
|
| goog.require('i18n.input.chrome.inputview.events.EventType');
|
| -goog.require('i18n.input.chrome.inputview.events.KeyCodes');
|
| goog.require('i18n.input.chrome.inputview.handler.PointerHandler');
|
| goog.require('i18n.input.chrome.inputview.util');
|
| goog.require('i18n.input.chrome.message.ContextType');
|
| @@ -64,13 +66,13 @@ var CandidateView = i18n.input.chrome.inputview.elements.content.CandidateView;
|
| var ConditionName = i18n.input.chrome.inputview.ConditionName;
|
| var ContextType = i18n.input.chrome.message.ContextType;
|
| var Css = i18n.input.chrome.inputview.Css;
|
| -var ElementType = i18n.input.chrome.inputview.elements.ElementType;
|
| +var ElementType = i18n.input.chrome.ElementType;
|
| var EventType = i18n.input.chrome.inputview.events.EventType;
|
| var ExpandedCandidateView = i18n.input.chrome.inputview.elements.content.
|
| ExpandedCandidateView;
|
| -var FeatureName = i18n.input.chrome.inputview.FeatureName;
|
| +var FeatureName = i18n.input.chrome.FeatureName;
|
| var InputToolCode = i18n.input.lang.InputToolCode;
|
| -var KeyCodes = i18n.input.chrome.inputview.events.KeyCodes;
|
| +var KeyCodes = i18n.input.chrome.events.KeyCodes;
|
| var MenuView = i18n.input.chrome.inputview.elements.content.MenuView;
|
| var Name = i18n.input.chrome.message.Name;
|
| var PerfTracker = i18n.input.chrome.inputview.PerfTracker;
|
| @@ -83,6 +85,62 @@ var events = i18n.input.chrome.inputview.events;
|
| var util = i18n.input.chrome.inputview.util;
|
|
|
|
|
| +/**
|
| + * Time in milliseconds after which backspace will start autorepeating.
|
| + * @const {number}
|
| + */
|
| +var BACKSPACE_REPEAT_START_TIME_MS = 300;
|
| +
|
| +
|
| +/**
|
| + * Minimum time, in milliseconds, after which backspace can repeat. This
|
| + * prevents deleting entire pages in a go.
|
| + * @const {number}
|
| + */
|
| +var MINIMUM_BACKSPACE_REPEAT_TIME_MS = 25;
|
| +
|
| +
|
| +/**
|
| + * Maximum time, in milliseconds, after which the backspace can repeat.
|
| + * @const {number}
|
| + */
|
| +var MAXIMUM_BACKSPACE_REPEAT_TIME_MS = 75;
|
| +
|
| +
|
| +/**
|
| + * The limit for backspace repeat for speeding up.
|
| + * The backspace repeat beyond this limit will have the maximum speed.
|
| + * @const {number}
|
| + */
|
| +var BACKSPACE_REPEAT_LIMIT = 255;
|
| +
|
| +
|
| +/**
|
| + * The time, in milliseconds, that the gesture preview window lingers before
|
| + * being dismissed.
|
| + *
|
| + * @const {number}
|
| + */
|
| +var GESTURE_PREVIEW_LINGER_TIME_MS = 250;
|
| +
|
| +
|
| +/**
|
| + * The maximum distance from the top of the keyboard that a gesture can move
|
| + * before it cancels the gesture typing gesture.
|
| + *
|
| + * @const {number}
|
| + */
|
| +var MAXIMUM_DISTANCE_FROM_TOP_FOR_GESTURES = 40;
|
| +
|
| +
|
| +/**
|
| + * The hotrod customized layout code.
|
| + *
|
| + * @const {string}
|
| + */
|
| +var HOTROD_DEFAULT_KEYSET = 'hotrod';
|
| +
|
| +
|
|
|
| /**
|
| * The controller of the input view keyboard.
|
| @@ -184,11 +242,11 @@ i18n.input.chrome.inputview.Controller = function(keyset, languageCode,
|
| this.soundController_ = new SoundController(false);
|
|
|
| /**
|
| - * Whether or not to commit the next gesture result.
|
| + * Whether or not the candidates were last set by gesture typing.
|
| *
|
| * @private {boolean}
|
| */
|
| - this.commitNextGestureResult_ = false;
|
| + this.candidatesSetByGestureTyping_ = false;
|
|
|
| /** @private {!i18n.input.chrome.inputview.KeyboardContainer} */
|
| this.container_ = new i18n.input.chrome.inputview.KeyboardContainer(
|
| @@ -256,9 +314,15 @@ i18n.input.chrome.inputview.Controller = function(keyset, languageCode,
|
|
|
| this.registerEventHandler_();
|
| };
|
| -goog.inherits(i18n.input.chrome.inputview.Controller,
|
| - goog.Disposable);
|
| +goog.inherits(i18n.input.chrome.inputview.Controller, goog.Disposable);
|
| var Controller = i18n.input.chrome.inputview.Controller;
|
| +var Statistics = i18n.input.chrome.Statistics;
|
| +
|
| +/**
|
| + * @define {boolean} Flag to disable delayed loading of non active keyset. It
|
| + * should only be used in testing.
|
| + */
|
| +Controller.DISABLE_DELAY_LOADING_FOR_TEST = false;
|
|
|
|
|
| /**
|
| @@ -300,15 +364,6 @@ Controller.EMOJI_VIEW_CODE_ = 'emoji';
|
|
|
|
|
| /**
|
| - * The limitation for backspace repeat time to avoid unexpected
|
| - * problem that backspace is held all the time.
|
| - *
|
| - * @private {number}
|
| - */
|
| -Controller.BACKSPACE_REPEAT_LIMIT_ = 255;
|
| -
|
| -
|
| -/**
|
| * The repeated times of the backspace.
|
| *
|
| * @private {number}
|
| @@ -326,12 +381,12 @@ Controller.HANDWRITING_CODE_SUFFIX_ = '-t-i0-handwrit';
|
|
|
|
|
| /**
|
| - * The US English compact layout prefix.
|
| + * The US English compact layout qwerty code.
|
| *
|
| * @const {string}
|
| * @private
|
| */
|
| -Controller.US_COMPACT_PREFIX_ = 'us.compact';
|
| +Controller.US_COMPACT_QWERTY_CODE_ = 'us.compact.qwerty';
|
|
|
|
|
| /**
|
| @@ -617,7 +672,9 @@ Controller.prototype.onUpdateSettings_ = function(e) {
|
| }
|
| if (goog.isDef(e.msg['gestureEditing'])) {
|
| settings.gestureEditing = e.msg['gestureEditing'];
|
| - var enabled = settings.gestureEditing && !this.adapter_.isA11yMode;
|
| + var enabled = settings.gestureEditing && !this.adapter_.isA11yMode &&
|
| + !this.adapter_.isHotrod &&
|
| + !this.adapter_.isFloatingVirtualKeyboardEnabled();
|
| this.container_.swipeView.enabled = enabled;
|
| this.container_.selectView.setSettingsEnabled(enabled);
|
| }
|
| @@ -661,20 +718,19 @@ Controller.prototype.onSettingsReady_ = function() {
|
| var newKeyset = '';
|
| if (this.adapter_.isA11yMode) {
|
| newKeyset = util.getConfigName(keysetMap[ContextType.DEFAULT]);
|
| + } else if (this.adapter_.isHotrod) {
|
| + newKeyset = HOTROD_DEFAULT_KEYSET;
|
| } else {
|
| newKeyset = /** @type {string} */ (this.model_.settings.
|
| getPreference(util.getConfigName(keysetMap[ContextType.DEFAULT])));
|
| }
|
| - if (!this.adapter_.features.isEnabled(FeatureName.EXPERIMENTAL) &&
|
| - keysetMap[ContextType.DEFAULT] ==
|
| - 'zhuyin.compact.qwerty') {
|
| - newKeyset = 'zhuyin';
|
| - }
|
| +
|
| if (newKeyset) {
|
| this.setDefaultKeyset_(newKeyset);
|
| }
|
| this.container_.selectView.setSettingsEnabled(
|
| - this.model_.settings.gestureEditing && !this.adapter_.isA11yMode);
|
| + this.model_.settings.gestureEditing && !this.adapter_.isA11yMode &&
|
| + !this.adapter_.isHotrod);
|
| // Loads resources in case the default keyset is changed.
|
| this.loadAllResources_();
|
| this.maybeCreateViews_();
|
| @@ -689,7 +745,13 @@ Controller.prototype.onSettingsReady_ = function() {
|
| */
|
| Controller.prototype.gestureTypingEnabled_ = function() {
|
| return this.isKeysetUSCompact_ && this.model_.settings.gestureTyping &&
|
| - !this.adapter_.isA11yMode && !this.adapter_.isChromeVoxOn;
|
| + !this.adapter_.isA11yMode && !this.adapter_.isHotrod &&
|
| + !this.adapter_.isChromeVoxOn &&
|
| + !this.adapter_.isPasswordBox() &&
|
| + !this.adapter_.isFloatingVirtualKeyboardEnabled() &&
|
| + !this.container_.altDataView.isVisible() &&
|
| + !this.container_.menuView.isVisible() &&
|
| + !this.container_.voiceView.isVisible();
|
| };
|
|
|
|
|
| @@ -748,13 +810,13 @@ Controller.prototype.getSpatialData_ = function(key, x, y) {
|
| * @private
|
| */
|
| Controller.prototype.getKeyContent_ = function(key) {
|
| - if (key.type == i18n.input.chrome.inputview.elements.ElementType.
|
| + if (key.type == i18n.input.chrome.ElementType.
|
| CHARACTER_KEY) {
|
| key = /** @type {!i18n.input.chrome.inputview.elements.content.
|
| CharacterKey} */ (key);
|
| return key.getActiveCharacter();
|
| }
|
| - if (key.type == i18n.input.chrome.inputview.elements.ElementType.
|
| + if (key.type == i18n.input.chrome.ElementType.
|
| COMPACT_KEY) {
|
| key = /** @type {!i18n.input.chrome.inputview.elements.content.
|
| FunctionalKey} */ (key);
|
| @@ -833,7 +895,7 @@ Controller.prototype.maybeSendLastStroke_ = function(opt_force) {
|
| if (lastStroke) {
|
| // This call will set up the necessary callbacks the decoder will use to
|
| // communicate back to this class.
|
| - this.adapter_.sendGestureEvent(lastStroke.points);
|
| + this.adapter_.sendGestureEvent(lastStroke.getPoints());
|
| }
|
| };
|
|
|
| @@ -848,13 +910,30 @@ Controller.prototype.maybeSendLastStroke_ = function(opt_force) {
|
| Controller.prototype.onDragEvent_ = function(e) {
|
| if (this.gestureTypingEnabled_() && e.type == EventType.DRAG &&
|
| !this.container_.swipeView.isVisible()) {
|
| + // Conveniently, the DragEvent has coordinates relative to the gesture
|
| + // canvas view, so we can test it's y coordinate in order to determine if
|
| + // we're off the canvas.
|
| + if (e.y + MAXIMUM_DISTANCE_FROM_TOP_FOR_GESTURES < 0) {
|
| + this.container_.gestureCanvasView.clear();
|
| + this.container_.gesturePreviewWindow.hide();
|
| + this.clearCandidates_();
|
| + return;
|
| + }
|
| this.container_.gestureCanvasView.addPoint(e);
|
| if (e.view && this.container_.gestureCanvasView.isGesturing) {
|
| // Ensure the last touched key is not highlighted.
|
| - e.view.setHighlighted(false);
|
| + if (e.view.type != ElementType.MODIFIER_KEY) {
|
| + e.view.setHighlighted(false);
|
| + }
|
| this.maybeSendLastStroke_();
|
| + // Reposition the gesture preview window to follow the user's touch point.
|
| + if (this.container_.gesturePreviewWindow &&
|
| + this.container_.gestureCanvasView.isActiveIdentifier(
|
| + e.identifier)) {
|
| + this.container_.gesturePreviewWindow.reposition(
|
| + new goog.math.Coordinate(e.x, e.y));
|
| + }
|
| }
|
| - return;
|
| }
|
| };
|
|
|
| @@ -949,29 +1028,29 @@ Controller.prototype.executeCommand_ = function(command, opt_arg) {
|
| inputview.openSettings();
|
| }
|
| break;
|
| + }
|
| +};
|
|
|
| - case CommandEnum.FLOATING:
|
| - if (inputview.setMode) {
|
| - inputview.setMode('FLOATING');
|
| - this.adapter_.isFloating = true;
|
| - this.container_.candidateView.setFloatingVKButtonsVisible(true);
|
| - this.resize();
|
| - setTimeout(function() {
|
| - var x = Math.floor((screen.width - window.innerWidth) / 2);
|
| - window.moveTo(x, window.screenY);
|
| - }, 0);
|
| - }
|
| - break;
|
| -
|
| - case CommandEnum.DOCKING:
|
| - if (inputview.setMode) {
|
| - inputview.setMode('FULL_WIDTH');
|
| - this.adapter_.isFloating = false;
|
| - this.container_.candidateView.setFloatingVKButtonsVisible(false);
|
| - }
|
| - break;
|
|
|
| +/**
|
| + * Returns the gesture typing event type for a given candidate ID.
|
| + *
|
| + * @param {number} candidateID The candidate ID to convert.
|
| + * @return {?i18n.input.chrome.Statistics.GestureTypingEvent} The gesture
|
| + * typing event type for the given candidate. Null if the candidate was not
|
| + * found.
|
| + * @private
|
| + */
|
| +Controller.prototype.getGestureEventTypeForCandidateID_ =
|
| + function(candidateID) {
|
| + if (candidateID == 0) {
|
| + return Statistics.GestureTypingEvent.REPLACED_0;
|
| + } else if (candidateID == 1) {
|
| + return Statistics.GestureTypingEvent.REPLACED_1;
|
| + } else if (candidateID >= 2) {
|
| + return Statistics.GestureTypingEvent.REPLACED_2;
|
| }
|
| + return null;
|
| };
|
|
|
|
|
| @@ -985,8 +1064,12 @@ Controller.prototype.executeCommand_ = function(command, opt_arg) {
|
| Controller.prototype.handlePointerAction_ = function(view, e) {
|
| if (this.gestureTypingEnabled_() && !this.container_.swipeView.isVisible()) {
|
| if (e.type == EventType.POINTER_DOWN) {
|
| + // Do some clean up before starting a new stroke.
|
| + this.container_.gestureCanvasView.removeEmptyStrokes();
|
| this.container_.gestureCanvasView.startStroke(e);
|
| - view.setHighlighted(false);
|
| + if (view.type != ElementType.MODIFIER_KEY) {
|
| + view.setHighlighted(false);
|
| + }
|
| }
|
|
|
| // Determine if the gestureCanvasView was handling a gesture before calling
|
| @@ -995,12 +1078,13 @@ Controller.prototype.handlePointerAction_ = function(view, e) {
|
| if (e.type == EventType.POINTER_UP && wasGesturing) {
|
| this.container_.gestureCanvasView.endStroke(e);
|
| this.maybeSendLastStroke_(true);
|
| - this.commitNextGestureResult_ = true;
|
| }
|
|
|
| // Do not trigger other activities when gesturing.
|
| if (wasGesturing) {
|
| - if (e.type == EventType.POINTER_OVER) {
|
| + if (view.type != ElementType.MODIFIER_KEY &&
|
| + (e.type == EventType.POINTER_OVER ||
|
| + e.type == EventType.POINTER_OUT)) {
|
| view.setHighlighted(false);
|
| }
|
| return;
|
| @@ -1018,19 +1102,13 @@ Controller.prototype.handlePointerAction_ = function(view, e) {
|
| this.handleSwipeAction_(view, e);
|
| }
|
| switch (view.type) {
|
| - case ElementType.KEYBOARD_CONTAINER_VIEW:
|
| - if (e.type == EventType.POINTER_DOWN) {
|
| - var tabbableKeysets = [
|
| - Controller.HANDWRITING_VIEW_CODE_,
|
| - Controller.EMOJI_VIEW_CODE_];
|
| - if (goog.array.contains(tabbableKeysets, this.currentKeyset_)) {
|
| - this.resetAll();
|
| - this.switchToKeyset(this.container_.currentKeysetView.fromKeyset);
|
| - }
|
| - }
|
| - return;
|
| + case ElementType.HOTROD_SWITCHER_KEY:
|
| case ElementType.BACK_BUTTON:
|
| case ElementType.BACK_TO_KEYBOARD:
|
| + if (view.type == ElementType.HOTROD_SWITCHER_KEY &&
|
| + !this.adapter_.isHotrod) {
|
| + return;
|
| + }
|
| if (e.type == EventType.POINTER_OUT || e.type == EventType.POINTER_UP) {
|
| view.setHighlighted(false);
|
| } else if (e.type == EventType.POINTER_DOWN ||
|
| @@ -1038,7 +1116,12 @@ Controller.prototype.handlePointerAction_ = function(view, e) {
|
| view.setHighlighted(true);
|
| }
|
| if (e.type == EventType.POINTER_UP) {
|
| - this.switchToKeyset(this.container_.currentKeysetView.fromKeyset);
|
| + var backToKeyset = this.container_.currentKeysetView.fromKeyset;
|
| + if (view.type == ElementType.HOTROD_SWITCHER_KEY &&
|
| + this.adapter_.isHotrod) {
|
| + backToKeyset = Controller.US_COMPACT_QWERTY_CODE_;
|
| + }
|
| + this.switchToKeyset(backToKeyset);
|
| this.clearCandidates_();
|
| this.soundController_.onKeyUp(view.type);
|
| }
|
| @@ -1067,6 +1150,16 @@ Controller.prototype.handlePointerAction_ = function(view, e) {
|
| if (e.type == EventType.POINTER_UP) {
|
| if (view.candidateType == CandidateType.CANDIDATE) {
|
| this.adapter_.selectCandidate(view.candidate);
|
| + if (this.candidatesSetByGestureTyping_) {
|
| + var type = this.getGestureEventTypeForCandidateID_(
|
| + view.candidate[Name.CANDIDATE_ID]);
|
| + if (type) {
|
| + this.statistics_.recordEnum(
|
| + Statistics.GESTURE_TYPING_METRIC_NAME,
|
| + type,
|
| + Statistics.GestureTypingEvent.MAX);
|
| + }
|
| + }
|
| } else if (view.candidateType == CandidateType.NUMBER) {
|
| this.adapter_.sendKeyDownAndUpEvent(
|
| view.candidate[Name.CANDIDATE], '');
|
| @@ -1099,6 +1192,10 @@ Controller.prototype.handlePointerAction_ = function(view, e) {
|
| return;
|
|
|
| case ElementType.MENU_ITEM:
|
| + if (this.adapter_.isHotrod) {
|
| + // Disable menu items in hotrod. Fix this if hotrod needs i18n support.
|
| + return;
|
| + }
|
| view = /** @type {!i18n.input.chrome.inputview.elements.content.
|
| MenuItem} */ (view);
|
| if (e.type == EventType.POINTER_UP) {
|
| @@ -1174,12 +1271,6 @@ Controller.prototype.handlePointerAction_ = function(view, e) {
|
| this.container_.floatingView.hide();
|
| }
|
| return;
|
| - case ElementType.RESIZE:
|
| - if (e.type == EventType.POINTER_UP) {
|
| - goog.dom.classlist.toggle(this.container_.getElement(), Css.SMALL);
|
| - this.resize();
|
| - }
|
| - return;
|
| case ElementType.CUT:
|
| case ElementType.COPY:
|
| case ElementType.PASTE:
|
| @@ -1376,7 +1467,9 @@ Controller.prototype.handlePointerEventForSoftKey_ = function(softKey, e) {
|
| EnSwitcherKey} */ (softKey);
|
| this.adapter_.toggleLanguageState(this.model_.stateManager.isEnMode);
|
| this.model_.stateManager.isEnMode = !this.model_.stateManager.isEnMode;
|
| - key.update();
|
| + if (!this.updateToggleLanguageKeyset_()) {
|
| + key.update();
|
| + }
|
| }
|
| break;
|
| case ElementType.SPACE_KEY:
|
| @@ -1398,6 +1491,10 @@ Controller.prototype.handlePointerEventForSoftKey_ = function(softKey, e) {
|
| this.switchToKeyset(key.toKeyset);
|
| this.returnToLetterKeysetOnSpace_ = false;
|
| }
|
| + var isHwt = Controller.HANDWRITING_VIEW_CODE_ == this.currentKeyset_;
|
| + if (isHwt) {
|
| + this.container_.cleanStroke();
|
| + }
|
| break;
|
|
|
| case ElementType.SWITCHER_KEY:
|
| @@ -1436,8 +1533,14 @@ Controller.prototype.handlePointerEventForSoftKey_ = function(softKey, e) {
|
| this.model_.stateManager.triggerChording();
|
| var ch = key.getActiveCharacter();
|
| if (ch.length == 1) {
|
| - this.adapter_.sendKeyDownAndUpEvent(key.getActiveCharacter(), '', 0,
|
| + if (this.currentKeyset_.indexOf('symbol') != -1) {
|
| + this.adapter_.sendKeyDownAndUpEvent(key.getActiveCharacter(),
|
| + KeyCodes.SYMBOL, 0, this.getSpatialData_(key, e.x, e.y));
|
| + }
|
| + else {
|
| + this.adapter_.sendKeyDownAndUpEvent(key.getActiveCharacter(), '', 0,
|
| this.getSpatialData_(key, e.x, e.y));
|
| + }
|
| } else if (ch.length > 1) {
|
| // Some compact keys contains more than 1 characters, such as '.com',
|
| // 'http://', etc. Those keys should trigger a direct commit text
|
| @@ -1475,10 +1578,7 @@ Controller.prototype.handlePointerEventForSoftKey_ = function(softKey, e) {
|
| var defaultFullKeyset = this.initialKeyset_.split(/\./)[0];
|
| var enableCompact = !this.adapter_.isA11yMode && goog.array.contains(
|
| util.KEYSETS_HAVE_COMPACT, defaultFullKeyset);
|
| - if (defaultFullKeyset == 'zhuyin' &&
|
| - !this.adapter_.features.isEnabled(FeatureName.EXPERIMENTAL) ||
|
| - this.languageCode_ == 'ko') {
|
| - // Hides 'switch to compact' for zhuyin when not in experimental env.
|
| + if (this.languageCode_ == 'ko') {
|
| enableCompact = false;
|
| }
|
| var hasHwt = !this.adapter_.isPasswordBox() &&
|
| @@ -1487,12 +1587,10 @@ Controller.prototype.handlePointerEventForSoftKey_ = function(softKey, e) {
|
| var hasEmoji = !this.adapter_.isPasswordBox();
|
| var enableSettings = this.shouldEnableSettings() &&
|
| !!window.inputview && !!inputview.openSettings;
|
| - var enableFVK = this.adapter_.isFloatingVirtualKeyboardEnabled();
|
| this.adapter_.getInputMethods(function(inputMethods) {
|
| this.container_.menuView.show(key, defaultFullKeyset, isCompact,
|
| enableCompact, this.currentInputMethod_, inputMethods, hasHwt,
|
| - enableSettings, hasEmoji, this.adapter_.isA11yMode, enableFVK,
|
| - this.adapter_.isFloating);
|
| + enableSettings, hasEmoji, this.adapter_.isA11yMode);
|
| }.bind(this));
|
| }
|
| break;
|
| @@ -1560,19 +1658,24 @@ Controller.prototype.stopBackspaceAutoRepeat_ = function() {
|
| * @private
|
| */
|
| Controller.prototype.backspaceTick_ = function() {
|
| - if (this.backspaceRepeated_ >= Controller.BACKSPACE_REPEAT_LIMIT_) {
|
| - this.stopBackspaceAutoRepeat_();
|
| - return;
|
| - }
|
| this.backspaceRepeated_++;
|
| this.backspaceDown_();
|
| this.soundController_.onKeyRepeat(ElementType.BACKSPACE_KEY);
|
|
|
| if (this.backspaceAutoRepeat_) {
|
| - this.backspaceAutoRepeat_.start(75);
|
| + var delay = MINIMUM_BACKSPACE_REPEAT_TIME_MS;
|
| + if (this.backspaceRepeated_ <= BACKSPACE_REPEAT_LIMIT) {
|
| + var ease = goog.fx.easing.easeOut(
|
| + this.backspaceRepeated_ / BACKSPACE_REPEAT_LIMIT);
|
| + var delta = MAXIMUM_BACKSPACE_REPEAT_TIME_MS -
|
| + MINIMUM_BACKSPACE_REPEAT_TIME_MS;
|
| + delay = MAXIMUM_BACKSPACE_REPEAT_TIME_MS - (delta * ease);
|
| + }
|
| + this.backspaceAutoRepeat_.start(delay);
|
| } else {
|
| this.backspaceAutoRepeat_ = new goog.async.Delay(
|
| - goog.bind(this.backspaceTick_, this), 300);
|
| + goog.bind(this.backspaceTick_, this),
|
| + BACKSPACE_REPEAT_START_TIME_MS);
|
| this.backspaceAutoRepeat_.start();
|
| }
|
| };
|
| @@ -1613,10 +1716,13 @@ Controller.prototype.resetAll = function() {
|
| this.container_.menuView.hide();
|
| this.container_.swipeView.reset();
|
| this.container_.altDataView.hide();
|
| - this.container_.gesturePreviewView.hide();
|
| + if (this.container_.gesturePreviewWindow) {
|
| + this.container_.gesturePreviewWindow.hide();
|
| + }
|
| if (this.container_.floatingView) {
|
| this.container_.floatingView.hide();
|
| }
|
| + this.stopBackspaceAutoRepeat_();
|
| };
|
|
|
|
|
| @@ -1655,10 +1761,10 @@ Controller.prototype.onSurroundingTextChanged_ = function(e) {
|
| if (!this.model_.settings.autoCapital || !e.text) {
|
| return;
|
| }
|
| -
|
| + var textBeforeCursor = e.textBeforeCursor.replace(/\u00a0/g, ' ');
|
| var isShiftEnabled = this.model_.stateManager.hasState(StateType.SHIFT);
|
| var needAutoCap = this.model_.settings.autoCapital &&
|
| - util.needAutoCap(e.text);
|
| + util.needAutoCap(textBeforeCursor);
|
| if (needAutoCap && !isShiftEnabled) {
|
| this.changeState_(StateType.SHIFT, true, false);
|
| this.shiftForAutoCapital_ = true;
|
| @@ -1676,6 +1782,7 @@ Controller.prototype.onSurroundingTextChanged_ = function(e) {
|
| Controller.prototype.onContextBlur_ = function() {
|
| this.container_.cleanStroke();
|
| this.container_.menuView.hide();
|
| + this.stopBackspaceAutoRepeat_();
|
| };
|
|
|
|
|
| @@ -1696,7 +1803,7 @@ Controller.prototype.backspaceDown_ = function() {
|
| this.statistics_.recordEnum('InputMethod.VirtualKeyboard.BackspaceOnLayout',
|
| this.statistics_.getLayoutType(this.currentKeyset_,
|
| this.adapter_.isA11yMode),
|
| - i18n.input.chrome.Statistics.LayoutTypes.MAX);
|
| + Statistics.LayoutTypes.MAX);
|
| };
|
|
|
|
|
| @@ -1774,32 +1881,63 @@ Controller.prototype.onCandidatesBack_ = function(e) {
|
|
|
|
|
| /**
|
| + * Converts a word to shifted or all-caps based on the current shift state.
|
| + *
|
| + * @param {string} word The word to potentially convert.
|
| + * @return {string} The converted word.
|
| + * @private
|
| + */
|
| +Controller.prototype.convertToShifted_ = function(word) {
|
| + if (this.model_.stateManager.getState() == StateType.SHIFT) {
|
| + if (this.model_.stateManager.isSticky(StateType.SHIFT) &&
|
| + this.model_.stateManager.isFinalSticky(StateType.SHIFT)) {
|
| + word = word.toUpperCase();
|
| + } else {
|
| + word = word.charAt(0).toUpperCase() + word.slice(1);
|
| + }
|
| + }
|
| + return word;
|
| +};
|
| +
|
| +
|
| +/**
|
| * Callback for gestures results event.
|
| *
|
| * @param {!i18n.input.chrome.DataSource.GesturesBackEvent} e .
|
| * @private
|
| */
|
| Controller.prototype.onGesturesBack_ = function(e) {
|
| - if (!this.commitNextGestureResult_ &&
|
| - goog.array.equals(e.results, this.gestureResultsCache_)) {
|
| + var response = e.response;
|
| + this.stopBackspaceAutoRepeat_();
|
| + if (!response.commit &&
|
| + goog.array.equals(response.results, this.gestureResultsCache_)) {
|
| // If gesture results have not updated, do not transmit to the UI.
|
| return;
|
| } else {
|
| - this.gestureResultsCache_ = e.results;
|
| + this.gestureResultsCache_ = response.results;
|
| }
|
| - var bestResult = e.results[0];
|
| - if (this.container_.gesturePreviewView) {
|
| - this.container_.gesturePreviewView.show(bestResult);
|
| + var bestResult = this.convertToShifted_(response.results[0]);
|
| + if (this.container_.gesturePreviewWindow &&
|
| + this.container_.gestureCanvasView.isGesturing) {
|
| + this.container_.gesturePreviewWindow.show(bestResult);
|
| }
|
| - // TODO: Resolve a race where multiple decoder results return after this flag
|
| - // is set to true.
|
| - if (this.commitNextGestureResult_) {
|
| + if (response.commit) {
|
| // Commit the best result.
|
| - this.adapter_.commitGestureResult(bestResult);
|
| - this.commitNextGestureResult_ = false;
|
| + this.adapter_.commitGestureResult(
|
| + bestResult, this.adapter_.isGoogleDocument());
|
| this.gestureResultsCache_ = [];
|
| + this.statistics_.recordEnum(
|
| + Statistics.GESTURE_TYPING_METRIC_NAME,
|
| + Statistics.GestureTypingEvent.TYPED,
|
| + Statistics.GestureTypingEvent.MAX);
|
| + if (this.container_.gesturePreviewWindow) {
|
| + new goog.async.Delay(
|
| + goog.bind(this.container_.gesturePreviewWindow.hide,
|
| + this.container_.gesturePreviewWindow),
|
| + GESTURE_PREVIEW_LINGER_TIME_MS).start();
|
| + }
|
| }
|
| - this.showGestureCandidates_(e.results.slice(1));
|
| + this.showGestureCandidates_(response.results.slice(1));
|
| };
|
|
|
|
|
| @@ -1814,14 +1952,16 @@ Controller.prototype.showGestureCandidates_ = function(results) {
|
| var candidates = [];
|
| for (var i = 0; i < results.length; ++i) {
|
| var candidate = {};
|
| - candidate[Name.CANDIDATE] = results[i];
|
| + var result = this.convertToShifted_(results[i]);
|
| + candidate[Name.CANDIDATE] = result;
|
| candidate[Name.CANDIDATE_ID] = i;
|
| candidate[Name.IS_EMOJI] = false;
|
| candidate[Name.MATCHED_LENGTHS] = 0;
|
| candidates.push(candidate);
|
| }
|
| // The source is empty as this is a gesture and not a series of key presses.
|
| - this.showCandidates_('', candidates, Controller.CandidatesOperation.NONE);
|
| + this.showCandidates_(
|
| + '', candidates, Controller.CandidatesOperation.NONE, true);
|
| };
|
|
|
|
|
| @@ -1831,10 +1971,12 @@ Controller.prototype.showGestureCandidates_ = function(results) {
|
| * @param {string} source The source text.
|
| * @param {!Array.<!Object>} candidates The candidate text list.
|
| * @param {Controller.CandidatesOperation} operation .
|
| + * @param {boolean=} opt_fromGestures Whether or not the candidates are being
|
| + * set by gesture typing.
|
| * @private
|
| */
|
| Controller.prototype.showCandidates_ = function(source, candidates,
|
| - operation) {
|
| + operation, opt_fromGestures) {
|
| var state = !!source ? ExpandedCandidateView.State.COMPLETION_CORRECTION :
|
| ExpandedCandidateView.State.PREDICTION;
|
| var expandView = this.container_.expandedCandidateView;
|
| @@ -1883,6 +2025,7 @@ Controller.prototype.showCandidates_ = function(source, candidates,
|
| SHRINK_CANDIDATES, false);
|
| this.container_.currentKeysetView.setVisible(true);
|
| }
|
| + this.candidatesSetByGestureTyping_ = !!opt_fromGestures;
|
| };
|
|
|
|
|
| @@ -1991,11 +2134,17 @@ Controller.prototype.maybeCreateViews_ = function() {
|
| // active keyset.
|
| var keyLen = Object.keys(this.keysetDataMap_).length;
|
| if (created && keyLen > 1 || !created && keyLen > 0) {
|
| - goog.Timer.callOnce((function() {
|
| + if (Controller.DISABLE_DELAY_LOADING_FOR_TEST) {
|
| for (var keyset in this.keysetDataMap_) {
|
| this.createView_(keyset);
|
| }
|
| - }).bind(this));
|
| + } else {
|
| + goog.Timer.callOnce((function() {
|
| + for (var keyset in this.keysetDataMap_) {
|
| + this.createView_(keyset);
|
| + }
|
| + }).bind(this));
|
| + }
|
| }
|
| };
|
|
|
| @@ -2016,14 +2165,17 @@ Controller.prototype.switchToKeyset = function(keyset) {
|
| keyset, this.contextTypeToLastKeysetMap_[contextType] ||
|
| this.getActiveKeyset_(), this.languageCode_);
|
|
|
| + // If it is the sub keyset switching, emoji, or in hotrod mode, don't record
|
| + // the keyset.
|
| + if (!this.isSubKeyset_(this.currentKeyset_, keyset) &&
|
| + keyset != Controller.EMOJI_VIEW_CODE_ &&
|
| + !this.adapter_.isHotrod) {
|
| + // Update the keyset of current context type.
|
| + this.contextTypeToKeysetMap_[this.currentInputMethod_][contextType] =
|
| + keyset;
|
| + }
|
| +
|
| if (ret) {
|
| - if (!this.isSubKeyset_(this.currentKeyset_, keyset) &&
|
| - keyset != Controller.EMOJI_VIEW_CODE_) {
|
| - // If it is the sub keyset switching, or emoji, don't record it.
|
| - // Update the keyset of current context type.
|
| - this.contextTypeToKeysetMap_[this.currentInputMethod_][contextType] =
|
| - keyset;
|
| - }
|
| this.updateLanguageState_(this.currentKeyset_, keyset);
|
| this.currentKeyset_ = keyset;
|
| this.resize(Controller.DEV);
|
| @@ -2033,20 +2185,19 @@ Controller.prototype.switchToKeyset = function(keyset) {
|
| } else {
|
| // Sets the current keyset for delay switching.
|
| this.currentKeyset_ = keyset;
|
| - if (keyset != Controller.EMOJI_VIEW_CODE_) { // Emoji is temp keyset.
|
| - this.contextTypeToKeysetMap_[this.currentInputMethod_][contextType] =
|
| - keyset;
|
| - }
|
| this.loadResource_(keyset);
|
| }
|
|
|
| // TODO: The 'us' part of this code is a workaround an issue where other xkb
|
| // languages seem to be sharing options between each other.
|
| this.isKeysetUSCompact_ =
|
| - this.currentKeyset_.indexOf(Controller.US_COMPACT_PREFIX_) >= 0;
|
| + this.currentKeyset_.indexOf(Controller.US_COMPACT_QWERTY_CODE_) >= 0;
|
| // If we're switching to a new keyset, we don't want spacebar to trigger
|
| // another keyset switch.
|
| this.returnToLetterKeysetOnSpace_ = false;
|
| + if (this.gestureTypingEnabled_()) {
|
| + this.container_.gestureCanvasView.clear();
|
| + }
|
| };
|
|
|
|
|
| @@ -2130,13 +2281,16 @@ Controller.prototype.resize = function(opt_preventResizeTo) {
|
| }
|
| candidateViewHeight = SizeSpec.NON_A11Y_CANDIDATE_VIEW_HEIGHT;
|
| }
|
| - width = this.adapter_.isFloating ?
|
| + var isFloatingMode = this.adapter_.isFloatingVirtualKeyboardEnabled();
|
| + width = isFloatingMode ?
|
| Math.floor(screen.width * widthPercent) : screen.width;
|
| - widthPercent = this.adapter_.isFloating ? 1.0 : widthPercent;
|
| - if (goog.dom.classlist.contains(this.container_.getElement(), Css.SMALL)) {
|
| - height = SizeSpec.SMALL_SIZE_HEIGHT;
|
| - width = SizeSpec.SMALL_SIZE_WIDTH;
|
| - candidateViewHeight = SizeSpec.SMALL_SIZE_CANDIDATE_VIEW_HEIGHT;
|
| + widthPercent = isFloatingMode ? 1.0 : widthPercent;
|
| +
|
| + // Floating virtual keyboard needs to be placed in the bottom of screen and
|
| + // centered when initially shows up. innerHeight == 0 is used as heuristic to
|
| + // check if keyboard is showing up for the first time.
|
| + if (isFloatingMode && window.innerHeight == 0) {
|
| + window.moveTo((screen.width - width) / 2, screen.height - height);
|
| }
|
|
|
| if ((window.innerHeight != height || window.innerWidth != width) &&
|
| @@ -2399,6 +2553,7 @@ Controller.prototype.onUpdateToggleLanguageState_ = function(e) {
|
| // e.msg value means whether is Chinese mode now.
|
| if (this.model_.stateManager.isEnMode == e.msg) {
|
| this.model_.stateManager.isEnMode = !e.msg;
|
| + this.updateToggleLanguageKeyset_();
|
| this.container_.currentKeysetView.update();
|
| }
|
| } else {
|
| @@ -2419,4 +2574,31 @@ Controller.prototype.onUpdateToggleLanguageState_ = function(e) {
|
| }
|
| }
|
| };
|
| +
|
| +
|
| +/**
|
| + * Update keyset when language state changes.
|
| + *
|
| + * @return {boolean}
|
| + * @private
|
| + */
|
| +Controller.prototype.updateToggleLanguageKeyset_ = function() {
|
| + var pos = this.currentKeyset_.indexOf('.us');
|
| + var toKeyset;
|
| + if (pos > 0) {
|
| + toKeyset = this.currentKeyset_.replace('.us', '');
|
| + if (goog.array.contains(util.KEYSETS_SWITCH_WITH_US, toKeyset)) {
|
| + this.switchToKeyset(toKeyset);
|
| + return true;
|
| + }
|
| + }
|
| + else if (goog.array.contains(util.KEYSETS_SWITCH_WITH_US,
|
| + this.currentKeyset_)) {
|
| + toKeyset = this.currentKeyset_ + '.us';
|
| + this.switchToKeyset(toKeyset);
|
| + return true;
|
| + }
|
| + return false;
|
| +};
|
| +
|
| }); // goog.scope
|
|
|