| Index: chrome/browser/resources/access_chromevox/chromevox/background/accessibility_api_handler.js
|
| ===================================================================
|
| --- chrome/browser/resources/access_chromevox/chromevox/background/accessibility_api_handler.js (revision 0)
|
| +++ chrome/browser/resources/access_chromevox/chromevox/background/accessibility_api_handler.js (revision 0)
|
| @@ -0,0 +1,302 @@
|
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +/**
|
| + * @fileoverview Accesses Chrome's accessibility extension API and gives
|
| + * spoken feedback for events that happen in the "Chrome of Chrome".
|
| + */
|
| +
|
| +goog.provide('cvox.ChromeVoxAccessibilityApiHandler');
|
| +
|
| +goog.require('cvox.AbstractEarcons');
|
| +goog.require('cvox.AbstractEarconsManager');
|
| +goog.require('cvox.AbstractTtsManager');
|
| +goog.require('cvox.ChromeVoxEditableTextBase');
|
| +
|
| +/**
|
| + * Class that adds listeners and handles events from the accessibility API.
|
| + */
|
| +cvox.ChromeVoxAccessibilityApiHandler = function() {
|
| +};
|
| +
|
| +/**
|
| + * The object used to play earcons.
|
| + * @type Object
|
| + */
|
| +cvox.ChromeVoxAccessibilityApiHandler.ttsManager = null;
|
| +
|
| +/**
|
| + * The object used to manage speech.
|
| + * @type Object
|
| + */
|
| +cvox.ChromeVoxAccessibilityApiHandler.earconsManager = null;
|
| +
|
| +/**
|
| + * The object that can describe changes and cursor movement in a generic
|
| + * editable text field.
|
| + * @type Object
|
| + */
|
| +cvox.ChromeVoxAccessibilityApiHandler.editableTextHandler = null;
|
| +
|
| +/**
|
| + * Initialize the accessibility API Handler.
|
| + * @param {Object} ttsManager The TTS manager to use for speaking.
|
| + * @param {Object} earconsManager The earcons manager to use for playing
|
| + * earcons.
|
| + */
|
| +cvox.ChromeVoxAccessibilityApiHandler.init = function(ttsManager,
|
| + earconsManager) {
|
| + cvox.ChromeVoxAccessibilityApiHandler.ttsManager = ttsManager;
|
| + cvox.ChromeVoxAccessibilityApiHandler.earconsManager = earconsManager;
|
| + try {
|
| + chrome.experimental.accessibility.setAccessibilityEnabled(true);
|
| + cvox.ChromeVoxAccessibilityApiHandler.addEventListeners();
|
| + } catch (err) {
|
| + console.log('Error trying to access accessibility extension api.');
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * Adds event listeners.
|
| + */
|
| +cvox.ChromeVoxAccessibilityApiHandler.addEventListeners = function() {
|
| + var accessibility = chrome.experimental.accessibility;
|
| +
|
| + chrome.tabs.onCreated.addListener(function(tab) {
|
| + var tts = cvox.ChromeVoxAccessibilityApiHandler.ttsManager;
|
| + var title = tab.title ? tab.title : tab.url;
|
| + tts.speak(title + ', tab created.', 0, {});
|
| + var earcons = cvox.ChromeVoxAccessibilityApiHandler.earconsManager;
|
| + earcons.playEarcon(cvox.AbstractEarcons.OBJECT_OPEN);
|
| + });
|
| +
|
| + chrome.tabs.onRemoved.addListener(function(tab) {
|
| + var earcons = cvox.ChromeVoxAccessibilityApiHandler.earconsManager;
|
| + earcons.playEarcon(cvox.AbstractEarcons.OBJECT_CLOSE);
|
| + });
|
| +
|
| + chrome.tabs.onSelectionChanged.addListener(function(tabId, selectInfo) {
|
| + chrome.tabs.get(tabId, function(tab) {
|
| + var tts = cvox.ChromeVoxAccessibilityApiHandler.ttsManager;
|
| + var title = tab.title ? tab.title : tab.url;
|
| + tts.speak(title + ', tab.', 0, {});
|
| + var earcons = cvox.ChromeVoxAccessibilityApiHandler.earconsManager;
|
| + earcons.playEarcon(cvox.AbstractEarcons.OBJECT_SELECT);
|
| + });
|
| + });
|
| +
|
| + chrome.tabs.onUpdated.addListener(function(tabId, selectInfo) {
|
| + chrome.tabs.get(tabId, function(tab) {
|
| + var earcons = cvox.ChromeVoxAccessibilityApiHandler.earconsManager;
|
| + if (tab.status == 'loading') {
|
| + earcons.playEarcon(cvox.AbstractEarcons.BUSY_PROGRESS_LOOP);
|
| + } else {
|
| + earcons.playEarcon(cvox.AbstractEarcons.TASK_SUCCESS);
|
| + }
|
| + });
|
| + });
|
| +
|
| + chrome.experimental.accessibility.onWindowOpened.addListener(function(win) {
|
| + var tts = cvox.ChromeVoxAccessibilityApiHandler.ttsManager;
|
| + tts.speak(win.name + ', window opened.', 0, {});
|
| + var earcons = cvox.ChromeVoxAccessibilityApiHandler.earconsManager;
|
| + earcons.playEarcon(cvox.AbstractEarcons.OBJECT_OPEN);
|
| + });
|
| +
|
| + chrome.experimental.accessibility.onWindowClosed.addListener(function(win) {
|
| + var tts = cvox.ChromeVoxAccessibilityApiHandler.ttsManager;
|
| + tts.speak(win.name + ', window closed.', 0, {});
|
| + var earcons = cvox.ChromeVoxAccessibilityApiHandler.earconsManager;
|
| + earcons.playEarcon(cvox.AbstractEarcons.OBJECT_CLOSE);
|
| + });
|
| +
|
| + chrome.experimental.accessibility.onMenuOpened.addListener(function(menu) {
|
| + var tts = cvox.ChromeVoxAccessibilityApiHandler.ttsManager;
|
| + tts.speak(menu.name + ', menu opened.', 0, {});
|
| + var earcons = cvox.ChromeVoxAccessibilityApiHandler.earconsManager;
|
| + earcons.playEarcon(cvox.AbstractEarcons.OBJECT_OPEN);
|
| + });
|
| +
|
| + chrome.experimental.accessibility.onMenuClosed.addListener(function(menu) {
|
| + var tts = cvox.ChromeVoxAccessibilityApiHandler.ttsManager;
|
| + tts.speak(menu.name + ', menu closed.', 0, {});
|
| + var earcons = cvox.ChromeVoxAccessibilityApiHandler.earconsManager;
|
| + earcons.playEarcon(cvox.AbstractEarcons.OBJECT_CLOSE);
|
| + });
|
| +
|
| + chrome.experimental.accessibility.onControlFocused.addListener(
|
| + /**
|
| + * @param {AccessibilityObject} ctl The focused control.
|
| + */
|
| + function(ctl) {
|
| + var tts = cvox.ChromeVoxAccessibilityApiHandler.ttsManager;
|
| + if (ctl.type == 'textbox') {
|
| + cvox.ChromeVoxAccessibilityApiHandler.trimWhitespace(ctl);
|
| + cvox.ChromeVoxAccessibilityApiHandler.editableTextHandler =
|
| + new cvox.ChromeVoxEditableTextBase(
|
| + ctl.details.value,
|
| + ctl.details.selectionStart,
|
| + ctl.details.selectionEnd,
|
| + tts);
|
| + } else {
|
| + cvox.ChromeVoxAccessibilityApiHandler.editableTextHandler = null;
|
| + }
|
| +
|
| + var description = cvox.ChromeVoxAccessibilityApiHandler.describe(ctl,
|
| + false);
|
| + tts.speak(description.utterance, 0, {});
|
| + if (description.earcon) {
|
| + var earcons =
|
| + cvox.ChromeVoxAccessibilityApiHandler.earconsManager;
|
| + earcons.playEarcon(description.earcon);
|
| + }
|
| + });
|
| +
|
| + chrome.experimental.accessibility.onControlAction.addListener(function(ctl) {
|
| + var tts = cvox.ChromeVoxAccessibilityApiHandler.ttsManager;
|
| + var description = cvox.ChromeVoxAccessibilityApiHandler.describe(ctl,
|
| + true);
|
| + tts.speak(description.utterance, 0, {});
|
| + if (description.earcon) {
|
| + var earcons = cvox.ChromeVoxAccessibilityApiHandler.earconsManager;
|
| + earcons.playEarcon(description.earcon);
|
| + }
|
| + });
|
| +
|
| + chrome.experimental.accessibility.onTextChanged.addListener(function(ctl) {
|
| + if (cvox.ChromeVoxAccessibilityApiHandler.editableTextHandler) {
|
| + cvox.ChromeVoxAccessibilityApiHandler.trimWhitespace(ctl);
|
| + cvox.ChromeVoxAccessibilityApiHandler.editableTextHandler.changed(
|
| + ctl.details.value,
|
| + ctl.details.selectionStart,
|
| + ctl.details.selectionEnd);
|
| + }
|
| + });
|
| +};
|
| +
|
| +/**
|
| + * Given a text control received from the accessibility api, trim any
|
| + * leading or trailing whitespace from control.details.value and from
|
| + * selectionStart and selectionEnd.
|
| + * @param {Object} control The text control object.
|
| + */
|
| +cvox.ChromeVoxAccessibilityApiHandler.trimWhitespace = function(control) {
|
| + var d = control.details;
|
| + var prefix = new RegExp(/^[\s\u200b]+/).exec(d.value);
|
| + var suffix = new RegExp(/[\s\u200b]+$/).exec(d.value);
|
| + var prefixLen = prefix ? prefix.length : 0;
|
| + var suffixLen = suffix ? suffix.length : 0;
|
| + d.value = d.value.substr(prefix, d.value.length - prefixLen - suffixLen);
|
| + d.selectionStart -= prefixLen;
|
| + d.selectionEnd -= prefixLen;
|
| + if (d.selectionEnd > d.value.length) {
|
| + d.selectionEnd = d.value.length;
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * Given a control received from the accessibility api, determine an
|
| + * utterance to speak and an earcon to play to describe it.
|
| + * @param {Object} control The control that had an action performed on it.
|
| + * @param {boolean} isSelect True if the action is a select action,
|
| + * otherwise it's a focus action.
|
| + * @return {Object} An object containing a string field |utterance| and
|
| + * earcon |earcon|.
|
| + */
|
| +cvox.ChromeVoxAccessibilityApiHandler.describe = function(control,
|
| + isSelect) {
|
| + var s = '';
|
| + var earcon = undefined;
|
| + var name = control.name.replace(/[_&]+/g, '').replace('...', '');
|
| + switch (control.type) {
|
| + case 'checkbox':
|
| + s += name;
|
| + if (control.details.isChecked) {
|
| + earcon = cvox.AbstractEarcons.CHECK_ON;
|
| + s += ', checkbox checked';
|
| + } else {
|
| + earcon = cvox.AbstractEarcons.CHECK_OFF;
|
| + s += ', checkbox not checked';
|
| + }
|
| + break;
|
| + case 'radiobutton':
|
| + s += name;
|
| + if (control.details.isChecked) {
|
| + earcon = cvox.AbstractEarcons.CHECK_ON;
|
| + s += ', radio button selected';
|
| + } else {
|
| + earcon = cvox.AbstractEarcons.CHECK_OFF;
|
| + s += ', radio button unselected';
|
| + }
|
| + break;
|
| + case 'menu':
|
| + s += name + ', menu';
|
| + break;
|
| + case 'menuitem':
|
| + s += name + ', menu item';
|
| + if (control.details.hasSubmenu) {
|
| + s += ', with submenu';
|
| + }
|
| + break;
|
| + case 'window':
|
| + s += name + ', window';
|
| + break;
|
| + case 'textbox':
|
| + earcon = cvox.AbstractEarcons.EDITABLE_TEXT;
|
| + s += control.details.value;
|
| + if (name != '') {
|
| + s += ', ' + name;
|
| + }
|
| + s += ', text box';
|
| + break;
|
| + case 'button':
|
| + earcon = cvox.AbstractEarcons.BUTTON;
|
| + s += name + ', button';
|
| + break;
|
| + case 'combobox':
|
| + earcon = cvox.AbstractEarcons.LISTBOX;
|
| + s += control.details.value;
|
| + if (name != '') {
|
| + s += ', ' + name;
|
| + }
|
| + s += ', combo box';
|
| + break;
|
| + case 'listbox':
|
| + earcon = cvox.AbstractEarcons.LISTBOX;
|
| + s += control.details.value;
|
| + if (name != '') {
|
| + s += ', ' + name;
|
| + }
|
| + s += ', list box';
|
| + break;
|
| + case 'link':
|
| + earcon = cvox.AbstractEarcons.LINK;
|
| + s += name + ', link';
|
| + break;
|
| + case 'tab':
|
| + s += name + ', tab';
|
| + break;
|
| +
|
| + default:
|
| + s += name + ', ' + control.type;
|
| + }
|
| +
|
| + if (isSelect) {
|
| + s += ', selected';
|
| + }
|
| + try {
|
| + if (control.details.itemCount >= 0) {
|
| + s += ', ' + (control.details.itemIndex + 1) +
|
| + ' of ' + control.details.itemCount;
|
| + }
|
| + } catch (err) {
|
| + }
|
| +
|
| + s += '.';
|
| +
|
| + var description = {};
|
| + description.utterance = s;
|
| + description.earcon = earcon;
|
| + return description;
|
| +};
|
|
|
| Property changes on: chrome/browser/resources/access_chromevox/chromevox/background/accessibility_api_handler.js
|
| ___________________________________________________________________
|
| Added: svn:executable
|
| + *
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|