| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview Handles braille input keys when the user is typing or editing | 6 * @fileoverview Handles braille input keys when the user is typing or editing |
| 7 * text in an input field. This class cooperates with the Braille IME | 7 * text in an input field. This class cooperates with the Braille IME |
| 8 * that is built into Chrome OS to do the actual text editing. | 8 * that is built into Chrome OS to do the actual text editing. |
| 9 */ | 9 */ |
| 10 | 10 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 | 86 |
| 87 this.translatorManager_.addChangeListener( | 87 this.translatorManager_.addChangeListener( |
| 88 this.commitAndClearEntryState_.bind(this)); | 88 this.commitAndClearEntryState_.bind(this)); |
| 89 }; | 89 }; |
| 90 | 90 |
| 91 /** | 91 /** |
| 92 * The ID of the Braille IME extension built into Chrome OS. | 92 * The ID of the Braille IME extension built into Chrome OS. |
| 93 * @const {string} | 93 * @const {string} |
| 94 * @private | 94 * @private |
| 95 */ | 95 */ |
| 96 cvox.BrailleInputHandler.IME_EXTENSION_ID_ = | 96 cvox.BrailleInputHandler.IME_EXTENSION_ID_ = 'jddehjeebkoimngcbdkaahpobgicbffp'; |
| 97 'jddehjeebkoimngcbdkaahpobgicbffp'; | |
| 98 | 97 |
| 99 /** | 98 /** |
| 100 * Name of the port to use for communicating with the Braille IME. | 99 * Name of the port to use for communicating with the Braille IME. |
| 101 * @const {string} | 100 * @const {string} |
| 102 * @private | 101 * @private |
| 103 */ | 102 */ |
| 104 cvox.BrailleInputHandler.IME_PORT_NAME_ = 'cvox.BrailleIme.Port'; | 103 cvox.BrailleInputHandler.IME_PORT_NAME_ = 'cvox.BrailleIme.Port'; |
| 105 | 104 |
| 106 /** | 105 /** |
| 107 * Regular expression that matches a string that starts with at least one | 106 * Regular expression that matches a string that starts with at least one |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 | 167 |
| 169 /** | 168 /** |
| 170 * Handles braille key events used for input by editing the current input | 169 * Handles braille key events used for input by editing the current input |
| 171 * field appropriately. | 170 * field appropriately. |
| 172 * @param {!cvox.BrailleKeyEvent} event The key event. | 171 * @param {!cvox.BrailleKeyEvent} event The key event. |
| 173 * @return {boolean} {@code true} if the event was handled, {@code false} | 172 * @return {boolean} {@code true} if the event was handled, {@code false} |
| 174 * if it should propagate further. | 173 * if it should propagate further. |
| 175 */ | 174 */ |
| 176 onBrailleKeyEvent: function(event) { | 175 onBrailleKeyEvent: function(event) { |
| 177 if (event.command === cvox.BrailleKeyCommand.DOTS) | 176 if (event.command === cvox.BrailleKeyCommand.DOTS) |
| 178 return this.onBrailleDots_(/** @type {number} */(event.brailleDots)); | 177 return this.onBrailleDots_(/** @type {number} */ (event.brailleDots)); |
| 179 // Any other braille command cancels the pending cells. | 178 // Any other braille command cancels the pending cells. |
| 180 this.pendingCells_.length = 0; | 179 this.pendingCells_.length = 0; |
| 181 if (event.command === cvox.BrailleKeyCommand.STANDARD_KEY) { | 180 if (event.command === cvox.BrailleKeyCommand.STANDARD_KEY) { |
| 182 if (event.standardKeyCode === 'Backspace' && | 181 if (event.standardKeyCode === 'Backspace' && !event.altKey && |
| 183 !event.altKey && !event.ctrlKey && !event.shiftKey && | 182 !event.ctrlKey && !event.shiftKey && this.onBackspace_()) { |
| 184 this.onBackspace_()) { | |
| 185 return true; | 183 return true; |
| 186 } else { | 184 } else { |
| 187 this.commitAndClearEntryState_(); | 185 this.commitAndClearEntryState_(); |
| 188 this.sendKeyEventPair_(event); | 186 this.sendKeyEventPair_(event); |
| 189 return true; | 187 return true; |
| 190 } | 188 } |
| 191 } | 189 } |
| 192 return false; | 190 return false; |
| 193 }, | 191 }, |
| 194 | 192 |
| 195 /** | 193 /** |
| 196 * Returns how the value of the currently displayed content should be | 194 * Returns how the value of the currently displayed content should be |
| 197 * expanded given the current input state. | 195 * expanded given the current input state. |
| 198 * @return {cvox.ExpandingBrailleTranslator.ExpansionType} | 196 * @return {cvox.ExpandingBrailleTranslator.ExpansionType} |
| 199 * The current expansion type. | 197 * The current expansion type. |
| 200 */ | 198 */ |
| 201 getExpansionType: function() { | 199 getExpansionType: function() { |
| 202 if (this.inAlwaysUncontractedContext_()) | 200 if (this.inAlwaysUncontractedContext_()) |
| 203 return cvox.ExpandingBrailleTranslator.ExpansionType.ALL; | 201 return cvox.ExpandingBrailleTranslator.ExpansionType.ALL; |
| 204 if (this.entryState_ && | 202 if (this.entryState_ && |
| 205 this.entryState_.translator === | 203 this.entryState_.translator === |
| 206 this.translatorManager_.getDefaultTranslator()) { | 204 this.translatorManager_.getDefaultTranslator()) { |
| 207 return cvox.ExpandingBrailleTranslator.ExpansionType.NONE; | 205 return cvox.ExpandingBrailleTranslator.ExpansionType.NONE; |
| 208 } | 206 } |
| 209 return cvox.ExpandingBrailleTranslator.ExpansionType.SELECTION; | 207 return cvox.ExpandingBrailleTranslator.ExpansionType.SELECTION; |
| 210 }, | 208 }, |
| 211 | 209 |
| 212 /** | 210 /** |
| 213 * @return {boolean} {@code true} if we have an input context and | 211 * @return {boolean} {@code true} if we have an input context and |
| 214 * uncontracted braille should always be used for that context. | 212 * uncontracted braille should always be used for that context. |
| 215 * @private | 213 * @private |
| 216 */ | 214 */ |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 this.imePort_ = port; | 339 this.imePort_ = port; |
| 342 }, | 340 }, |
| 343 | 341 |
| 344 /** | 342 /** |
| 345 * Called when a message is received from the IME. | 343 * Called when a message is received from the IME. |
| 346 * @param {*} message The message. | 344 * @param {*} message The message. |
| 347 * @private | 345 * @private |
| 348 */ | 346 */ |
| 349 onImeMessage_: function(message) { | 347 onImeMessage_: function(message) { |
| 350 if (!goog.isObject(message)) { | 348 if (!goog.isObject(message)) { |
| 351 console.error('Unexpected message from Braille IME: ', | 349 console.error( |
| 352 JSON.stringify(message)); | 350 'Unexpected message from Braille IME: ', JSON.stringify(message)); |
| 353 } | 351 } |
| 354 switch (message.type) { | 352 switch (message.type) { |
| 355 case 'activeState': | 353 case 'activeState': |
| 356 this.imeActive_ = message.active; | 354 this.imeActive_ = message.active; |
| 357 break; | 355 break; |
| 358 case 'inputContext': | 356 case 'inputContext': |
| 359 this.inputContext_ = message.context; | 357 this.inputContext_ = message.context; |
| 360 this.clearEntryState_(); | 358 this.clearEntryState_(); |
| 361 if (this.imeActive_ && this.inputContext_) | 359 if (this.imeActive_ && this.inputContext_) |
| 362 this.pendingCells_.forEach(this.onBrailleDots_, this); | 360 this.pendingCells_.forEach(this.onBrailleDots_, this); |
| 363 this.pendingCells_.length = 0; | 361 this.pendingCells_.length = 0; |
| 364 break; | 362 break; |
| 365 case 'brailleDots': | 363 case 'brailleDots': |
| 366 this.onBrailleDots_(message['dots']); | 364 this.onBrailleDots_(message['dots']); |
| 367 break; | 365 break; |
| 368 case 'backspace': | 366 case 'backspace': |
| 369 // Note that we can't send the backspace key through the | 367 // Note that we can't send the backspace key through the |
| 370 // virtualKeyboardPrivate API in this case because it would then be | 368 // virtualKeyboardPrivate API in this case because it would then be |
| 371 // processed by the IME again, leading to an infinite loop. | 369 // processed by the IME again, leading to an infinite loop. |
| 372 this.postImeMessage_( | 370 this.postImeMessage_({ |
| 373 {type: 'keyEventHandled', requestId: message['requestId'], | 371 type: 'keyEventHandled', |
| 374 result: this.onBackspace_()}); | 372 requestId: message['requestId'], |
| 373 result: this.onBackspace_() |
| 374 }); |
| 375 break; | 375 break; |
| 376 case 'reset': | 376 case 'reset': |
| 377 this.clearEntryState_(); | 377 this.clearEntryState_(); |
| 378 break; | 378 break; |
| 379 default: | 379 default: |
| 380 console.error('Unexpected message from Braille IME: ', | 380 console.error( |
| 381 JSON.stringify(message)); | 381 'Unexpected message from Braille IME: ', JSON.stringify(message)); |
| 382 break; | 382 break; |
| 383 } | 383 } |
| 384 }, | 384 }, |
| 385 | 385 |
| 386 /** | 386 /** |
| 387 * Called when the IME port is disconnected. | 387 * Called when the IME port is disconnected. |
| 388 * @param {Port} port The port that was disconnected. | 388 * @param {Port} port The port that was disconnected. |
| 389 * @private | 389 * @private |
| 390 */ | 390 */ |
| 391 onImeDisconnect_: function(port) { | 391 onImeDisconnect_: function(port) { |
| 392 this.imePort_ = null; | 392 this.imePort_ = null; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 var numericCode = cvox.BrailleKeyEvent.keyCodeToLegacyCode(keyName); | 424 var numericCode = cvox.BrailleKeyEvent.keyCodeToLegacyCode(keyName); |
| 425 if (!goog.isDef(numericCode)) | 425 if (!goog.isDef(numericCode)) |
| 426 throw Error('Unknown key code in event: ' + JSON.stringify(event)); | 426 throw Error('Unknown key code in event: ' + JSON.stringify(event)); |
| 427 var keyEvent = { | 427 var keyEvent = { |
| 428 type: 'keydown', | 428 type: 'keydown', |
| 429 keyCode: numericCode, | 429 keyCode: numericCode, |
| 430 keyName: keyName, | 430 keyName: keyName, |
| 431 charValue: cvox.BrailleKeyEvent.keyCodeToCharValue(keyName), | 431 charValue: cvox.BrailleKeyEvent.keyCodeToCharValue(keyName), |
| 432 // See chrome/common/extensions/api/virtual_keyboard_private.json for | 432 // See chrome/common/extensions/api/virtual_keyboard_private.json for |
| 433 // these constants. | 433 // these constants. |
| 434 modifiers: (event.shiftKey ? 2 : 0) | | 434 modifiers: (event.shiftKey ? 2 : 0) | (event.ctrlKey ? 4 : 0) | |
| 435 (event.ctrlKey ? 4 : 0) | | |
| 436 (event.altKey ? 8 : 0) | 435 (event.altKey ? 8 : 0) |
| 437 }; | 436 }; |
| 438 chrome.virtualKeyboardPrivate.sendKeyEvent(keyEvent); | 437 chrome.virtualKeyboardPrivate.sendKeyEvent(keyEvent); |
| 439 keyEvent.type = 'keyup'; | 438 keyEvent.type = 'keyup'; |
| 440 chrome.virtualKeyboardPrivate.sendKeyEvent(keyEvent); | 439 chrome.virtualKeyboardPrivate.sendKeyEvent(keyEvent); |
| 441 } | 440 } |
| 442 }; | 441 }; |
| 443 | 442 |
| 444 /** | 443 /** |
| 445 * The entry state is the state related to entering a series of braille cells | 444 * The entry state is the state related to entering a series of braille cells |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 537 } | 536 } |
| 538 // There was an actual text change (or cursor movement) that we hadn't | 537 // There was an actual text change (or cursor movement) that we hadn't |
| 539 // caused ourselves, reset any pending input. | 538 // caused ourselves, reset any pending input. |
| 540 this.inputHandler_.clearEntryState_(); | 539 this.inputHandler_.clearEntryState_(); |
| 541 }, | 540 }, |
| 542 | 541 |
| 543 /** | 542 /** |
| 544 * Makes sure the current text is permanently added to the edit field. | 543 * Makes sure the current text is permanently added to the edit field. |
| 545 * After this call, this object should be abandoned. | 544 * After this call, this object should be abandoned. |
| 546 */ | 545 */ |
| 547 commit: function() { | 546 commit: function() {}, |
| 548 }, | |
| 549 | 547 |
| 550 /** | 548 /** |
| 551 * @return {boolean} true if the entry state uses uncommitted cells. | 549 * @return {boolean} true if the entry state uses uncommitted cells. |
| 552 */ | 550 */ |
| 553 get usesUncommittedCells() { | 551 get usesUncommittedCells() { |
| 554 return false; | 552 return false; |
| 555 }, | 553 }, |
| 556 | 554 |
| 557 /** | 555 /** |
| 558 * Updates the translated text based on the current cells and sends the | 556 * Updates the translated text based on the current cells and sends the |
| (...skipping 26 matching lines...) Expand all Loading... |
| 585 get lastCellIsBlank_() { | 583 get lastCellIsBlank_() { |
| 586 return this.cells_[this.cells_.length - 1] === 0; | 584 return this.cells_[this.cells_.length - 1] === 0; |
| 587 }, | 585 }, |
| 588 | 586 |
| 589 /** | 587 /** |
| 590 * Sends new text to the IME. This dhould be overriden by subclasses. | 588 * Sends new text to the IME. This dhould be overriden by subclasses. |
| 591 * The old text is still available in the {@code text_} property. | 589 * The old text is still available in the {@code text_} property. |
| 592 * @param {string} newText Text to send. | 590 * @param {string} newText Text to send. |
| 593 * @private | 591 * @private |
| 594 */ | 592 */ |
| 595 sendTextChange_: function(newText) { | 593 sendTextChange_: function(newText) {} |
| 596 } | |
| 597 }; | 594 }; |
| 598 | 595 |
| 599 /** | 596 /** |
| 600 * Entry state that uses {@code deleteSurroundingText} and {@code commitText} | 597 * Entry state that uses {@code deleteSurroundingText} and {@code commitText} |
| 601 * calls to the IME to update the currently enetered text. | 598 * calls to the IME to update the currently enetered text. |
| 602 * @param {!cvox.BrailleInputHandler} inputHandler | 599 * @param {!cvox.BrailleInputHandler} inputHandler |
| 603 * @param {!cvox.LibLouis.Translator} translator | 600 * @param {!cvox.LibLouis.Translator} translator |
| 604 * @constructor | 601 * @constructor |
| 605 * @extends {cvox.BrailleInputHandler.EntryState_} | 602 * @extends {cvox.BrailleInputHandler.EntryState_} |
| 606 * @private | 603 * @private |
| 607 */ | 604 */ |
| 608 cvox.BrailleInputHandler.EditsEntryState_ = function( | 605 cvox.BrailleInputHandler.EditsEntryState_ = function(inputHandler, translator) { |
| 609 inputHandler, translator) { | |
| 610 cvox.BrailleInputHandler.EntryState_.call(this, inputHandler, translator); | 606 cvox.BrailleInputHandler.EntryState_.call(this, inputHandler, translator); |
| 611 }; | 607 }; |
| 612 | 608 |
| 613 cvox.BrailleInputHandler.EditsEntryState_.prototype = { | 609 cvox.BrailleInputHandler.EditsEntryState_.prototype = { |
| 614 __proto__: cvox.BrailleInputHandler.EntryState_.prototype, | 610 __proto__: cvox.BrailleInputHandler.EntryState_.prototype, |
| 615 | 611 |
| 616 /** @override */ | 612 /** @override */ |
| 617 sendTextChange_: function(newText) { | 613 sendTextChange_: function(newText) { |
| 618 var oldText = this.text_; | 614 var oldText = this.text_; |
| 619 // Find the common prefix of the old and new text. | 615 // Find the common prefix of the old and new text. |
| 620 var commonPrefixLength = StringUtil.longestCommonPrefixLength( | 616 var commonPrefixLength = |
| 621 oldText, newText); | 617 StringUtil.longestCommonPrefixLength(oldText, newText); |
| 622 // How many characters we need to delete from the existing text to replace | 618 // How many characters we need to delete from the existing text to replace |
| 623 // them with characters from the new text. | 619 // them with characters from the new text. |
| 624 var deleteLength = oldText.length - commonPrefixLength; | 620 var deleteLength = oldText.length - commonPrefixLength; |
| 625 // New text, if any, to insert after deleting the deleteLength characters | 621 // New text, if any, to insert after deleting the deleteLength characters |
| 626 // before the cursor. | 622 // before the cursor. |
| 627 var toInsert = newText.substring(commonPrefixLength); | 623 var toInsert = newText.substring(commonPrefixLength); |
| 628 if (deleteLength > 0 || toInsert.length > 0) { | 624 if (deleteLength > 0 || toInsert.length > 0) { |
| 629 // After deleting, we expect this text to be present before the cursor. | 625 // After deleting, we expect this text to be present before the cursor. |
| 630 var textBeforeAfterDelete = | 626 var textBeforeAfterDelete = |
| 631 this.inputHandler_.currentTextBefore_.substring( | 627 this.inputHandler_.currentTextBefore_.substring( |
| 632 0, this.inputHandler_.currentTextBefore_.length - deleteLength); | 628 0, this.inputHandler_.currentTextBefore_.length - deleteLength); |
| 633 if (deleteLength > 0) { | 629 if (deleteLength > 0) { |
| 634 // Queue this text up to be ignored when the change comes in. | 630 // Queue this text up to be ignored when the change comes in. |
| 635 this.pendingTextsBefore_.push(textBeforeAfterDelete); | 631 this.pendingTextsBefore_.push(textBeforeAfterDelete); |
| 636 } | 632 } |
| 637 if (toInsert.length > 0) { | 633 if (toInsert.length > 0) { |
| 638 // Likewise, queue up what we expect to be before the cursor after | 634 // Likewise, queue up what we expect to be before the cursor after |
| 639 // the replacement text is inserted. | 635 // the replacement text is inserted. |
| 640 this.pendingTextsBefore_.push(textBeforeAfterDelete + toInsert); | 636 this.pendingTextsBefore_.push(textBeforeAfterDelete + toInsert); |
| 641 } | 637 } |
| 642 // Send the replace operation to be performed asynchronously by the IME. | 638 // Send the replace operation to be performed asynchronously by the IME. |
| 643 this.inputHandler_.postImeMessage_( | 639 this.inputHandler_.postImeMessage_({ |
| 644 {type: 'replaceText', | 640 type: 'replaceText', |
| 645 contextID: this.inputHandler_.inputContext_.contextID, | 641 contextID: this.inputHandler_.inputContext_.contextID, |
| 646 deleteBefore: deleteLength, | 642 deleteBefore: deleteLength, |
| 647 newText: toInsert}); | 643 newText: toInsert |
| 644 }); |
| 648 } | 645 } |
| 649 } | 646 } |
| 650 }; | 647 }; |
| 651 | 648 |
| 652 /** | 649 /** |
| 653 * Entry state that only updates the edit field when a blank cell is entered. | 650 * Entry state that only updates the edit field when a blank cell is entered. |
| 654 * During the input of a single 'word', the uncommitted text is stored by the | 651 * During the input of a single 'word', the uncommitted text is stored by the |
| 655 * IME. | 652 * IME. |
| 656 * @param {!cvox.BrailleInputHandler} inputHandler | 653 * @param {!cvox.BrailleInputHandler} inputHandler |
| 657 * @param {!cvox.LibLouis.Translator} translator | 654 * @param {!cvox.LibLouis.Translator} translator |
| 658 * @constructor | 655 * @constructor |
| 659 * @private | 656 * @private |
| 660 * @extends {cvox.BrailleInputHandler.EntryState_} | 657 * @extends {cvox.BrailleInputHandler.EntryState_} |
| 661 */ | 658 */ |
| 662 cvox.BrailleInputHandler.LateCommitEntryState_ = function( | 659 cvox.BrailleInputHandler.LateCommitEntryState_ = function( |
| 663 inputHandler, translator) { | 660 inputHandler, translator) { |
| 664 cvox.BrailleInputHandler.EntryState_.call(this, inputHandler, translator); | 661 cvox.BrailleInputHandler.EntryState_.call(this, inputHandler, translator); |
| 665 }; | 662 }; |
| 666 | 663 |
| 667 cvox.BrailleInputHandler.LateCommitEntryState_.prototype = { | 664 cvox.BrailleInputHandler.LateCommitEntryState_.prototype = { |
| 668 __proto__: cvox.BrailleInputHandler.EntryState_.prototype, | 665 __proto__: cvox.BrailleInputHandler.EntryState_.prototype, |
| 669 | 666 |
| 670 /** @override */ | 667 /** @override */ |
| 671 commit: function() { | 668 commit: function() { |
| 672 this.inputHandler_.postImeMessage_( | 669 this.inputHandler_.postImeMessage_({ |
| 673 {type: 'commitUncommitted', | 670 type: 'commitUncommitted', |
| 674 contextID: this.inputHandler_.inputContext_.contextID}); | 671 contextID: this.inputHandler_.inputContext_.contextID |
| 672 }); |
| 675 }, | 673 }, |
| 676 | 674 |
| 677 /** @override */ | 675 /** @override */ |
| 678 get usesUncommittedCells() { | 676 get usesUncommittedCells() { |
| 679 return true; | 677 return true; |
| 680 }, | 678 }, |
| 681 | 679 |
| 682 /** @override */ | 680 /** @override */ |
| 683 sendTextChange_: function(newText) { | 681 sendTextChange_: function(newText) { |
| 684 this.inputHandler_.postImeMessage_( | 682 this.inputHandler_.postImeMessage_({ |
| 685 {type: 'setUncommitted', | 683 type: 'setUncommitted', |
| 686 contextID: this.inputHandler_.inputContext_.contextID, | 684 contextID: this.inputHandler_.inputContext_.contextID, |
| 687 text: newText}); | 685 text: newText |
| 686 }); |
| 688 } | 687 } |
| 689 }; | 688 }; |
| OLD | NEW |