зеркало из https://github.com/mozilla/gecko-dev.git
Bug 886075 - Should be able to move caret with braille. r=eeejay r=kats
This commit is contained in:
Родитель
43d297b457
Коммит
004fdc5faf
|
@ -269,7 +269,7 @@ this.AccessFu = {
|
|||
this.Input.moveCursor('movePrevious', 'Simple', 'gesture');
|
||||
break;
|
||||
case 'Accessibility:ActivateObject':
|
||||
this.Input.activateCurrent();
|
||||
this.Input.activateCurrent(JSON.parse(aData));
|
||||
break;
|
||||
case 'Accessibility:Focus':
|
||||
this._focused = JSON.parse(aData);
|
||||
|
@ -465,6 +465,13 @@ var Output = {
|
|||
androidEvent.type = 'Accessibility:Event';
|
||||
if (androidEvent.bounds)
|
||||
androidEvent.bounds = this._adjustBounds(androidEvent.bounds, aBrowser);
|
||||
if (androidEvent.brailleText && 'output' in androidEvent.brailleText) {
|
||||
this.brailleStartOffset = androidEvent.brailleText.startOffset;
|
||||
this.brailleEndOffset = androidEvent.brailleText.endOffset;
|
||||
// We need to append a space at the end so that the routing key corresponding
|
||||
// to the end of the output (i.e. the space) can be hit to move the caret there.
|
||||
androidEvent.brailleText = androidEvent.brailleText.output + ' ';
|
||||
}
|
||||
this._bridge.handleGeckoMessage(JSON.stringify(androidEvent));
|
||||
}
|
||||
},
|
||||
|
@ -684,9 +691,11 @@ var Input = {
|
|||
mm.sendAsyncMessage('AccessFu:MoveCaret', aDetails);
|
||||
},
|
||||
|
||||
activateCurrent: function activateCurrent() {
|
||||
activateCurrent: function activateCurrent(aData) {
|
||||
let mm = Utils.getMessageManager(Utils.CurrentBrowser);
|
||||
mm.sendAsyncMessage('AccessFu:Activate', {});
|
||||
let offset = aData && typeof aData.keyIndex === 'number' ?
|
||||
aData.keyIndex - Output.brailleStartOffset : -1;
|
||||
mm.sendAsyncMessage('AccessFu:Activate', {offset: offset});
|
||||
},
|
||||
|
||||
sendContextMenuMessage: function sendContextMenuMessage() {
|
||||
|
|
|
@ -47,9 +47,12 @@ this.OutputGenerator = {
|
|||
* @param {PivotContext} aContext object that generates and caches
|
||||
* context information for a given accessible and its relationship with
|
||||
* another accessible.
|
||||
* @return {Array} An array of strings. Depending on the utterance order,
|
||||
* @return {Object} An object that neccessarily has an output property which
|
||||
* is an array of strings. Depending on the utterance order,
|
||||
* the strings describe the context for an accessible object either
|
||||
* starting from the accessible's ancestry or accessible's subtree.
|
||||
* The object may also have properties specific to the type of output
|
||||
* generated.
|
||||
*/
|
||||
genForContext: function genForContext(aContext) {
|
||||
let output = [];
|
||||
|
@ -65,8 +68,7 @@ this.OutputGenerator = {
|
|||
return (nameRule & NAME_FROM_SUBTREE_RULE) &&
|
||||
(Utils.getAttributes(aAccessible)['explicit-name'] === 'true');
|
||||
};
|
||||
let outputOrder = typeof gUtteranceOrder.value == 'number' ?
|
||||
gUtteranceOrder.value : this.defaultOutputOrder;
|
||||
let outputOrder = this._getOutputOrder();
|
||||
let contextStart = this._getContextStart(aContext);
|
||||
|
||||
if (outputOrder === OUTPUT_DESC_FIRST) {
|
||||
|
@ -84,7 +86,7 @@ this.OutputGenerator = {
|
|||
// Clean up the white space.
|
||||
let trimmed;
|
||||
output = [trimmed for (word of output) if (trimmed = word.trim())];
|
||||
return output;
|
||||
return {output: output};
|
||||
},
|
||||
|
||||
|
||||
|
@ -164,8 +166,7 @@ this.OutputGenerator = {
|
|||
}
|
||||
|
||||
if (name) {
|
||||
let outputOrder = typeof gUtteranceOrder.value == 'number' ?
|
||||
gUtteranceOrder.value : this.defaultOutputOrder;
|
||||
let outputOrder = this._getOutputOrder();
|
||||
aOutput[outputOrder === OUTPUT_DESC_FIRST ?
|
||||
'push' : 'unshift'](name);
|
||||
}
|
||||
|
@ -185,6 +186,11 @@ this.OutputGenerator = {
|
|||
return str.replace('#1', aCount);
|
||||
},
|
||||
|
||||
_getOutputOrder: function _getOutputOrder() {
|
||||
return typeof gUtteranceOrder.value === 'number' ?
|
||||
gUtteranceOrder.value : this.defaultOutputOrder;
|
||||
},
|
||||
|
||||
roleRuleMap: {
|
||||
'menubar': INCLUDE_DESC,
|
||||
'scrollbar': INCLUDE_DESC,
|
||||
|
@ -562,6 +568,20 @@ this.BrailleGenerator = {
|
|||
|
||||
defaultOutputOrder: OUTPUT_DESC_LAST,
|
||||
|
||||
genForContext: function genForContext(aContext) {
|
||||
let output = OutputGenerator.genForContext.apply(this, arguments);
|
||||
let outputOrder = this._getOutputOrder();
|
||||
|
||||
let acc = aContext.accessible;
|
||||
if (acc instanceof Ci.nsIAccessibleText) {
|
||||
output.endOffset = outputOrder === OUTPUT_DESC_FIRST ?
|
||||
output.output.join(' ').length : acc.characterCount;
|
||||
output.startOffset = output.endOffset - acc.characterCount;
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
objectOutputFunctions: {
|
||||
|
||||
__proto__: OutputGenerator.objectOutputFunctions,
|
||||
|
|
|
@ -240,12 +240,12 @@ AndroidPresenter.prototype = {
|
|||
this._braillePresenter = new BraillePresenter();
|
||||
}
|
||||
brailleText = this._braillePresenter.pivotChanged(aContext, aReason).
|
||||
details.text;
|
||||
details;
|
||||
}
|
||||
|
||||
androidEvents.push({eventType: (isExploreByTouch) ?
|
||||
this.ANDROID_VIEW_HOVER_ENTER : focusEventType,
|
||||
text: UtteranceGenerator.genForContext(aContext),
|
||||
text: UtteranceGenerator.genForContext(aContext).output,
|
||||
bounds: aContext.bounds,
|
||||
clickable: aContext.accessible.actionCount > 0,
|
||||
checkable: !!(state &
|
||||
|
@ -397,7 +397,7 @@ SpeechPresenter.prototype = {
|
|||
actions: [
|
||||
{method: 'playEarcon', data: 'tick', options: {}},
|
||||
{method: 'speak',
|
||||
data: UtteranceGenerator.genForContext(aContext).join(' '),
|
||||
data: UtteranceGenerator.genForContext(aContext).output.join(' '),
|
||||
options: {enqueue: true}}
|
||||
]
|
||||
}
|
||||
|
@ -452,9 +452,10 @@ BraillePresenter.prototype = {
|
|||
return null;
|
||||
}
|
||||
|
||||
let text = BrailleGenerator.genForContext(aContext);
|
||||
let brailleOutput = BrailleGenerator.genForContext(aContext);
|
||||
brailleOutput.output = brailleOutput.output.join(' ');
|
||||
|
||||
return { type: this.type, details: {text: text.join(' ')} };
|
||||
return { type: this.type, details: brailleOutput };
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
let Ci = Components.interfaces;
|
||||
let Cu = Components.utils;
|
||||
|
||||
const ROLE_ENTRY = Ci.nsIAccessibleRole.ROLE_ENTRY;
|
||||
const ROLE_INTERNAL_FRAME = Ci.nsIAccessibleRole.ROLE_INTERNAL_FRAME;
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
|
@ -155,6 +156,24 @@ function activateCurrent(aMessage) {
|
|||
}
|
||||
}
|
||||
|
||||
function moveCaretTo(aAccessible, aOffset) {
|
||||
let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
|
||||
let oldOffset = accText.caretOffset;
|
||||
let text = accText.getText(0, accText.characterCount);
|
||||
|
||||
if (aOffset >= 0 && aOffset <= accText.characterCount) {
|
||||
accText.caretOffset = aOffset;
|
||||
}
|
||||
|
||||
presentCaretChange(text, oldOffset, accText.caretOffset);
|
||||
}
|
||||
|
||||
let focusedAcc = Utils.AccRetrieval.getAccessibleFor(content.document.activeElement);
|
||||
if (focusedAcc && focusedAcc.role === ROLE_ENTRY) {
|
||||
moveCaretTo(focusedAcc, aMessage.json.offset);
|
||||
return;
|
||||
}
|
||||
|
||||
let vc = Utils.getVirtualCursor(content.document);
|
||||
if (!forwardMessage(vc, aMessage))
|
||||
activateAccessible(vc.position);
|
||||
|
@ -218,10 +237,13 @@ function moveCaret(aMessage) {
|
|||
}
|
||||
}
|
||||
|
||||
let newOffset = accText.caretOffset;
|
||||
if (oldOffset !== newOffset) {
|
||||
let msg = Presentation.textSelectionChanged(text, newOffset, newOffset,
|
||||
oldOffset, oldOffset);
|
||||
presentCaretChange(text, oldOffset, accText.caretOffset);
|
||||
}
|
||||
|
||||
function presentCaretChange(aText, aOldOffset, aNewOffset) {
|
||||
if (aOldOffset !== aNewOffset) {
|
||||
let msg = Presentation.textSelectionChanged(aText, aNewOffset, aNewOffset,
|
||||
aOldOffset, aOldOffset);
|
||||
sendAsyncMessage('AccessFu:Present', msg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@ function testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aGenerator
|
|||
var accessible = getAccessible(aAccOrElmOrID);
|
||||
var oldAccessible = getAccessible(aOldAccOrElmOrID);
|
||||
var context = new PivotContext(accessible, oldAccessible);
|
||||
var output = aGenerator.genForContext(context);
|
||||
var output = aGenerator.genForContext(context).output;
|
||||
|
||||
isDeeply(output, expected,
|
||||
"Context output is correct for " + aAccOrElmOrID);
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ public class GeckoAccessibility {
|
|||
private static JSONObject sEventMessage = null;
|
||||
private static AccessibilityNodeInfo sVirtualCursorNode = null;
|
||||
|
||||
// This is the number Brailleback uses to start indexing routing keys.
|
||||
private static final int BRAILLE_CLICK_BASE_INDEX = -275000000;
|
||||
private static SelfBrailleClient sSelfBrailleClient = null;
|
||||
|
||||
private static final HashSet<String> sServiceWhitelist =
|
||||
|
@ -339,11 +341,19 @@ public class GeckoAccessibility {
|
|||
return true;
|
||||
} else if (action == AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY &&
|
||||
virtualViewId == VIRTUAL_CURSOR_POSITION) {
|
||||
// XXX: Self brailling gives this action with a bogus argument instead of an actual click action
|
||||
// XXX: Self brailling gives this action with a bogus argument instead of an actual click action;
|
||||
// the argument value is the BRAILLE_CLICK_BASE_INDEX - the index of the routing key that was hit
|
||||
int granularity = arguments.getInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT);
|
||||
if (granularity < 0) {
|
||||
int keyIndex = BRAILLE_CLICK_BASE_INDEX - granularity;
|
||||
JSONObject activationData = new JSONObject();
|
||||
try {
|
||||
activationData.put("keyIndex", keyIndex);
|
||||
} catch (JSONException e) {
|
||||
return true;
|
||||
}
|
||||
GeckoAppShell.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ActivateObject", null));
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ActivateObject", activationData.toString()));
|
||||
} else {
|
||||
JSONObject movementData = new JSONObject();
|
||||
try {
|
||||
|
|
Загрузка…
Ссылка в новой задаче