Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Autocorrect #9052

Merged
merged 1 commit into from

2 participants

@davidflanagan

Still a work in progress. Needs tweaking before merging. Still needs a settings UI, too.

@gregorwagner gregorwagner commented on the diff
apps/keyboard/js/imes/latin/latin.js
((171 lines not shown))
+ inputText.substring(cursor);
+ cursor++;
+
+ // Remember this change so we can revert it on backspace
+ revertTo = ' ';
+ revertFrom = newtext;
+ justAutoCorrected = false;
+ }
+ }
+
+
+ // When the worker thread sends us a batch of suggestions, deal
+ // with them here.
+ function handleSuggestions(input, suggestions) {
+ if (suggestions.length === 0) { // If no suggestions
+ keyboard.sendCandidates(suggestions); // Clear any displayed suggestions
@gregorwagner Owner

Why do you add the suggestions here?

@davidflanagan Owner

Suggestions is an empty array here, so I'm just using it to clear any previously displayed suggestions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
apps/keyboard/js/imes/latin/latin.js
((126 lines not shown))
+
+ // Remember the change we just made so we can revert it if the
+ // user types backspace
+ revertTo = currentWord;
+ revertFrom = newWord;
+ justAutoCorrected = true;
+ }
+
+ // Auto punctuate, converting space punctuation to punctuation space
+ // or converting space space to period space if the two spaces were
+ // close enough together. Assumes that pre-conditions for auto punctuation
+ // have been met.
+ function autoPunctuate(keycode) {
+ switch (keycode) {
+ case SPACE:
+ if (Date.now() - lastKeyWasSpace < DOUBLE_SPACE_TIME)
@gregorwagner Owner

lastKeyWasSpace sounds more like a bool to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@davidflanagan

I've pushed a new version of the patch that fixes the bug where an old auto correction (jrego -> regolith) could still happen even after the suggestions disappeared.

I've also updated the tests so that (hopefully) the Travis build will not fail anymore. (I had changed an internal API that the tests used and hadn't updated them accordingly).

@davidflanagan

Updated the patch again to change the lastKeyWasSpace variable to lastSpaceTimestamp

@davidflanagan

I don't know what caused the travis failure: none of the tests ran for some reason. But there is no lint.

@davidflanagan davidflanagan merged commit 132c5a7 into mozilla-b2g:master
@davidflanagan davidflanagan referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@davidflanagan davidflanagan referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@davidflanagan davidflanagan referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@davidflanagan davidflanagan referenced this pull request from a commit in davidflanagan/gaia
@davidflanagan davidflanagan Bug 873934: uplift auto-correct patches from master to v1-train
Revert "Merge pull request #9971 from es92/bug-851565-keyboard-suggestion-capitalization-fix"

This reverts commit 37d7a21, reversing
changes made to eea3449.

Revert "Merge pull request #9183 from evelynhung/issue-861108-v1.0.1"

This reverts commit 21ff040.

Merge pull request #9052 from davidflanagan/autocorrect

Bug 860462 - enable keyboard auto-correction r=gwagner(cherry picked from commit 132c5a7)

Conflicts:

	apps/keyboard/style/keyboard.css

Merge pull request #9124 from ckerschb/docu2

Bug 858158 (final) - [keyboard] document prediction algorithm and make it tuneable(cherry picked from commit d83b558)

Merge pull request #9421 from davidflanagan/bug797171

Bug 797171: revert user-selected suggested words on backspace r=anygregor(cherry picked from commit 23ed330)

Merge pull request #9422 from davidflanagan/bug861113

Bug 861113: correctly define uppercase for non Latin-1 letters(cherry picked from commit 58665c2)

Merge pull request #9153 from davidflanagan/bug860624

Bug 865484 - refactor dictionary data structure and search algorithm for keyboard auto-correct r=anygregor r=ckerschb
(cherry picked from commit 413482d)

Merge pull request #9610 from davidflanagan/autocorrect-visuals

Bug 868819: modify auto-correct UX and visuals(cherry picked from commit 9fa85e6)

Conflicts:

	apps/keyboard/style/keyboard.css

Merge pull request #10038 from comoyo/keyboard_no_autocorrect

Bug 876658 - Dont perform autocorrect if old & new word are the same. r=rudyl(cherry picked from commit bebcb40)

Merge pull request #10155 from davidflanagan/bug876891

Bugs 878387, 878168, 876891: fix three closely related auto-correct bugs. r=janjongboom(cherry picked from commit 6ca1a9b)

Merge pull request #10154 from davidflanagan/bug873223

Bug 873223: make long suggestions fit, increase font size, fix justification r=RudyLu(cherry picked from commit 417e5e2)

Conflicts:

	apps/keyboard/style/keyboard.css

Merge pull request #10171 from davidflanagan/bug878384

Bug 878384: don't autocorrect single-letters r=es92(cherry picked from commit 7611662)

Merge pull request #10172 from davidflanagan/bug878838

Bug 878838: don't suggest the same word twice r=es92(cherry picked from commit 0689050)

Merge pull request #10173 from davidflanagan/nondeterministic-autocorrect

Bug 879076: handle case of nearby keys correctly r=es92(cherry picked from commit 60d03c4)

Merge pull request #10175 from davidflanagan/bug878843

Bug 878843 - Integrate with replaceSurroundingText for autocorrect (with... r=fabrice,djf(cherry picked from commit bc48562)

tweak css for suggestions display because of keyboard layout differences between master and v1-train

Merge pull request #10228 from es92/Bug879187

Bug879187: Autocorrect suggestions disappear when keyboard redrawn r=davidflanagan(cherry picked from commit 159b0dd)

Merge pull request #10227 from davidflanagan/bug879533

Bug 879533: don't display user's input if we don't have any suggestions r=es92(cherry picked from commit eed0873)

Merge pull request #10230 from davidflanagan/bug878386

Bug 878386: if initial search for corrections fails, search harder r=es92(cherry picked from commit 0225f1a)
ee64a66
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 11, 2013
  1. @davidflanagan
This page is out of date. Refresh to see the latest.
View
2  apps/keyboard/js/imes/jskanji/jskanji.js
@@ -369,7 +369,7 @@
}
};
- this.activate = function ime_activate(language, suggestions, state) {
+ this.activate = function ime_activate(language, state, options) {
var inputType = state.type;
debug('Activate. Input type: ' + inputType);
var layout = IMELayouts.JP;
View
6 apps/keyboard/js/imes/jspinyin/jspinyin.js
@@ -291,7 +291,7 @@ IMEngineBase.prototype = {
/**
* Notifies when the IM is shown
*/
- activate: function engineBase_activate(language, suggestions, state) {
+ activate: function engineBase_activate(language, state, options) {
}
};
@@ -700,9 +700,9 @@ IMEngine.prototype = {
/**
* Override
*/
- activate: function engine_activate(language, suggestions, state) {
+ activate: function engine_activate(language, state, options) {
var inputType = state.type;
- IMEngineBase.prototype.activate.call(this, language, suggestions, state);
+ IMEngineBase.prototype.activate.call(this, language, state, options);
debug('Activate. Input type: ' + inputType);
PinyinDecoderService.flushCache(null);
var keyboard = this._inputTraditionalChinese ?
View
514 apps/keyboard/js/imes/latin/latin.js
@@ -4,13 +4,15 @@
'use strict';
/*
- * This latin input method provides three forms of input assistance:
+ * This latin input method provides four forms of input assistance:
*
* 1) word suggestions
*
- * 2) auto capitalization
+ * 2) auto correction
*
- * 3) punctuation assistance by converting space space to period space
+ * 3) auto capitalization
+ *
+ * 4) punctuation assistance by converting space space to period space
* and by transposing space followed by punctuation.
*
* These input modifications are controlled by the type and inputmode
@@ -44,14 +46,20 @@
var inputMode; // The inputmode we're using: see getInputMode()
var capitalizing; // Are we auto-capitalizing for this activation?
var suggesting; // Are we offering suggestions for this activation?
+ var correcting; // Are we auto-correcting user input?
var punctuating; // Are we offering punctuation assistance?
var inputText; // The input text
var cursor; // The insertion position
var selection; // The end of the selection, if there is one, or 0
- var lastKeyWasSpace; // Was the last key a space?
+ var lastSpaceTimestamp; // If the last key was a space, this is the timestamp
var layoutParams; // Parameters passed to setLayoutParams
var idleTimer; // Used by deactivate
var suggestionsTimer; // Used by updateSuggestions;
+ var autoCorrection; // Correction to make if next input is space
+ var revertTo; // Revert to this on backspace after autocorrect
+ var revertFrom; // Revert away from this on backspace
+ var justAutoCorrected; // Was last change an auto correction?
+ var correctionDisabled; // Temporarily diabled after reverting?
// Terminate the worker when the keyboard is inactive for this long.
const workerTimeout = 30000; // 30 seconds of idle time
@@ -69,13 +77,23 @@
const QUESTION = 63;
const EXCLAMATION = 33;
const COMMA = 44;
+ const COLON = 58;
+ const SEMICOLON = 59;
const WS = /^\s+$/; // all whitespace characters
const UC = /^[A-ZÀ-ÖØ-Þ]+$/; // all uppercase latin characters
- const LETTER = /^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/; // all latin letters
const DOUBLE_SPACE_TIME = 700; // ms between spaces to convert to ". "
+ // Don't offer to autocorrect unless we're reasonably certain that the
+ // user wants this correction. The first suggested word must be at least
+ // this much more highly weighted than the second suggested word.
+ // XXX: this seems too low, but we get a root word and the root with suffix
+ // that have similar weights, and should probably auto correct on one.
+ // Maybe the prediction engine should weight on the length of the word so
+ // that we can raise this to 1.25 or something.
+ const AUTO_CORRECT_THRESHOLD = 1.05;
+
// keyboard.js calls this to pass us the interface object we need
// to communicate with it
function init(interfaceObject) {
@@ -115,7 +133,7 @@
// This gets called whenever the keyboard pops up to tell us everything
// we need to provide useful typing assistance.
- function activate(lang, suggestionsEnabled, state) {
+ function activate(lang, state, options) {
language = lang;
inputMode = getInputMode(state.type, state.inputmode);
inputText = state.value;
@@ -128,14 +146,15 @@
// Figure out what kind of input assistance we're providing for this
// activation.
capitalizing = punctuating = (inputMode === 'latin-prose');
- suggesting = (suggestionsEnabled && inputMode !== 'verbatim');
+ suggesting = (options.suggest && inputMode !== 'verbatim');
+ correcting = (options.correct && inputMode !== 'verbatim');
// If we are going to offer suggestions, set up the worker thread.
- if (suggesting)
+ if (suggesting || correcting)
setupSuggestionsWorker();
// Reset the double space flag
- lastKeyWasSpace = 0;
+ lastSpaceTimestamp = 0;
// Start off with the correct capitalization and suggestions
updateCapitalization();
@@ -172,13 +191,13 @@
worker.onmessage = function(e) {
switch (e.data.cmd) {
case 'log':
- console.log.apply(console, e.data.args);
+ console.log.apply(console, e.data.message);
break;
case 'unknownLanguage':
- console.error('No dictionary for language', e.data.args[0]);
+ console.error('No dictionary for language', e.data.language);
break;
case 'predictions':
- keyboard.sendCandidates(e.data.args);
+ handleSuggestions(e.data.input, e.data.suggestions);
break;
}
};
@@ -189,17 +208,98 @@
worker.postMessage({ cmd: 'setLanguage', args: [language]});
}
+ /*
+ * The keyboard calls this method to tell us about user input.
+ *
+ * What we do with the input depends on various things:
+ *
+ * - whether we are suggesting, correcting, punctuating and/or capitalizing:
+ * these are controlled by settings, input mode and input type
+ *
+ * - whether there is a selected region in the input field
+ *
+ * - whether there is an auto-correction ready (when input is space
+ * or punctuation).
+ *
+ * - whether the last action was an autocorrection (when input is backspace)
+ *
+ * - the cursor position (affects suggestions, capitalization, etc.)
+ *
+ * If there is a selection just handle simple insertions and deletions
+ * with no extra behavior. (I think)
+ *
+ * If input is a space or punctuation:
+ *
+ * If there is a autocorrection ready, and we are correcting and
+ * the cursor is at the end of a word, make the correction
+ *
+ * If the previous character is a space, fix the punctuation. Note that
+ * this only works for a subset of the punctuation characters.
+ *
+ * Otherwise just insert it.
+ *
+ * If we're correcting and corrections are temporarily diabled, turn them
+ * back on.
+ *
+ * If input is a backspace:
+ *
+ * If we just did an auto-correction, revert it and turn off corrections
+ * until the next space or punctuation character.
+ *
+ * If we just inserted a suggested word that the user selected, revert
+ * the insertion, but don't disable autocorrect.
+ *
+ * Should we undo punctuation corrections this way, too?
+ *
+ * Otherwise, just delete the character before the cursor
+ *
+ * For any other input character, just insert it.
+ *
+ * Reset the backspace reversion state
+ *
+ * Update the capitalization state, if we're capitalizing
+ */
function click(keycode, repeat) {
- if (punctuating && handlePunctuation(keycode)) {
- // nothing to do here: handlePunctuation did it for us
+ // If the key is anything other than a backspace, forget about any
+ // previous changes that we would otherwise revert.
+ if (keycode !== BACKSPACE) {
+ revertTo = revertFrom = '';
+ justAutoCorrected = false;
+ }
+
+ if (selection) {
+ // If there is selected text, don't do anything fancy here.
+ handleKey(keycode);
}
else {
- // Update our internal model of the input text and cursor position
- updateState(keycode);
- // Generate the key event
- keyboard.sendKey(keycode);
+ switch (keycode) {
+ case SPACE:
+ case RETURN:
+ case PERIOD:
+ case QUESTION:
+ case EXCLAMATION:
+ case COMMA:
+ case COLON:
+ case SEMICOLON:
+ // These keys may trigger word or punctuation corrections
+ handleCorrections(keycode);
+ correctionDisabled = false;
+ break;
+
+ case BACKSPACE:
+ handleBackspace();
+ break;
+
+ default:
+ handleKey(keycode);
+ }
}
+ // If there was a potential auto correction, we either used it in
+ // handleCorrections() above or it is now out of date, so clear it
+ // so it doesn't get used later
+ autoCorrection = null;
+
// And update the keyboard capitalization state, if necessary
updateCapitalization();
@@ -210,23 +310,251 @@
if (keycode === SPACE || keycode === RETURN) {
keyboard.setLayoutPage(LAYOUT_PAGE_DEFAULT);
}
+
+ lastSpaceTimestamp = (keycode === SPACE) ? Date.now() : 0;
}
- // If the user selections one of the suggestions offered by this input method
+ // Handle any key (including backspace) and do the right thing even if
+ // there is a selection in the text field. This method does not perform
+ // auto-correction or auto-punctuation.
+ function handleKey(keycode) {
+ // First, update our internal state
+ if (keycode === BACKSPACE) {
+ if (selection) {
+ // backspace while a region is selected erases the selection
+ // and leaves the cursor at the selection start
+ inputText = inputText.substring(0, cursor) +
+ inputText.substring(selection);
+ selection = 0;
+ } else if (cursor > 0) {
+ cursor--;
+ inputText = inputText.substring(0, cursor) +
+ inputText.substring(cursor + 1);
+ }
+ } else {
+ if (selection) {
+ inputText =
+ inputText.substring(0, cursor) +
+ String.fromCharCode(keycode) +
+ inputText.substring(selection);
+ selection = 0;
+ } else {
+ inputText =
+ inputText.substring(0, cursor) +
+ String.fromCharCode(keycode) +
+ inputText.substring(cursor);
+ }
+ cursor++;
+ }
+
+ // Generate the key event
+ keyboard.sendKey(keycode);
+ }
+
+ // If we just did auto correction or auto punctuation, then backspace
+ // should undo it. Otherwise it is just an ordinary backspace.
+ function handleBackspace() {
+ // If we made a correction and haven't changed it at all yet,
+ // then revert it.
+ var len = revertFrom ? revertFrom.length : 0;
+ if (len && cursor > len &&
+ inputText.substring(cursor - len, cursor) === revertFrom) {
+
+ // Revert the content of the text field
+ for (var i = 0; i < len; i++)
+ keyboard.sendKey(BACKSPACE);
+ keyboard.sendString(revertTo);
+
+ // Revert our internal state
+ inputText =
+ inputText.substring(0, cursor - len) +
+ revertTo +
+ inputText.substring(cursor);
+ cursor -= len - revertTo.length;
+
+ // If the change we just reverted was an auto-correction then
+ // temporarily disable auto correction until the next space
+ if (justAutoCorrected) {
+ correctionDisabled = true;
+ }
+
+ revertFrom = revertTo = '';
+ justAutoCorrected = false;
+ }
+ else {
+ handleKey(BACKSPACE);
+ }
+ }
+
+ // This function is called when the user types space, return or a punctuation
+ // character. It performs auto correction or auto punctuation or just
+ // inserts the character.
+ function handleCorrections(keycode) {
+ if (correcting && autoCorrection && !correctionDisabled && atWordEnd()) {
+ autoCorrect(keycode);
+ }
+ else if (punctuating && cursor >= 2 &&
+ isWhiteSpace(inputText[cursor - 1]) &&
+ !isWhiteSpace(inputText[cursor - 2]))
+ {
+ autoPunctuate(keycode);
+ }
+ else {
+ handleKey(keycode);
+ }
+ }
+
+ // Perform an autocorrection. Assumes that all pre-conditions for
+ // auto-correction have been met.
+ function autoCorrect(keycode) {
+ // Get the word before the cursor
+ var currentWord = wordBeforeCursor();
+ var currentWordLength = currentWord.length;
+
+ // Figure out the auto correction text
+ var newWord = autoCorrection; // Atart with suggested word
+ newWord += String.fromCharCode(keycode); // and add the user's input.
+ if (keycode !== SPACE && keycode !== RETURN) // If not whitespace
+ newWord += ' '; // add a space.
+
+ // Backspace over the current word in the text field
+ for (var i = 0; i < currentWordLength; i++)
+ keyboard.sendKey(BACKSPACE);
+
+ // And send the correction to the textfield
+ keyboard.sendString(newWord);
+
+ // Now update our internal state to match.
+ inputText =
+ inputText.substring(0, cursor - currentWordLength) +
+ newWord +
+ inputText.substring(cursor);
+
+ // Update the cursor position, too.
+ cursor = cursor - currentWordLength + newWord.length;
+
+ // Remember the change we just made so we can revert it if the
+ // user types backspace
+ revertTo = currentWord;
+ revertFrom = newWord;
+ justAutoCorrected = true;
+ }
+
+ // Auto punctuate, converting space punctuation to punctuation space
+ // or converting space space to period space if the two spaces were
+ // close enough together. Assumes that pre-conditions for auto punctuation
+ // have been met.
+ function autoPunctuate(keycode) {
+ switch (keycode) {
+ case SPACE:
+ if (Date.now() - lastSpaceTimestamp < DOUBLE_SPACE_TIME)
+ fixPunctuation(PERIOD);
+ else
+ handleKey(keycode);
+ break;
+
+ case PERIOD:
+ case QUESTION:
+ case EXCLAMATION:
+ case COMMA:
+ fixPunctuation(keycode);
+ break;
+
+ default:
+ // colon and semicolon don't auto-punctuate because they're
+ // used after spaces for smileys.
+ handleKey(keycode);
+ break;
+ }
+
+ // In both the space space and the space period case we call this function
+ function fixPunctuation(keycode) {
+ keyboard.sendKey(BACKSPACE);
+ keyboard.sendKey(keycode);
+ keyboard.sendKey(SPACE);
+
+ var newtext = String.fromCharCode(keycode) + ' ';
+
+ inputText = inputText.substring(0, cursor - 1) +
+ newtext +
+ inputText.substring(cursor);
+ cursor++;
+
+ // Remember this change so we can revert it on backspace
+ revertTo = ' ';
+ revertFrom = newtext;
+ justAutoCorrected = false;
+ }
+ }
+
+
+ // When the worker thread sends us a batch of suggestions, deal
+ // with them here.
+ function handleSuggestions(input, suggestions) {
+ if (suggestions.length === 0) { // If no suggestions
+ keyboard.sendCandidates(suggestions); // Clear any displayed suggestions
@gregorwagner Owner

Why do you add the suggestions here?

@davidflanagan Owner

Suggestions is an empty array here, so I'm just using it to clear any previously displayed suggestions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ return; // We're done
+ }
+
+ // Check that the word before the cursor has not changed since
+ // we requested these suggestions. If the user has typed faster
+ // than we could offer suggestions, ignore these.
+ if (wordBeforeCursor() !== input) {
+ keyboard.sendCandidates([]); // Clear any displayed suggestions
+ return;
+ }
+
+ // Figure out if the first suggestion is good enough to offer as
+ // an autocorrection. We define "good enough" as significantly better
+ // than the second best suggestion. And significance is defined by
+ // a tuneable constant.
+ var significant =
+ suggestions.length === 1 ||
+ suggestions[0][1] / suggestions[1][1] > AUTO_CORRECT_THRESHOLD;
+
+ // Loop through the suggestions discarding the weights, and checking
+ // to see if the user's current input is one of the words. We don't
+ // want to autocorrect a valid word. Also, if the input begins with
+ // a capital letter, capitalize the suggestions
+ var lcinput = input.toLowerCase();
+ var inputStartsWithCapital = isUpperCase(input[0]);
+ var inputIsWord = false;
+ for (var i = 0; i < suggestions.length; i++) {
+ suggestions[i] = suggestions[i][0];
+ if (lcinput === suggestions[i].toLowerCase())
+ inputIsWord = true;
+ if (inputStartsWithCapital)
+ suggestions[i] =
+ suggestions[i][0].toUpperCase() + suggestions[i].substring(1);
+ }
+
+ // If we're going to use the first suggestion as an auto-correction
+ // then we have to tell the renderer to highlight it and we have to
+ // ensure that the raw input is also listed as a suggestion. If the
+ // input is the same as the first suggestion, don't auto-correct it.
+ if (correcting && !correctionDisabled && significant && !inputIsWord) {
+ // Remember the word to use if the next character is a space.
+ autoCorrection = suggestions[0];
+ // Make sure the user also has their actual input as a choice
+ // XXX: should this be highlighted in some special way?
+ // XXX: or should we just have a x icon to dismiss the autocorrection?
+ suggestions.push(input);
+ // Mark the auto-correction so the renderer can highlight it
+ suggestions[0] = '*' + suggestions[0];
+ }
+
+ keyboard.sendCandidates(suggestions);
+ }
+
+ // If the user selects one of the suggestions offered by this input method
// the keyboard calls this method to tell us it has been selected.
// We have to backspace over the current word, insert this new word, and
// update our internal state to match.
function select(word) {
- // Find the position of the first letter of the current word
- for (var firstletter = cursor - 1; firstletter >= 0; firstletter--) {
- if (!LETTER.test(inputText[firstletter])) {
- break;
- }
- }
- firstletter++;
+ var oldWord = wordBeforeCursor();
// Send backspaces
- for (var i = 0, n = cursor - firstletter; i < n; i++)
+ for (var i = 0, n = oldWord.length; i < n; i++)
keyboard.sendKey(BACKSPACE);
// Send the word
@@ -237,12 +565,12 @@
// Update internal state
inputText =
- inputText.substring(0, firstletter) +
+ inputText.substring(0, cursor - oldWord.length) +
word +
' ' +
inputText.substring(cursor);
- cursor = firstletter + word.length + 1;
+ cursor += word.length - oldWord.length + 1;
// Clear the suggestions
keyboard.sendCandidates([]);
@@ -260,7 +588,7 @@
function updateSuggestions(repeat) {
// If the user hasn't enabled suggestions, or if they're not appropriate
// for this input type, or are turned off by the input mode, do nothing
- if (!suggesting)
+ if (!suggesting && ! correcting)
return;
// If we deferred suggestions because of a key repeat, clear that timer
@@ -277,113 +605,12 @@
// If we're not at the end of a word, we want to clear any suggestions
// that might already be there
if (!atWordEnd()) {
- keyboard.sendCandidates([]);
+ if (suggesting)
+ keyboard.sendCandidates([]);
return;
}
- // Otherwise, find the word we're at the end of and ask for completions
- for (var firstletter = cursor - 1; firstletter >= 0; firstletter--) {
- if (!LETTER.test(inputText[firstletter])) {
- break;
- }
- }
- firstletter++;
-
- // firstletter is now the position of the start of the word and cursor is
- // the end of the word
- var word = inputText.substring(firstletter, cursor);
-
- worker.postMessage({cmd: 'predict', args: [word]});
- }
-
- // This function handles two special punctuation cases. If the user
- // types two spaces sufficiently close together we convert them to
- // period space. And if the user types nonspace space punctuation,
- // we transpose the space and the punctuation. (This supports adding
- // a punctuation mark after a word suggestion since suggestions
- // automatically insert a space.) This method returns true if it
- // handles the keycode and returns false otherwise.
- function handlePunctuation(keycode) {
- if (!punctuating || selection)
- return false;
-
- // In both the space space and the space period case we call this function
- function fixPunctuation(keycode) {
- keyboard.sendKey(BACKSPACE);
- keyboard.sendKey(keycode);
- keyboard.sendKey(SPACE);
-
- inputText = inputText.substring(0, cursor - 1) +
- String.fromCharCode(keycode) +
- ' ' +
- inputText.substring(cursor);
- cursor++;
- }
-
- switch (keycode) {
- case SPACE:
- var now = Date.now();
-
- if (lastKeyWasSpace &&
- (now - lastKeyWasSpace) < DOUBLE_SPACE_TIME &&
- cursor >= 2 &&
- !isWhiteSpace(inputText[cursor - 2]))
- {
- fixPunctuation(PERIOD);
- lastKeyWasSpace = 0;
- return true;
- }
-
- lastKeyWasSpace = now;
- return false;
-
- case PERIOD:
- case QUESTION:
- case EXCLAMATION:
- case COMMA:
- lastKeyWasSpace = 0;
- if (cursor >= 2 &&
- isWhiteSpace(inputText[cursor - 1]) &&
- !isWhiteSpace(inputText[cursor - 2])) {
- fixPunctuation(keycode);
- return true;
- }
- return false;
-
- default:
- lastKeyWasSpace = 0;
- return false;
- }
- }
-
- function updateState(keycode) {
- if (keycode === BACKSPACE) {
- if (selection) {
- // backspace while a region is selected erases the selection
- // and leaves the cursor at the selection start
- inputText = inputText.substring(0, cursor) +
- inputText.substring(selection);
- selection = 0;
- } else if (cursor > 0) {
- cursor--;
- inputText = inputText.substring(0, cursor) +
- inputText.substring(cursor + 1);
- }
- } else {
- if (selection) {
- inputText =
- inputText.substring(0, cursor) +
- String.fromCharCode(keycode) +
- inputText.substring(selection);
- selection = 0;
- } else {
- inputText =
- inputText.substring(0, cursor) +
- String.fromCharCode(keycode) +
- inputText.substring(cursor);
- }
- cursor++;
- }
+ worker.postMessage({cmd: 'predict', args: [wordBeforeCursor()]});
}
function updateCapitalization() {
@@ -450,8 +677,23 @@
return false;
// We're at the end of a word if the cursor is not at the start and
- // the character before the cursor is a letter
- return cursor > 0 && LETTER.test(inputText[cursor - 1]);
+ // the character before the cursor is not whitespace
+ return cursor > 0 && !WS.test(inputText[cursor - 1]);
+ }
+
+ // Get the word before the cursor
+ function wordBeforeCursor() {
+ // Otherwise, find the word we're at the end of and ask for completions
+ for (var firstletter = cursor - 1; firstletter >= 0; firstletter--) {
+ if (WS.test(inputText[firstletter])) {
+ break;
+ }
+ }
+ firstletter++;
+
+ // firstletter is now the position of the start of the word and cursor is
+ // the end of the word
+ return inputText.substring(firstletter, cursor);
}
function atSentenceStart() {
View
2  apps/keyboard/js/imes/latin/predictions.js
@@ -277,7 +277,7 @@ var Predictions = function() {
}
// Record the suggestion and move to the next best candidate
if (!(prefix in _suggestions_index)) {
- _suggestions.push(prefix);
+ _suggestions.push([prefix, cand.freq]);
_suggestions_index[prefix] = true;
}
}
View
8 apps/keyboard/js/imes/latin/worker.js
@@ -38,7 +38,7 @@ self.onmessage = function(e) {
// Send console messages back to the main thread with this method
function log(msg) {
- postMessage({cmd: 'log', args: [msg]});
+ postMessage({cmd: 'log', message: msg});
}
// Track our current language so we don't load dictionaries more often
@@ -66,7 +66,7 @@ var Commands = {
//
if (!xhr.response || xhr.response.byteLength === 0) {
log('error loading dictionary');
- postMessage({ cmd: 'unknownLanguage', args: [language] });
+ postMessage({ cmd: 'unknownLanguage', language: language });
}
else {
Predictions.setDictionary(xhr.response);
@@ -81,11 +81,11 @@ var Commands = {
predict: function predict(prefix) {
try {
var words = Predictions.predict(prefix);
- postMessage({ cmd: 'predictions', args: words });
+ postMessage({ cmd: 'predictions', input: prefix, suggestions: words });
}
catch (e) {
log('Exception in predictions.js: ' + JSON.stringify(e));
- postMessage({cmd: 'predictions', args: [] });
+ postMessage({cmd: 'predictions', input: prefix, suggestions: [] });
}
}
};
View
19 apps/keyboard/js/keyboard.js
@@ -232,6 +232,7 @@ const specialCodes = [
// These values are initialized with user settings
var userLanguage;
var suggestionsEnabled;
+var correctionsEnabled;
var clickEnabled;
var vibrationEnabled;
var enabledKeyboardGroups;
@@ -279,11 +280,12 @@ window.addEventListener('load', getKeyboardSettings);
function getKeyboardSettings() {
// Before we can initialize the keyboard we need to know the current
- // value of all keyboard-related settings. These are two of the settings
- // we want to query, with the default value we'll use
+ // value of all keyboard-related settings. These are the settings
+ // we want to query, with the default values we'll use if the query fails
var settingsQuery = {
'language.current': 'en-US',
'keyboard.wordsuggestion': true,
+ 'keyboard.autocorrect': true,
'keyboard.vibration': false,
'keyboard.clicksound': false,
'ring.enabled': true
@@ -299,6 +301,7 @@ function getKeyboardSettings() {
// Copy settings values to the corresponding global variables.
userLanguage = values['language.current'];
suggestionsEnabled = values['keyboard.wordsuggestion'];
+ correctionsEnabled = values['keyboard.autocorrect'];
vibrationEnabled = values['keyboard.vibration'];
clickEnabled = values['keyboard.clicksound'];
isSoundEnabled = values['ring.enabled'];
@@ -337,6 +340,13 @@ function initKeyboard() {
suggestionsEnabled = e.settingValue;
});
+ navigator.mozSettings.addObserver('keyboard.autocorrect', function(e) {
+ // The keyboard won't be displayed when this setting changes, so we
+ // don't need to tell the keyboard about the new value right away.
+ // We pass the value to the input method when the keyboard is displayed
+ correctionsEnabled = e.settingValue;
+ });
+
navigator.mozSettings.addObserver('keyboard.vibration', function(e) {
vibrationEnabled = e.settingValue;
});
@@ -1388,7 +1398,10 @@ function showKeyboard(state) {
resetKeyboard();
if (inputMethod.activate) {
- inputMethod.activate(userLanguage, suggestionsEnabled, state);
+ inputMethod.activate(userLanguage, state, {
+ suggest: suggestionsEnabled,
+ correct: correctionsEnabled
+ });
}
if (!inputMethod.displaysCandidates ||
View
4 apps/keyboard/js/render.js
@@ -261,6 +261,10 @@ const IMERender = (function() {
var span = document.createElement('span');
span.dataset.selection = true;
if (typeof candidate === 'string') {
+ if (candidate[0] === '*') { // it is an autocorrection candidate
+ candidate = candidate.substring(1);
+ span.classList.add('autocorrect');
+ }
span.dataset.data = span.textContent = candidate;
}
else {
View
7 apps/keyboard/style/keyboard.css
@@ -583,7 +583,7 @@ bubble above the key when you tap and hold. */
border-right: 0.1rem solid #808098;
font-size: 3.2rem;
line-height: 6rem;
- min-width: 6rem;
+ min-width: 5rem;
display: inline-block;
height: 6.4rem;
padding: 0 1rem;
@@ -602,6 +602,11 @@ bubble above the key when you tap and hold. */
margin: 0.3rem;
}
+#keyboard-candidate-panel.latin span.autocorrect {
+ background: #0ac; /* XXX: gradient like above? */
+}
+
+
#keyboard-candidate-panel-toggle-button {
border-left: 0.1rem solid #e8e8ff;
border-right: 0.1rem solid #808098;
View
8 apps/keyboard/test/unit/latin_test.js
@@ -270,13 +270,13 @@ suite('latin input method capitalization and punctuation', function() {
// reset the output state
reset();
// activate the IM
- im.activate('en', false, {
+ im.activate('en', {
type: type,
inputmode: mode,
value: state.value,
selectionStart: state.cursor,
selectionEnd: state.cursor
- });
+ },{suggest: false, correct: false});
// Send the input one character at a time, converting
// the input to uppercase if the IM has set uppercase
@@ -357,13 +357,13 @@ suite("latin input method word suggestions", function() {
suggestionsExpected = expected;
reset();
- im.activate(language, enabled, {
+ im.activate(language, {
type: type,
inputmode: mode,
value: state.value,
selectionStart: state.cursor,
selectionEnd: state.se || state.cursor
- });
+ }, { suggest: enabled, correct: false});
// Send some input and see if we get completions
im.click('t'.charCodeAt(0));
View
7 apps/settings/index.html
@@ -1442,6 +1442,13 @@ <h1 data-l10n-id="keyboard"> Keyboard </h1>
</li>
<li>
<label>
+ <input type="checkbox" name="keyboard.autocorrect"/>
+ <span></span>
+ </label>
+ <a data-l10n-id="autoCorrect">Auto correction</a>
+ </li>
+ <li>
+ <label>
<input type="checkbox" name="keyboard.wordsuggestion"/>
<span></span>
</label>
View
1  apps/settings/locales/settings.en-US.properties
@@ -286,6 +286,7 @@ keyboardLayouts=Keyboard layouts
keypad=Keypad
vibration=Vibration
clickSound=Click sound
+autoCorrect=Auto correction
wordSuggestion=Word suggestion
english=English
dvorak=English (Dvorak)
View
3  build/settings.py
@@ -56,7 +56,8 @@
"keyboard.layouts.spanish": False,
"keyboard.vibration": False,
"keyboard.clicksound": False,
- "keyboard.wordsuggestion": False,
+ "keyboard.autocorrect": True,
+ "keyboard.wordsuggestion": True,
"keyboard.current": "en",
"language.current": "en-US",
"lockscreen.passcode-lock.code": "0000",
Something went wrong with that request. Please try again.