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 |