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 |