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 |