Bug 886075 - Should be able to move caret with braille. r=eeejay r=kats

This commit is contained in:
Max Li 2013-07-03 18:20:11 -04:00
Родитель 43d297b457
Коммит 004fdc5faf
6 изменённых файлов: 84 добавлений и 21 удалений

Просмотреть файл

@ -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 {