| 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 'use strict'; | 5 'use strict'; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * @fileoverview Braille hardware keyboard input method. | 8 * @fileoverview Braille hardware keyboard input method. |
| 9 * | 9 * |
| 10 * This method is automatically enabled when a braille display is connected | 10 * This method is automatically enabled when a braille display is connected |
| 11 * and ChromeVox is turned on. Most of the braille input and editing logic | 11 * and ChromeVox is turned on. Most of the braille input and editing logic |
| 12 * is located in ChromeVox where the braille translation library is available. | 12 * is located in ChromeVox where the braille translation library is available. |
| 13 * This IME connects to ChromeVox and communicates using messages as follows: | 13 * This IME connects to ChromeVox and communicates using messages as follows: |
| 14 * | 14 * |
| 15 * Sent from this IME to ChromeVox: | 15 * Sent from this IME to ChromeVox: |
| 16 * {type: 'activeState', active: boolean} | 16 * {type: 'activeState', active: boolean} |
| 17 * {type: 'inputContext', context: InputContext} | 17 * {type: 'inputContext', context: InputContext} |
| 18 * Sent on focus/blur to inform ChromeVox of the type of the current field. | 18 * Sent on focus/blur to inform ChromeVox of the type of the current field. |
| 19 * In the latter case (blur), context is null. | 19 * In the latter case (blur), context is null. |
| 20 * {type: 'reset'} | 20 * {type: 'reset'} |
| 21 * Sent when the {@code onReset} IME event fires. | 21 * Sent when the {@code onReset} IME event fires or uncommitted text is |
| 22 * committed without being triggered by ChromeVox (e.g. because of a |
| 23 * key press). |
| 22 * {type: 'brailleDots', dots: number} | 24 * {type: 'brailleDots', dots: number} |
| 23 * Sent when the user typed a braille cell using the standard keyboard. | 25 * Sent when the user typed a braille cell using the standard keyboard. |
| 24 * ChromeVox treats this similarly to entering braille input using the | 26 * ChromeVox treats this similarly to entering braille input using the |
| 25 * braille display. | 27 * braille display. |
| 26 * {type: 'backspace', requestId: string} | 28 * {type: 'backspace', requestId: string} |
| 27 * Sent when the user presses the backspace key. | 29 * Sent when the user presses the backspace key. |
| 28 * ChromeVox must respond with a {@code keyEventHandled} message | 30 * ChromeVox must respond with a {@code keyEventHandled} message |
| 29 * with the same request id. | 31 * with the same request id. |
| 30 * | 32 * |
| 31 * Sent from ChromeVox to this IME: | 33 * Sent from ChromeVox to this IME: |
| 32 * {type: 'replaceText', contextID: number, deleteBefore: number, | 34 * {type: 'replaceText', contextID: number, deleteBefore: number, |
| 33 * newText: string} | 35 * newText: string} |
| 34 * Deletes {@code deleteBefore} characters before the cursor (or selection) | 36 * Deletes {@code deleteBefore} characters before the cursor (or selection) |
| 35 * and inserts {@code newText}. {@code contextID} identifies the text field | 37 * and inserts {@code newText}. {@code contextID} identifies the text field |
| 36 * to apply the update to (no change will happen if focus has moved to a | 38 * to apply the update to (no change will happen if focus has moved to a |
| 37 * different field). | 39 * different field). |
| 40 * {type: 'setUncommitted', contextID: number, text: string} |
| 41 * Stores text for the field identified by contextID to be committed |
| 42 * either as a result of a 'commitUncommitted' message or a by the IME |
| 43 * unhandled key press event. Unlike 'replaceText', this does not send the |
| 44 * uncommitted text to the input field, but instead stores it in the IME. |
| 45 * {type: 'commitUncommitted', contextID: number} |
| 46 * Commits any uncommitted text if it matches the given context ID. |
| 47 * See 'setUncommitted' above. |
| 38 * {type: 'keyEventHandled', requestId: string, result: boolean} | 48 * {type: 'keyEventHandled', requestId: string, result: boolean} |
| 39 * Response to a {@code backspace} message indicating whether the | 49 * Response to a {@code backspace} message indicating whether the |
| 40 * backspace was handled by ChromeVox or should be allowed to propagate | 50 * backspace was handled by ChromeVox or should be allowed to propagate |
| 41 * through the normal event handling pipeline. | 51 * through the normal event handling pipeline. |
| 42 */ | 52 */ |
| 43 | 53 |
| 44 /** | 54 /** |
| 45 * @constructor | 55 * @constructor |
| 46 */ | 56 */ |
| 47 var BrailleIme = function() {}; | 57 var BrailleIme = function() {}; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 engineID_: '', | 134 engineID_: '', |
| 125 | 135 |
| 126 /** | 136 /** |
| 127 * The port used to communicate with ChromeVox. | 137 * The port used to communicate with ChromeVox. |
| 128 * @type {Port} port_ | 138 * @type {Port} port_ |
| 129 * @private | 139 * @private |
| 130 */ | 140 */ |
| 131 port_: null, | 141 port_: null, |
| 132 | 142 |
| 133 /** | 143 /** |
| 144 * Uncommitted text and context ID. |
| 145 * @type {?{contextID: number, text: string}} |
| 146 * @private |
| 147 */ |
| 148 uncommitted_: null, |
| 149 |
| 150 /** |
| 134 * Registers event listeners in the chrome IME API. | 151 * Registers event listeners in the chrome IME API. |
| 135 */ | 152 */ |
| 136 init: function() { | 153 init: function() { |
| 137 chrome.input.ime.onActivate.addListener(this.onActivate_.bind(this)); | 154 chrome.input.ime.onActivate.addListener(this.onActivate_.bind(this)); |
| 138 chrome.input.ime.onDeactivated.addListener(this.onDeactivated_.bind(this)); | 155 chrome.input.ime.onDeactivated.addListener(this.onDeactivated_.bind(this)); |
| 139 chrome.input.ime.onFocus.addListener(this.onFocus_.bind(this)); | 156 chrome.input.ime.onFocus.addListener(this.onFocus_.bind(this)); |
| 140 chrome.input.ime.onBlur.addListener(this.onBlur_.bind(this)); | 157 chrome.input.ime.onBlur.addListener(this.onBlur_.bind(this)); |
| 141 chrome.input.ime.onInputContextUpdate.addListener( | 158 chrome.input.ime.onInputContextUpdate.addListener( |
| 142 this.onInputContextUpdate_.bind(this)); | 159 this.onInputContextUpdate_.bind(this)); |
| 143 chrome.input.ime.onKeyEvent.addListener(this.onKeyEvent_.bind(this), | 160 chrome.input.ime.onKeyEvent.addListener(this.onKeyEvent_.bind(this), |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 }, | 226 }, |
| 210 | 227 |
| 211 /** | 228 /** |
| 212 * Called by the system when this IME is active and a key event is generated. | 229 * Called by the system when this IME is active and a key event is generated. |
| 213 * @param {string} engineID Engine ID, should be 'braille'. | 230 * @param {string} engineID Engine ID, should be 'braille'. |
| 214 * @param {!ChromeKeyboardEvent} event The keyboard event. | 231 * @param {!ChromeKeyboardEvent} event The keyboard event. |
| 215 * @private | 232 * @private |
| 216 */ | 233 */ |
| 217 onKeyEvent_: function(engineID, event) { | 234 onKeyEvent_: function(engineID, event) { |
| 218 var result = this.processKey_(event); | 235 var result = this.processKey_(event); |
| 219 if (result !== undefined) { | 236 if (result !== undefined) |
| 220 chrome.input.ime.keyEventHandled(event.requestId, result); | 237 this.keyEventHandled_(event.requestId, event.type, result); |
| 221 } | |
| 222 }, | 238 }, |
| 223 | 239 |
| 224 /** | 240 /** |
| 225 * Called when chrome ends the current text input session. | 241 * Called when chrome ends the current text input session. |
| 226 * @param {string} engineID Engine ID, should be 'braille'. | 242 * @param {string} engineID Engine ID, should be 'braille'. |
| 227 * @private | 243 * @private |
| 228 */ | 244 */ |
| 229 onReset_: function(engineID) { | 245 onReset_: function(engineID) { |
| 230 this.log_('onReset', engineID); | 246 this.log_('onReset', engineID); |
| 231 this.engineID_ = engineID; | 247 this.engineID_ = engineID; |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 * @type {{contextID: number, deleteBefore: number, | 365 * @type {{contextID: number, deleteBefore: number, |
| 350 * newText: string}} | 366 * newText: string}} |
| 351 */ | 367 */ |
| 352 (message); | 368 (message); |
| 353 this.replaceText_(message.contextID, message.deleteBefore, | 369 this.replaceText_(message.contextID, message.deleteBefore, |
| 354 message.newText); | 370 message.newText); |
| 355 break; | 371 break; |
| 356 case 'keyEventHandled': | 372 case 'keyEventHandled': |
| 357 message = | 373 message = |
| 358 /** @type {{requestId: string, result: boolean}} */ (message); | 374 /** @type {{requestId: string, result: boolean}} */ (message); |
| 359 chrome.input.ime.keyEventHandled(message.requestId, message.result); | 375 this.keyEventHandled_(message.requestId, 'keydown', message.result); |
| 376 break; |
| 377 case 'setUncommitted': |
| 378 message = |
| 379 /** @type {{contextID: number, text: string}} */ (message); |
| 380 this.setUncommitted_(message.contextID, message.text); |
| 381 break; |
| 382 case 'commitUncommitted': |
| 383 message = |
| 384 /** @type {{contextID: number}} */ (message); |
| 385 this.commitUncommitted_(message.contextID); |
| 360 break; | 386 break; |
| 361 default: | 387 default: |
| 362 console.error('Unknown message from ChromeVox: ' + | 388 console.error('Unknown message from ChromeVox: ' + |
| 363 JSON.stringify(message)); | 389 JSON.stringify(message)); |
| 364 break; | 390 break; |
| 365 } | 391 } |
| 366 }, | 392 }, |
| 367 | 393 |
| 368 /** | 394 /** |
| 369 * Handles a disconnect event from the ChromeVox side. | 395 * Handles a disconnect event from the ChromeVox side. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 // deleteSurroundingText works correctly. | 449 // deleteSurroundingText works correctly. |
| 424 chrome.input.ime.deleteSurroundingText( | 450 chrome.input.ime.deleteSurroundingText( |
| 425 {engineID: this.engineID_, contextID: contextID, | 451 {engineID: this.engineID_, contextID: contextID, |
| 426 offset: 0, length: 0}, deleteText); | 452 offset: 0, length: 0}, deleteText); |
| 427 } else { | 453 } else { |
| 428 addText(); | 454 addText(); |
| 429 } | 455 } |
| 430 }, | 456 }, |
| 431 | 457 |
| 432 /** | 458 /** |
| 459 * Responds to an asynchronous key event, indicating whether it was handled |
| 460 * or not. If it wasn't handled, any uncommitted text is committed |
| 461 * before sending the response to the IME API. |
| 462 * @param {string} requestId Key event request id. |
| 463 * @param {string} type Type of key event being responded to. |
| 464 * @param {boolean} response Whether the IME handled the event. |
| 465 */ |
| 466 keyEventHandled_: function(requestId, type, response) { |
| 467 if (!response && type === 'keydown' && this.uncommitted_) { |
| 468 this.commitUncommitted_(this.uncommitted_.contextID); |
| 469 this.sendToChromeVox_({type: 'reset'}); |
| 470 } |
| 471 chrome.input.ime.keyEventHandled(requestId, response); |
| 472 }, |
| 473 |
| 474 /** |
| 475 * Stores uncommitted text that will be committed on any key press or |
| 476 * when {@code commitUncommitted_} is called. |
| 477 * @param {number} contextID of the current field. |
| 478 * @param {string} text to store. |
| 479 */ |
| 480 setUncommitted_: function(contextID, text) { |
| 481 this.uncommitted_ = {contextID: contextID, text: text}; |
| 482 }, |
| 483 |
| 484 /** |
| 485 * Commits the last set uncommitted text if it matches the given context id. |
| 486 * @param {number} contextID |
| 487 */ |
| 488 commitUncommitted_: function(contextID) { |
| 489 if (this.uncommitted_ && contextID === this.uncommitted_.contextID) |
| 490 chrome.input.ime.commitText(this.uncommitted_); |
| 491 this.uncommitted_ = null; |
| 492 }, |
| 493 |
| 494 /** |
| 433 * Updates the menu items for this IME. | 495 * Updates the menu items for this IME. |
| 434 */ | 496 */ |
| 435 updateMenuItems_: function() { | 497 updateMenuItems_: function() { |
| 436 // TODO(plundblad): Localize when translations available. | 498 // TODO(plundblad): Localize when translations available. |
| 437 chrome.input.ime.setMenuItems( | 499 chrome.input.ime.setMenuItems( |
| 438 {engineID: this.engineID_, | 500 {engineID: this.engineID_, |
| 439 items: [ | 501 items: [ |
| 440 { | 502 { |
| 441 id: this.USE_STANDARD_KEYBOARD_ID, | 503 id: this.USE_STANDARD_KEYBOARD_ID, |
| 442 label: 'Use standard keyboard for braille', | 504 label: 'Use standard keyboard for braille', |
| 443 style: 'check', | 505 style: 'check', |
| 444 visible: true, | 506 visible: true, |
| 445 checked: this.useStandardKeyboard_, | 507 checked: this.useStandardKeyboard_, |
| 446 enabled: true | 508 enabled: true |
| 447 } | 509 } |
| 448 ] | 510 ] |
| 449 }); | 511 }); |
| 450 } | 512 } |
| 451 }; | 513 }; |
| OLD | NEW |