Chromium Code Reviews| 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. |
| 22 * {type: 'brailleDots', dots: number} | 22 * {type: 'brailleDots', dots: number} |
| 23 * Sent when the user typed a braille cell using the standard keyboard. | 23 * Sent when the user typed a braille cell using the standard keyboard. |
| 24 * ChromeVox treats this similarly to entering braille input using the | 24 * ChromeVox treats this similarly to entering braille input using the |
| 25 * braille display. | 25 * braille display. |
| 26 * {type: 'backspace', requestId: string} | |
| 27 * Sent when the user presses the backspace key. | |
| 28 * ChromeVox must respond with a {@code keyEventHandled} message | |
| 29 * with the same request id. | |
| 26 * | 30 * |
| 27 * Sent from ChromeVox to this IME: | 31 * Sent from ChromeVox to this IME: |
| 28 * {type: 'replaceText', contextID: number, deleteBefore: number, | 32 * {type: 'replaceText', contextID: number, deleteBefore: number, |
| 29 * newText: string} | 33 * newText: string} |
| 30 * Deletes {@code deleteBefore} characters before the cursor (or selection) | 34 * Deletes {@code deleteBefore} characters before the cursor (or selection) |
| 31 * and inserts {@code newText}. {@code contextID} identifies the text field | 35 * and inserts {@code newText}. {@code contextID} identifies the text field |
| 32 * to apply the update to (no change will happen if focus has moved to a | 36 * to apply the update to (no change will happen if focus has moved to a |
| 33 * different field). | 37 * different field). |
| 38 * {type: 'keyEventHandled', requestId: string, result: boolean} | |
| 39 * Response to a {@code backspace} message indicating whether the | |
| 40 * backspace was handled by ChromeVox or should be allowed to propagate | |
| 41 * through the normal event handling pipeline. | |
| 34 */ | 42 */ |
| 35 | 43 |
| 36 /** | 44 /** |
| 37 * @constructor | 45 * @constructor |
| 38 */ | 46 */ |
| 39 var BrailleIme = function() {}; | 47 var BrailleIme = function() {}; |
| 40 | 48 |
| 41 BrailleIme.prototype = { | 49 BrailleIme.prototype = { |
| 42 /** | 50 /** |
| 43 * Whether to enable extra debug logging for the IME. | 51 * Whether to enable extra debug logging for the IME. |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 125 /** | 133 /** |
| 126 * Registers event listeners in the chrome IME API. | 134 * Registers event listeners in the chrome IME API. |
| 127 */ | 135 */ |
| 128 init: function() { | 136 init: function() { |
| 129 chrome.input.ime.onActivate.addListener(this.onActivate_.bind(this)); | 137 chrome.input.ime.onActivate.addListener(this.onActivate_.bind(this)); |
| 130 chrome.input.ime.onDeactivated.addListener(this.onDeactivated_.bind(this)); | 138 chrome.input.ime.onDeactivated.addListener(this.onDeactivated_.bind(this)); |
| 131 chrome.input.ime.onFocus.addListener(this.onFocus_.bind(this)); | 139 chrome.input.ime.onFocus.addListener(this.onFocus_.bind(this)); |
| 132 chrome.input.ime.onBlur.addListener(this.onBlur_.bind(this)); | 140 chrome.input.ime.onBlur.addListener(this.onBlur_.bind(this)); |
| 133 chrome.input.ime.onInputContextUpdate.addListener( | 141 chrome.input.ime.onInputContextUpdate.addListener( |
| 134 this.onInputContextUpdate_.bind(this)); | 142 this.onInputContextUpdate_.bind(this)); |
| 135 chrome.input.ime.onKeyEvent.addListener(this.onKeyEvent_.bind(this)); | 143 chrome.input.ime.onKeyEvent.addListener(this.onKeyEvent_.bind(this), |
| 144 ['async']); | |
| 136 chrome.input.ime.onReset.addListener(this.onReset_.bind(this)); | 145 chrome.input.ime.onReset.addListener(this.onReset_.bind(this)); |
| 137 chrome.input.ime.onMenuItemActivated.addListener( | 146 chrome.input.ime.onMenuItemActivated.addListener( |
| 138 this.onMenuItemActivated_.bind(this)); | 147 this.onMenuItemActivated_.bind(this)); |
| 139 this.connectChromeVox_(); | 148 this.connectChromeVox_(); |
| 140 }, | 149 }, |
| 141 | 150 |
| 142 /** | 151 /** |
| 143 * Called by the IME framework when this IME is activated. | 152 * Called by the IME framework when this IME is activated. |
| 144 * @param {string} engineID Engine ID, should be 'braille'. | 153 * @param {string} engineID Engine ID, should be 'braille'. |
| 145 * @private | 154 * @private |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 196 */ | 205 */ |
| 197 onInputContextUpdate_: function(context) { | 206 onInputContextUpdate_: function(context) { |
| 198 this.log_('onInputContextUpdate', JSON.stringify(context)); | 207 this.log_('onInputContextUpdate', JSON.stringify(context)); |
| 199 this.sendInputContext_(context); | 208 this.sendInputContext_(context); |
| 200 }, | 209 }, |
| 201 | 210 |
| 202 /** | 211 /** |
| 203 * Called by the system when this IME is active and a key event is generated. | 212 * Called by the system when this IME is active and a key event is generated. |
| 204 * @param {string} engineID Engine ID, should be 'braille'. | 213 * @param {string} engineID Engine ID, should be 'braille'. |
| 205 * @param {!ChromeKeyboardEvent} event The keyboard event. | 214 * @param {!ChromeKeyboardEvent} event The keyboard event. |
| 206 * @return {boolean} Whether the event was handled by this IME (true) or | |
| 207 * should be allowed to propagate. | |
| 208 * @private | 215 * @private |
| 209 */ | 216 */ |
| 210 onKeyEvent_: function(engineID, event) { | 217 onKeyEvent_: function(engineID, event) { |
| 211 this.log_('onKeyEvent', engineID + ', ' + JSON.stringify(event)); | 218 this.log_('onKeyEvent', engineID + ', ' + JSON.stringify(event)); |
| 212 return this.processKey_(event); | 219 var result = this.processKey_(event); |
| 220 if (result !== undefined) { | |
| 221 chrome.input.ime.keyEventHandled(event.requestId, result); | |
| 222 } | |
| 213 }, | 223 }, |
| 214 | 224 |
| 215 /** | 225 /** |
| 216 * Called when chrome ends the current text input session. | 226 * Called when chrome ends the current text input session. |
| 217 * @param {string} engineID Engine ID, should be 'braille'. | 227 * @param {string} engineID Engine ID, should be 'braille'. |
| 218 * @private | 228 * @private |
| 219 */ | 229 */ |
| 220 onReset_: function(engineID) { | 230 onReset_: function(engineID) { |
| 221 this.log_('onReset', engineID); | 231 this.log_('onReset', engineID); |
| 222 this.engineID_ = engineID; | 232 this.engineID_ = engineID; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 255 return; | 265 return; |
| 256 } | 266 } |
| 257 if (this.DEBUG) { | 267 if (this.DEBUG) { |
| 258 console.log('BrailleIme.' + func + ': ' + message); | 268 console.log('BrailleIme.' + func + ': ' + message); |
| 259 } | 269 } |
| 260 }, | 270 }, |
| 261 | 271 |
| 262 /** | 272 /** |
| 263 * Handles a qwerty key on the home row as a braille key. | 273 * Handles a qwerty key on the home row as a braille key. |
| 264 * @param {!ChromeKeyboardEvent} event Keyboard event. | 274 * @param {!ChromeKeyboardEvent} event Keyboard event. |
| 265 * @return {boolean} Whether the key event was handled or not. | 275 * @return {boolean|undefined} Whether the event was handled, or |
| 276 * {@code undefined} if handling was delegated to ChromeVox. | |
| 266 * @private | 277 * @private |
| 267 */ | 278 */ |
| 268 processKey_: function(event) { | 279 processKey_: function(event) { |
| 269 if (!this.useStandardKeyboard_) { | 280 if (!this.useStandardKeyboard_) { |
| 270 return false; | 281 return false; |
| 271 } | 282 } |
| 283 if (event.code === 'Backspace' && event.type === 'keydown') { | |
| 284 this.pressed_ = 0; | |
| 285 this.accumulated_ = 0; | |
| 286 this.sendToChromeVox_( | |
| 287 {type: 'backspace', requestId: event.requestId}); | |
| 288 return undefined; | |
| 289 } | |
| 272 var dot = this.CODE_TO_DOT_[event.code]; | 290 var dot = this.CODE_TO_DOT_[event.code]; |
| 273 if (!dot || event.altKey || event.ctrlKey || event.shiftKey || | 291 if (!dot || event.altKey || event.ctrlKey || event.shiftKey || |
| 274 event.capsLock) { | 292 event.capsLock) { |
| 275 this.pressed_ = 0; | 293 this.pressed_ = 0; |
| 276 this.accumulated_ = 0; | 294 this.accumulated_ = 0; |
| 277 return false; | 295 return false; |
| 278 } | 296 } |
| 279 if (event.type === 'keydown') { | 297 if (event.type === 'keydown') { |
| 280 this.pressed_ |= dot; | 298 this.pressed_ |= dot; |
| 281 this.accumulated_ |= this.pressed_; | 299 this.accumulated_ |= this.pressed_; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 329 case 'replaceText': | 347 case 'replaceText': |
| 330 message = | 348 message = |
| 331 /** | 349 /** |
| 332 * @type {{contextID: number, deleteBefore: number, | 350 * @type {{contextID: number, deleteBefore: number, |
| 333 * newText: string}} | 351 * newText: string}} |
| 334 */ | 352 */ |
| 335 (message); | 353 (message); |
| 336 this.replaceText_(message.contextID, message.deleteBefore, | 354 this.replaceText_(message.contextID, message.deleteBefore, |
| 337 message.newText); | 355 message.newText); |
| 338 break; | 356 break; |
| 357 case 'keyEventHandled': | |
| 358 message = | |
| 359 /** @type {{requestId: string, result: boolean}} */ (message); | |
| 360 chrome.input.ime.keyEventHandled(message.requestId, message.result); | |
| 361 break; | |
| 362 default: | |
| 363 console.error('Unknown message from ChromeVox: ' + | |
| 364 JSON.stringify(message)); | |
| 365 break; | |
| 339 } | 366 } |
| 340 }, | 367 }, |
| 341 | 368 |
| 342 /** | 369 /** |
| 343 * Handles a disconnect event from the ChromeVox side. | 370 * Handles a disconnect event from the ChromeVox side. |
| 344 * @private | 371 * @private |
| 345 */ | 372 */ |
| 346 onChromeVoxDisconnect_: function() { | 373 onChromeVoxDisconnect_: function() { |
| 347 this.port_ = null; | 374 this.port_ = null; |
| 348 this.log_('onChromeVoxDisconnect', | 375 this.log_('onChromeVoxDisconnect', |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 381 | 408 |
| 382 /** | 409 /** |
| 383 * Replaces text in the current text field. | 410 * Replaces text in the current text field. |
| 384 * @param {number} contextID Context for the input field to replace the | 411 * @param {number} contextID Context for the input field to replace the |
| 385 * text in. | 412 * text in. |
| 386 * @param {number} deleteBefore How many characters to delete before the | 413 * @param {number} deleteBefore How many characters to delete before the |
| 387 * cursor. | 414 * cursor. |
| 388 * @param {string} toInsert Text to insert at the cursor. | 415 * @param {string} toInsert Text to insert at the cursor. |
| 389 */ | 416 */ |
| 390 replaceText_: function(contextID, deleteBefore, toInsert) { | 417 replaceText_: function(contextID, deleteBefore, toInsert) { |
| 418 console.log('replaceText: ' + deleteBefore + ',' + toInsert); | |
|
David Tseng
2014/06/19 21:30:16
nit: Remove
| |
| 391 var addText = function() { | 419 var addText = function() { |
| 392 chrome.input.ime.commitText( | 420 chrome.input.ime.commitText( |
| 393 {contextID: contextID, text: toInsert}); | 421 {contextID: contextID, text: toInsert}); |
| 394 }.bind(this); | 422 }.bind(this); |
| 395 if (deleteBefore > 0) { | 423 if (deleteBefore > 0) { |
| 396 var deleteText = function() { | 424 var deleteText = function() { |
| 397 chrome.input.ime.deleteSurroundingText( | 425 chrome.input.ime.deleteSurroundingText( |
| 398 {engineID: this.engineID_, contextID: contextID, | 426 {engineID: this.engineID_, contextID: contextID, |
| 399 offset: -deleteBefore, length: deleteBefore}, addText); | 427 offset: -deleteBefore, length: deleteBefore}, addText); |
| 400 }.bind(this); | 428 }.bind(this); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 421 label: 'Use standard keyboard for braille', | 449 label: 'Use standard keyboard for braille', |
| 422 style: 'check', | 450 style: 'check', |
| 423 visible: true, | 451 visible: true, |
| 424 checked: this.useStandardKeyboard_, | 452 checked: this.useStandardKeyboard_, |
| 425 enabled: true | 453 enabled: true |
| 426 } | 454 } |
| 427 ] | 455 ] |
| 428 }); | 456 }); |
| 429 } | 457 } |
| 430 }; | 458 }; |
| OLD | NEW |