зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1011886 - [AccessFu] Introduce key echo by character, word, and character and word. r=eeejay
This commit is contained in:
Родитель
d5a8f0d7ec
Коммит
1c013f94e5
|
@ -402,10 +402,11 @@ this.EventManager.prototype = {
|
||||||
// If there are embedded objects in the text, ignore them.
|
// If there are embedded objects in the text, ignore them.
|
||||||
// Assuming changes to the descendants would already be handled by the
|
// Assuming changes to the descendants would already be handled by the
|
||||||
// show/hide event.
|
// show/hide event.
|
||||||
let modifiedText = event.modifiedText.replace(/\uFFFC/g, '').trim();
|
let modifiedText = event.modifiedText.replace(/\uFFFC/g, '');
|
||||||
if (!modifiedText) {
|
if (modifiedText != event.modifiedText && !modifiedText.trim()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aLiveRegion) {
|
if (aLiveRegion) {
|
||||||
if (aEvent.eventType === Events.TEXT_REMOVED) {
|
if (aEvent.eventType === Events.TEXT_REMOVED) {
|
||||||
this._queueLiveEvent(Events.TEXT_REMOVED, aLiveRegion, aIsPolite,
|
this._queueLiveEvent(Events.TEXT_REMOVED, aLiveRegion, aIsPolite,
|
||||||
|
@ -416,8 +417,8 @@ this.EventManager.prototype = {
|
||||||
modifiedText));
|
modifiedText));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.present(Presentation.textChanged(isInserted, event.start,
|
this.present(Presentation.textChanged(aEvent.accessible, isInserted,
|
||||||
event.length, text, modifiedText));
|
event.start, event.length, text, modifiedText));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,7 @@
|
||||||
const {utils: Cu, interfaces: Ci} = Components;
|
const {utils: Cu, interfaces: Ci} = Components;
|
||||||
|
|
||||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, 'Utils', // jshint ignore:line
|
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
|
||||||
'resource://gre/modules/accessibility/Utils.jsm');
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, 'Logger', // jshint ignore:line
|
XPCOMUtils.defineLazyModuleGetter(this, 'Logger', // jshint ignore:line
|
||||||
'resource://gre/modules/accessibility/Utils.jsm');
|
'resource://gre/modules/accessibility/Utils.jsm');
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, 'PivotContext', // jshint ignore:line
|
XPCOMUtils.defineLazyModuleGetter(this, 'PivotContext', // jshint ignore:line
|
||||||
|
@ -60,8 +59,8 @@ Presenter.prototype = {
|
||||||
/**
|
/**
|
||||||
* Text has changed, either by the user or by the system. TODO.
|
* Text has changed, either by the user or by the system. TODO.
|
||||||
*/
|
*/
|
||||||
textChanged: function textChanged(aIsInserted, aStartOffset, aLength, aText, // jshint ignore:line
|
textChanged: function textChanged(aAccessible, aIsInserted, aStartOffset, // jshint ignore:line
|
||||||
aModifiedText) {}, // jshint ignore:line
|
aLength, aText, aModifiedText) {}, // jshint ignore:line
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Text selection has changed. TODO.
|
* Text selection has changed. TODO.
|
||||||
|
@ -344,7 +343,7 @@ AndroidPresenter.prototype.tabStateChanged =
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidPresenter.prototype.textChanged = function AndroidPresenter_textChanged(
|
AndroidPresenter.prototype.textChanged = function AndroidPresenter_textChanged(
|
||||||
aIsInserted, aStart, aLength, aText, aModifiedText) {
|
aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) {
|
||||||
let eventDetails = {
|
let eventDetails = {
|
||||||
eventType: this.ANDROID_VIEW_TEXT_CHANGED,
|
eventType: this.ANDROID_VIEW_TEXT_CHANGED,
|
||||||
text: [aText],
|
text: [aText],
|
||||||
|
@ -461,6 +460,13 @@ B2GPresenter.prototype = Object.create(Presenter.prototype);
|
||||||
|
|
||||||
B2GPresenter.prototype.type = 'B2G';
|
B2GPresenter.prototype.type = 'B2G';
|
||||||
|
|
||||||
|
B2GPresenter.prototype.keyboardEchoSetting =
|
||||||
|
new PrefCache('accessibility.accessfu.keyboard_echo');
|
||||||
|
B2GPresenter.prototype.NO_ECHO = 0;
|
||||||
|
B2GPresenter.prototype.CHARACTER_ECHO = 1;
|
||||||
|
B2GPresenter.prototype.WORD_ECHO = 2;
|
||||||
|
B2GPresenter.prototype.CHARACTER_AND_WORD_ECHO = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pattern used for haptic feedback.
|
* A pattern used for haptic feedback.
|
||||||
* @type {Array}
|
* @type {Array}
|
||||||
|
@ -497,6 +503,12 @@ B2GPresenter.prototype.pivotChanged =
|
||||||
|
|
||||||
B2GPresenter.prototype.valueChanged =
|
B2GPresenter.prototype.valueChanged =
|
||||||
function B2GPresenter_valueChanged(aAccessible) {
|
function B2GPresenter_valueChanged(aAccessible) {
|
||||||
|
|
||||||
|
// the editable value changes are handled in the text changed presenter
|
||||||
|
if (Utils.getState(aAccessible).contains(States.EDITABLE)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: this.type,
|
type: this.type,
|
||||||
details: {
|
details: {
|
||||||
|
@ -506,6 +518,42 @@ B2GPresenter.prototype.valueChanged =
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
B2GPresenter.prototype.textChanged = function B2GPresenter_textChanged(
|
||||||
|
aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) {
|
||||||
|
let echoSetting = this.keyboardEchoSetting.value;
|
||||||
|
let text = '';
|
||||||
|
|
||||||
|
if (echoSetting == this.CHARACTER_ECHO ||
|
||||||
|
echoSetting == this.CHARACTER_AND_WORD_ECHO) {
|
||||||
|
text = aModifiedText;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add word if word boundary is added
|
||||||
|
if ((echoSetting == this.WORD_ECHO ||
|
||||||
|
echoSetting == this.CHARACTER_AND_WORD_ECHO) &&
|
||||||
|
aIsInserted && aLength === 1) {
|
||||||
|
let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
|
||||||
|
let startBefore = {}, endBefore = {};
|
||||||
|
let startAfter = {}, endAfter = {};
|
||||||
|
accText.getTextBeforeOffset(aStart,
|
||||||
|
Ci.nsIAccessibleText.BOUNDARY_WORD_END, startBefore, endBefore);
|
||||||
|
let maybeWord = accText.getTextBeforeOffset(aStart + 1,
|
||||||
|
Ci.nsIAccessibleText.BOUNDARY_WORD_END, startAfter, endAfter);
|
||||||
|
if (endBefore.value !== endAfter.value) {
|
||||||
|
text += maybeWord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: this.type,
|
||||||
|
details: {
|
||||||
|
eventType: 'text-change',
|
||||||
|
data: text
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
B2GPresenter.prototype.actionInvoked =
|
B2GPresenter.prototype.actionInvoked =
|
||||||
function B2GPresenter_actionInvoked(aObject, aActionName) {
|
function B2GPresenter_actionInvoked(aObject, aActionName) {
|
||||||
return {
|
return {
|
||||||
|
@ -614,11 +662,11 @@ this.Presentation = { // jshint ignore:line
|
||||||
for each (p in this.presenters)]; // jshint ignore:line
|
for each (p in this.presenters)]; // jshint ignore:line
|
||||||
},
|
},
|
||||||
|
|
||||||
textChanged: function Presentation_textChanged(aIsInserted, aStartOffset,
|
textChanged: function Presentation_textChanged(aAccessible, aIsInserted,
|
||||||
aLength, aText,
|
aStartOffset, aLength, aText,
|
||||||
aModifiedText) {
|
aModifiedText) {
|
||||||
return [p.textChanged(aIsInserted, aStartOffset, aLength, aText, // jshint ignore:line
|
return [p.textChanged(aAccessible, aIsInserted, aStartOffset, aLength, // jshint ignore:line
|
||||||
aModifiedText) for each (p in this.presenters)]; // jshint ignore:line
|
aText, aModifiedText) for each (p in this.presenters)]; // jshint ignore:line
|
||||||
},
|
},
|
||||||
|
|
||||||
textSelectionChanged: function textSelectionChanged(aText, aStart, aEnd,
|
textSelectionChanged: function textSelectionChanged(aText, aStart, aEnd,
|
||||||
|
|
|
@ -626,6 +626,15 @@ function ExpectedValueChange(aValue, aOptions) {
|
||||||
|
|
||||||
ExpectedValueChange.prototype = Object.create(ExpectedPresent.prototype);
|
ExpectedValueChange.prototype = Object.create(ExpectedPresent.prototype);
|
||||||
|
|
||||||
|
function ExpectedTextChanged(aValue, aOptions) {
|
||||||
|
ExpectedPresent.call(this, {
|
||||||
|
eventType: 'text-change',
|
||||||
|
data: aValue
|
||||||
|
}, null, aOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpectedTextChanged.prototype = Object.create(ExpectedPresent.prototype);
|
||||||
|
|
||||||
function ExpectedEditState(aEditState, aOptions) {
|
function ExpectedEditState(aEditState, aOptions) {
|
||||||
ExpectedMessage.call(this, 'AccessFu:Input', aOptions);
|
ExpectedMessage.call(this, 'AccessFu:Input', aOptions);
|
||||||
this.json = aEditState;
|
this.json = aEditState;
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js">
|
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js">
|
||||||
</script>
|
</script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js">
|
||||||
|
</script>
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="chrome://mochikit/content/chrome-harness.js">
|
src="chrome://mochikit/content/chrome-harness.js">
|
||||||
</script>
|
</script>
|
||||||
|
@ -169,9 +172,98 @@
|
||||||
multiline: false,
|
multiline: false,
|
||||||
atStart: true,
|
atStart: true,
|
||||||
atEnd: false
|
atEnd: false
|
||||||
}, { focused: 'html' })]
|
}, { focused: 'html' })],
|
||||||
|
|
||||||
|
[ContentMessages.focusSelector('input'),
|
||||||
|
new ExpectedAnnouncement('editing'),
|
||||||
|
new ExpectedEditState({
|
||||||
|
editing: true,
|
||||||
|
multiline: false,
|
||||||
|
atStart: true,
|
||||||
|
atEnd: true
|
||||||
|
}),
|
||||||
|
new ExpectedCursorChange([{string: 'entry'}]),
|
||||||
|
new ExpectedTextSelectionChanged(0, 0)
|
||||||
|
],
|
||||||
|
[function() {
|
||||||
|
SpecialPowers.setIntPref(KEYBOARD_ECHO_SETTING, 3);
|
||||||
|
typeKey('a')();
|
||||||
|
},
|
||||||
|
new ExpectedTextChanged('a'),
|
||||||
|
new ExpectedTextSelectionChanged(1, 1),
|
||||||
|
],
|
||||||
|
[typeKey('b'),
|
||||||
|
new ExpectedTextChanged('b'),
|
||||||
|
new ExpectedTextSelectionChanged(2, 2),
|
||||||
|
],
|
||||||
|
[typeKey('c'),
|
||||||
|
new ExpectedTextChanged('c'),
|
||||||
|
new ExpectedTextSelectionChanged(3, 3),
|
||||||
|
],
|
||||||
|
[typeKey('d'),
|
||||||
|
new ExpectedTextChanged('d'),
|
||||||
|
new ExpectedTextSelectionChanged(4, 4),
|
||||||
|
],
|
||||||
|
[typeKey(' '),
|
||||||
|
new ExpectedTextChanged(' abcd'),
|
||||||
|
new ExpectedTextSelectionChanged(5, 5),
|
||||||
|
],
|
||||||
|
[typeKey('e'),
|
||||||
|
new ExpectedTextChanged('e'),
|
||||||
|
new ExpectedTextSelectionChanged(6, 6),
|
||||||
|
],
|
||||||
|
[function() {
|
||||||
|
SpecialPowers.setIntPref(KEYBOARD_ECHO_SETTING, 2);
|
||||||
|
typeKey('a')();
|
||||||
|
},
|
||||||
|
new ExpectedTextChanged(''),
|
||||||
|
new ExpectedTextSelectionChanged(7, 7),
|
||||||
|
],
|
||||||
|
[typeKey('d'),
|
||||||
|
new ExpectedTextChanged(''),
|
||||||
|
new ExpectedTextSelectionChanged(8, 8),
|
||||||
|
],
|
||||||
|
[typeKey(' '),
|
||||||
|
new ExpectedTextChanged(' ead'),
|
||||||
|
new ExpectedTextSelectionChanged(9, 9),
|
||||||
|
],
|
||||||
|
[function() {
|
||||||
|
SpecialPowers.setIntPref(KEYBOARD_ECHO_SETTING, 1);
|
||||||
|
typeKey('f')();
|
||||||
|
},
|
||||||
|
new ExpectedTextChanged('f'),
|
||||||
|
new ExpectedTextSelectionChanged(10, 10),
|
||||||
|
],
|
||||||
|
[typeKey('g'),
|
||||||
|
new ExpectedTextChanged('g'),
|
||||||
|
new ExpectedTextSelectionChanged(11, 11),
|
||||||
|
],
|
||||||
|
[typeKey(' '),
|
||||||
|
new ExpectedTextChanged(' '),
|
||||||
|
new ExpectedTextSelectionChanged(12, 12),
|
||||||
|
],
|
||||||
|
[function() {
|
||||||
|
SpecialPowers.setIntPref(KEYBOARD_ECHO_SETTING, 0);
|
||||||
|
typeKey('f')();
|
||||||
|
},
|
||||||
|
new ExpectedTextChanged(''),
|
||||||
|
new ExpectedTextSelectionChanged(13, 13),
|
||||||
|
],
|
||||||
|
[typeKey('g'),
|
||||||
|
new ExpectedTextChanged(''),
|
||||||
|
new ExpectedTextSelectionChanged(14, 14),
|
||||||
|
],
|
||||||
|
[typeKey(' '),
|
||||||
|
new ExpectedTextChanged(''),
|
||||||
|
new ExpectedTextSelectionChanged(15, 15),
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const KEYBOARD_ECHO_SETTING = 'accessibility.accessfu.keyboard_echo';
|
||||||
|
function typeKey(key) {
|
||||||
|
return function() { synthesizeKey(key, {}, currentTabWindow()); };
|
||||||
|
}
|
||||||
|
|
||||||
addA11yLoadEvent(function() {
|
addA11yLoadEvent(function() {
|
||||||
textTest.start(function () {
|
textTest.start(function () {
|
||||||
closeBrowserWindow();
|
closeBrowserWindow();
|
||||||
|
|
|
@ -797,6 +797,9 @@ pref("accessibility.accessfu.quicknav_index", 0);
|
||||||
pref("accessibility.accessfu.utterance", 1);
|
pref("accessibility.accessfu.utterance", 1);
|
||||||
// Whether to skip images with empty alt text
|
// Whether to skip images with empty alt text
|
||||||
pref("accessibility.accessfu.skip_empty_images", true);
|
pref("accessibility.accessfu.skip_empty_images", true);
|
||||||
|
// Setting to change the verbosity of entered text (0 - none, 1 - characters,
|
||||||
|
// 2 - words, 3 - both)
|
||||||
|
pref("accessibility.accessfu.keyboard_echo", 3);
|
||||||
|
|
||||||
// Enable hit-target fluffing
|
// Enable hit-target fluffing
|
||||||
pref("ui.touch.radius.enabled", true);
|
pref("ui.touch.radius.enabled", true);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче