| 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 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 SPACE: 0x100, | 113 SPACE: 0x100, |
| 114 | 114 |
| 115 /** | 115 /** |
| 116 * Maps key codes on a standard keyboard to the correspodning dots. | 116 * Maps key codes on a standard keyboard to the correspodning dots. |
| 117 * Keys on the 'home row' correspond to the keys on a Perkins-style keyboard. | 117 * Keys on the 'home row' correspond to the keys on a Perkins-style keyboard. |
| 118 * Note that the mapping below is arranged like the dots in a braille cell. | 118 * Note that the mapping below is arranged like the dots in a braille cell. |
| 119 * Only 6 dot input is supported. | 119 * Only 6 dot input is supported. |
| 120 * @private | 120 * @private |
| 121 * @const {Object<number>} | 121 * @const {Object<number>} |
| 122 */ | 122 */ |
| 123 CODE_TO_DOT_: {'KeyF': 0x01, 'KeyJ': 0x08, | 123 CODE_TO_DOT_: { |
| 124 'KeyD': 0x02, 'KeyK': 0x10, | 124 'KeyF': 0x01, |
| 125 'KeyS': 0x04, 'KeyL': 0x20, | 125 'KeyJ': 0x08, |
| 126 'Space': 0x100 }, | 126 'KeyD': 0x02, |
| 127 'KeyK': 0x10, |
| 128 'KeyS': 0x04, |
| 129 'KeyL': 0x20, |
| 130 'Space': 0x100 |
| 131 }, |
| 127 | 132 |
| 128 /** | 133 /** |
| 129 * The current engine ID as set by {@code onActivate}, or the empty string if | 134 * The current engine ID as set by {@code onActivate}, or the empty string if |
| 130 * the IME is not active. | 135 * the IME is not active. |
| 131 * @type {string} | 136 * @type {string} |
| 132 * @private | 137 * @private |
| 133 */ | 138 */ |
| 134 engineID_: '', | 139 engineID_: '', |
| 135 | 140 |
| 136 /** | 141 /** |
| (...skipping 13 matching lines...) Expand all Loading... |
| 150 /** | 155 /** |
| 151 * Registers event listeners in the chrome IME API. | 156 * Registers event listeners in the chrome IME API. |
| 152 */ | 157 */ |
| 153 init: function() { | 158 init: function() { |
| 154 chrome.input.ime.onActivate.addListener(this.onActivate_.bind(this)); | 159 chrome.input.ime.onActivate.addListener(this.onActivate_.bind(this)); |
| 155 chrome.input.ime.onDeactivated.addListener(this.onDeactivated_.bind(this)); | 160 chrome.input.ime.onDeactivated.addListener(this.onDeactivated_.bind(this)); |
| 156 chrome.input.ime.onFocus.addListener(this.onFocus_.bind(this)); | 161 chrome.input.ime.onFocus.addListener(this.onFocus_.bind(this)); |
| 157 chrome.input.ime.onBlur.addListener(this.onBlur_.bind(this)); | 162 chrome.input.ime.onBlur.addListener(this.onBlur_.bind(this)); |
| 158 chrome.input.ime.onInputContextUpdate.addListener( | 163 chrome.input.ime.onInputContextUpdate.addListener( |
| 159 this.onInputContextUpdate_.bind(this)); | 164 this.onInputContextUpdate_.bind(this)); |
| 160 chrome.input.ime.onKeyEvent.addListener(this.onKeyEvent_.bind(this), | 165 chrome.input.ime.onKeyEvent.addListener( |
| 161 ['async']); | 166 this.onKeyEvent_.bind(this), ['async']); |
| 162 chrome.input.ime.onReset.addListener(this.onReset_.bind(this)); | 167 chrome.input.ime.onReset.addListener(this.onReset_.bind(this)); |
| 163 chrome.input.ime.onMenuItemActivated.addListener( | 168 chrome.input.ime.onMenuItemActivated.addListener( |
| 164 this.onMenuItemActivated_.bind(this)); | 169 this.onMenuItemActivated_.bind(this)); |
| 165 this.connectChromeVox_(); | 170 this.connectChromeVox_(); |
| 166 }, | 171 }, |
| 167 | 172 |
| 168 /** | 173 /** |
| 169 * Called by the IME framework when this IME is activated. | 174 * Called by the IME framework when this IME is activated. |
| 170 * @param {string} engineID Engine ID, should be 'braille'. | 175 * @param {string} engineID Engine ID, should be 'braille'. |
| 171 * @private | 176 * @private |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 * {@code undefined} if handling was delegated to ChromeVox. | 296 * {@code undefined} if handling was delegated to ChromeVox. |
| 292 * @private | 297 * @private |
| 293 */ | 298 */ |
| 294 processKey_: function(event) { | 299 processKey_: function(event) { |
| 295 if (!this.useStandardKeyboard_) { | 300 if (!this.useStandardKeyboard_) { |
| 296 return false; | 301 return false; |
| 297 } | 302 } |
| 298 if (event.code === 'Backspace' && event.type === 'keydown') { | 303 if (event.code === 'Backspace' && event.type === 'keydown') { |
| 299 this.pressed_ = 0; | 304 this.pressed_ = 0; |
| 300 this.accumulated_ = 0; | 305 this.accumulated_ = 0; |
| 301 this.sendToChromeVox_( | 306 this.sendToChromeVox_({type: 'backspace', requestId: event.requestId}); |
| 302 {type: 'backspace', requestId: event.requestId}); | |
| 303 return undefined; | 307 return undefined; |
| 304 } | 308 } |
| 305 var dot = this.CODE_TO_DOT_[event.code]; | 309 var dot = this.CODE_TO_DOT_[event.code]; |
| 306 if (!dot || event.altKey || event.ctrlKey || event.shiftKey || | 310 if (!dot || event.altKey || event.ctrlKey || event.shiftKey || |
| 307 event.capsLock) { | 311 event.capsLock) { |
| 308 this.pressed_ = 0; | 312 this.pressed_ = 0; |
| 309 this.accumulated_ = 0; | 313 this.accumulated_ = 0; |
| 310 return false; | 314 return false; |
| 311 } | 315 } |
| 312 if (event.type === 'keydown') { | 316 if (event.type === 'keydown') { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 337 * Connects to the ChromeVox extension for message passing. | 341 * Connects to the ChromeVox extension for message passing. |
| 338 * @private | 342 * @private |
| 339 */ | 343 */ |
| 340 connectChromeVox_: function() { | 344 connectChromeVox_: function() { |
| 341 if (this.port_) { | 345 if (this.port_) { |
| 342 this.port_.disconnect(); | 346 this.port_.disconnect(); |
| 343 this.port_ = null; | 347 this.port_ = null; |
| 344 } | 348 } |
| 345 this.port_ = chrome.runtime.connect( | 349 this.port_ = chrome.runtime.connect( |
| 346 this.CHROMEVOX_EXTENSION_ID_, {name: this.PORT_NAME}); | 350 this.CHROMEVOX_EXTENSION_ID_, {name: this.PORT_NAME}); |
| 347 this.port_.onMessage.addListener( | 351 this.port_.onMessage.addListener(this.onChromeVoxMessage_.bind(this)); |
| 348 this.onChromeVoxMessage_.bind(this)); | 352 this.port_.onDisconnect.addListener(this.onChromeVoxDisconnect_.bind(this)); |
| 349 this.port_.onDisconnect.addListener( | |
| 350 this.onChromeVoxDisconnect_.bind(this)); | |
| 351 }, | 353 }, |
| 352 | 354 |
| 353 /** | 355 /** |
| 354 * Handles a message from the ChromeVox extension. | 356 * Handles a message from the ChromeVox extension. |
| 355 * @param {*} message The message from the extension. | 357 * @param {*} message The message from the extension. |
| 356 * @private | 358 * @private |
| 357 */ | 359 */ |
| 358 onChromeVoxMessage_: function(message) { | 360 onChromeVoxMessage_: function(message) { |
| 359 message = /** @type {{type: string}} */ (message); | 361 message = /** @type {{type: string}} */ (message); |
| 360 this.log_('onChromeVoxMessage', message); | 362 this.log_('onChromeVoxMessage', message); |
| 361 switch (message.type) { | 363 switch (message.type) { |
| 362 case 'replaceText': | 364 case 'replaceText': |
| 363 message = | 365 message = |
| 364 /** | 366 /** |
| 365 * @type {{contextID: number, deleteBefore: number, | 367 * @type {{contextID: number, deleteBefore: number, |
| 366 * newText: string}} | 368 * newText: string}} |
| 367 */ | 369 */ |
| 368 (message); | 370 (message); |
| 369 this.replaceText_(message.contextID, message.deleteBefore, | 371 this.replaceText_( |
| 370 message.newText); | 372 message.contextID, message.deleteBefore, message.newText); |
| 371 break; | 373 break; |
| 372 case 'keyEventHandled': | 374 case 'keyEventHandled': |
| 373 message = | 375 message = |
| 374 /** @type {{requestId: string, result: boolean}} */ (message); | 376 /** @type {{requestId: string, result: boolean}} */ (message); |
| 375 this.keyEventHandled_(message.requestId, 'keydown', message.result); | 377 this.keyEventHandled_(message.requestId, 'keydown', message.result); |
| 376 break; | 378 break; |
| 377 case 'setUncommitted': | 379 case 'setUncommitted': |
| 378 message = | 380 message = |
| 379 /** @type {{contextID: number, text: string}} */ (message); | 381 /** @type {{contextID: number, text: string}} */ (message); |
| 380 this.setUncommitted_(message.contextID, message.text); | 382 this.setUncommitted_(message.contextID, message.text); |
| 381 break; | 383 break; |
| 382 case 'commitUncommitted': | 384 case 'commitUncommitted': |
| 383 message = | 385 message = |
| 384 /** @type {{contextID: number}} */ (message); | 386 /** @type {{contextID: number}} */ (message); |
| 385 this.commitUncommitted_(message.contextID); | 387 this.commitUncommitted_(message.contextID); |
| 386 break; | 388 break; |
| 387 default: | 389 default: |
| 388 console.error('Unknown message from ChromeVox: ' + | 390 console.error( |
| 389 JSON.stringify(message)); | 391 'Unknown message from ChromeVox: ' + JSON.stringify(message)); |
| 390 break; | 392 break; |
| 391 } | 393 } |
| 392 }, | 394 }, |
| 393 | 395 |
| 394 /** | 396 /** |
| 395 * Handles a disconnect event from the ChromeVox side. | 397 * Handles a disconnect event from the ChromeVox side. |
| 396 * @private | 398 * @private |
| 397 */ | 399 */ |
| 398 onChromeVoxDisconnect_: function() { | 400 onChromeVoxDisconnect_: function() { |
| 399 this.port_ = null; | 401 this.port_ = null; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 419 */ | 421 */ |
| 420 sendInputContext_: function(context) { | 422 sendInputContext_: function(context) { |
| 421 this.sendToChromeVox_({type: 'inputContext', context: context}); | 423 this.sendToChromeVox_({type: 'inputContext', context: context}); |
| 422 }, | 424 }, |
| 423 | 425 |
| 424 /** | 426 /** |
| 425 * Sends the active state to ChromeVox. | 427 * Sends the active state to ChromeVox. |
| 426 * @private | 428 * @private |
| 427 */ | 429 */ |
| 428 sendActiveState_: function() { | 430 sendActiveState_: function() { |
| 429 this.sendToChromeVox_({type: 'activeState', | 431 this.sendToChromeVox_( |
| 430 active: this.engineID_.length > 0}); | 432 {type: 'activeState', active: this.engineID_.length > 0}); |
| 431 }, | 433 }, |
| 432 | 434 |
| 433 /** | 435 /** |
| 434 * Replaces text in the current text field. | 436 * Replaces text in the current text field. |
| 435 * @param {number} contextID Context for the input field to replace the | 437 * @param {number} contextID Context for the input field to replace the |
| 436 * text in. | 438 * text in. |
| 437 * @param {number} deleteBefore How many characters to delete before the | 439 * @param {number} deleteBefore How many characters to delete before the |
| 438 * cursor. | 440 * cursor. |
| 439 * @param {string} toInsert Text to insert at the cursor. | 441 * @param {string} toInsert Text to insert at the cursor. |
| 440 */ | 442 */ |
| 441 replaceText_: function(contextID, deleteBefore, toInsert) { | 443 replaceText_: function(contextID, deleteBefore, toInsert) { |
| 442 var addText = chrome.input.ime.commitText.bind( | 444 var addText = chrome.input.ime.commitText.bind( |
| 443 null, {contextID: contextID, text: toInsert}, function() {}); | 445 null, {contextID: contextID, text: toInsert}, function() {}); |
| 444 if (deleteBefore > 0) { | 446 if (deleteBefore > 0) { |
| 445 var deleteText = chrome.input.ime.deleteSurroundingText.bind(null, | 447 var deleteText = chrome.input.ime.deleteSurroundingText.bind( |
| 446 {engineID: this.engineID_, contextID: contextID, | 448 null, { |
| 447 offset: -deleteBefore, length: deleteBefore}, addText); | 449 engineID: this.engineID_, |
| 450 contextID: contextID, |
| 451 offset: -deleteBefore, |
| 452 length: deleteBefore |
| 453 }, |
| 454 addText); |
| 448 // Make sure there's no non-zero length selection so that | 455 // Make sure there's no non-zero length selection so that |
| 449 // deleteSurroundingText works correctly. | 456 // deleteSurroundingText works correctly. |
| 450 chrome.input.ime.deleteSurroundingText( | 457 chrome.input.ime.deleteSurroundingText( |
| 451 {engineID: this.engineID_, contextID: contextID, | 458 { |
| 452 offset: 0, length: 0}, deleteText); | 459 engineID: this.engineID_, |
| 460 contextID: contextID, |
| 461 offset: 0, |
| 462 length: 0 |
| 463 }, |
| 464 deleteText); |
| 453 } else { | 465 } else { |
| 454 addText(); | 466 addText(); |
| 455 } | 467 } |
| 456 }, | 468 }, |
| 457 | 469 |
| 458 /** | 470 /** |
| 459 * Responds to an asynchronous key event, indicating whether it was handled | 471 * Responds to an asynchronous key event, indicating whether it was handled |
| 460 * or not. If it wasn't handled, any uncommitted text is committed | 472 * or not. If it wasn't handled, any uncommitted text is committed |
| 461 * before sending the response to the IME API. | 473 * before sending the response to the IME API. |
| 462 * @param {string} requestId Key event request id. | 474 * @param {string} requestId Key event request id. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 489 if (this.uncommitted_ && contextID === this.uncommitted_.contextID) | 501 if (this.uncommitted_ && contextID === this.uncommitted_.contextID) |
| 490 chrome.input.ime.commitText(this.uncommitted_); | 502 chrome.input.ime.commitText(this.uncommitted_); |
| 491 this.uncommitted_ = null; | 503 this.uncommitted_ = null; |
| 492 }, | 504 }, |
| 493 | 505 |
| 494 /** | 506 /** |
| 495 * Updates the menu items for this IME. | 507 * Updates the menu items for this IME. |
| 496 */ | 508 */ |
| 497 updateMenuItems_: function() { | 509 updateMenuItems_: function() { |
| 498 // TODO(plundblad): Localize when translations available. | 510 // TODO(plundblad): Localize when translations available. |
| 499 chrome.input.ime.setMenuItems( | 511 chrome.input.ime.setMenuItems({ |
| 500 {engineID: this.engineID_, | 512 engineID: this.engineID_, |
| 501 items: [ | 513 items: [{ |
| 502 { | 514 id: this.USE_STANDARD_KEYBOARD_ID, |
| 503 id: this.USE_STANDARD_KEYBOARD_ID, | 515 label: 'Use standard keyboard for braille', |
| 504 label: 'Use standard keyboard for braille', | 516 style: 'check', |
| 505 style: 'check', | 517 visible: true, |
| 506 visible: true, | 518 checked: this.useStandardKeyboard_, |
| 507 checked: this.useStandardKeyboard_, | 519 enabled: true |
| 508 enabled: true | 520 }] |
| 509 } | 521 }); |
| 510 ] | |
| 511 }); | |
| 512 } | 522 } |
| 513 }; | 523 }; |
| OLD | NEW |