mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 785852 - Support editing mode navigation in Jelly Bean. r=eeejay r=kats
This commit is contained in:
parent
d8deaa0bf9
commit
a7dbb70ce3
@ -116,6 +116,7 @@ this.AccessFu = {
|
||||
Services.obs.addObserver(this, 'Accessibility:PreviousObject', false);
|
||||
Services.obs.addObserver(this, 'Accessibility:Focus', false);
|
||||
Services.obs.addObserver(this, 'Accessibility:ActivateObject', false);
|
||||
Services.obs.addObserver(this, 'Accessibility:MoveCaret', false);
|
||||
Utils.win.addEventListener('TabOpen', this);
|
||||
Utils.win.addEventListener('TabClose', this);
|
||||
Utils.win.addEventListener('TabSelect', this);
|
||||
@ -158,6 +159,7 @@ this.AccessFu = {
|
||||
Services.obs.removeObserver(this, 'Accessibility:PreviousObject');
|
||||
Services.obs.removeObserver(this, 'Accessibility:Focus');
|
||||
Services.obs.removeObserver(this, 'Accessibility:ActivateObject');
|
||||
Services.obs.removeObserver(this, 'Accessibility:MoveCaret');
|
||||
|
||||
if (this.doneCallback) {
|
||||
this.doneCallback();
|
||||
@ -277,6 +279,9 @@ this.AccessFu = {
|
||||
{action: 'whereIsIt', move: true});
|
||||
}
|
||||
break;
|
||||
case 'Accessibility:MoveCaret':
|
||||
this.Input.moveCaret(JSON.parse(aData));
|
||||
break;
|
||||
case 'remote-browser-frame-shown':
|
||||
case 'in-process-browser-or-app-frame-shown':
|
||||
{
|
||||
@ -667,6 +672,18 @@ var Input = {
|
||||
inputType: aInputType});
|
||||
},
|
||||
|
||||
moveCaret: function moveCaret(aDetails) {
|
||||
if (!this.editState.editing) {
|
||||
return;
|
||||
}
|
||||
|
||||
aDetails.atStart = this.editState.atStart;
|
||||
aDetails.atEnd = this.editState.atEnd;
|
||||
|
||||
let mm = Utils.getMessageManager(Utils.CurrentBrowser);
|
||||
mm.sendAsyncMessage('AccessFu:MoveCaret', aDetails);
|
||||
},
|
||||
|
||||
activateCurrent: function activateCurrent() {
|
||||
let mm = Utils.getMessageManager(Utils.CurrentBrowser);
|
||||
mm.sendAsyncMessage('AccessFu:Activate', {});
|
||||
|
@ -61,7 +61,7 @@ Presenter.prototype = {
|
||||
/**
|
||||
* Text selection has changed. TODO.
|
||||
*/
|
||||
textSelectionChanged: function textSelectionChanged() {},
|
||||
textSelectionChanged: function textSelectionChanged(aText, aStart, aEnd, aOldStart, aOldEnd) {},
|
||||
|
||||
/**
|
||||
* Selection has changed. TODO.
|
||||
@ -205,8 +205,10 @@ AndroidPresenter.prototype = {
|
||||
ANDROID_VIEW_HOVER_ENTER: 0x80,
|
||||
ANDROID_VIEW_HOVER_EXIT: 0x100,
|
||||
ANDROID_VIEW_SCROLLED: 0x1000,
|
||||
ANDROID_VIEW_TEXT_SELECTION_CHANGED: 0x2000,
|
||||
ANDROID_ANNOUNCEMENT: 0x4000,
|
||||
ANDROID_VIEW_ACCESSIBILITY_FOCUSED: 0x8000,
|
||||
ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000,
|
||||
|
||||
pivotChanged: function AndroidPresenter_pivotChanged(aContext, aReason) {
|
||||
if (!aContext.accessible)
|
||||
@ -302,6 +304,37 @@ AndroidPresenter.prototype = {
|
||||
return {type: this.type, details: [eventDetails]};
|
||||
},
|
||||
|
||||
textSelectionChanged: function AndroidPresenter_textSelectionChanged(aText, aStart,
|
||||
aEnd, aOldStart,
|
||||
aOldEnd) {
|
||||
let androidEvents = [];
|
||||
|
||||
if (Utils.AndroidSdkVersion >= 14) {
|
||||
androidEvents.push({
|
||||
eventType: this.ANDROID_VIEW_TEXT_SELECTION_CHANGED,
|
||||
text: [aText],
|
||||
fromIndex: aStart,
|
||||
toIndex: aEnd,
|
||||
itemCount: aText.length
|
||||
});
|
||||
}
|
||||
|
||||
if (Utils.AndroidSdkVersion >= 16) {
|
||||
let [from, to] = aOldStart < aStart ? [aOldStart, aStart] : [aStart, aOldStart];
|
||||
androidEvents.push({
|
||||
eventType: this.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
|
||||
text: [aText],
|
||||
fromIndex: from,
|
||||
toIndex: to
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: this.type,
|
||||
details: androidEvents
|
||||
};
|
||||
},
|
||||
|
||||
viewportChanged: function AndroidPresenter_viewportChanged(aWindow) {
|
||||
if (Utils.AndroidSdkVersion < 14)
|
||||
return null;
|
||||
@ -445,6 +478,11 @@ this.Presentation = {
|
||||
for each (p in this.presenters)];
|
||||
},
|
||||
|
||||
textSelectionChanged: function textSelectionChanged(aText, aStart, aEnd, aOldStart, aOldEnd) {
|
||||
return [p.textSelectionChanged(aText, aStart, aEnd, aOldStart, aOldEnd)
|
||||
for each (p in this.presenters)];
|
||||
},
|
||||
|
||||
tabStateChanged: function Presentation_tabStateChanged(aDocObj, aPageState) {
|
||||
return [p.tabStateChanged(aDocObj, aPageState)
|
||||
for each (p in this.presenters)];
|
||||
|
@ -172,6 +172,58 @@ function activateContextMenu(aMessage) {
|
||||
sendContextMenuCoordinates(vc.position);
|
||||
}
|
||||
|
||||
function moveCaret(aMessage) {
|
||||
const MOVEMENT_GRANULARITY_CHARACTER = 1;
|
||||
const MOVEMENT_GRANULARITY_WORD = 2;
|
||||
const MOVEMENT_GRANULARITY_PARAGRAPH = 8;
|
||||
|
||||
let direction = aMessage.json.direction;
|
||||
let granularity = aMessage.json.granularity;
|
||||
let accessible = Utils.getVirtualCursor(content.document).position;
|
||||
let accText = accessible.QueryInterface(Ci.nsIAccessibleText);
|
||||
let oldOffset = accText.caretOffset;
|
||||
let text = accText.getText(0, accText.characterCount);
|
||||
|
||||
let start = {}, end = {};
|
||||
if (direction === 'Previous' && !aMessage.json.atStart) {
|
||||
switch (granularity) {
|
||||
case MOVEMENT_GRANULARITY_CHARACTER:
|
||||
accText.caretOffset--;
|
||||
break;
|
||||
case MOVEMENT_GRANULARITY_WORD:
|
||||
accText.getTextBeforeOffset(accText.caretOffset,
|
||||
Ci.nsIAccessibleText.BOUNDARY_WORD_START, start, end);
|
||||
accText.caretOffset = end.value === accText.caretOffset ? start.value : end.value;
|
||||
break;
|
||||
case MOVEMENT_GRANULARITY_PARAGRAPH:
|
||||
let startOfParagraph = text.lastIndexOf('\n', accText.caretOffset - 1);
|
||||
accText.caretOffset = startOfParagraph !== -1 ? startOfParagraph : 0;
|
||||
break;
|
||||
}
|
||||
} else if (direction === 'Next' && !aMessage.json.atEnd) {
|
||||
switch (granularity) {
|
||||
case MOVEMENT_GRANULARITY_CHARACTER:
|
||||
accText.caretOffset++;
|
||||
break;
|
||||
case MOVEMENT_GRANULARITY_WORD:
|
||||
accText.getTextAtOffset(accText.caretOffset,
|
||||
Ci.nsIAccessibleText.BOUNDARY_WORD_END, start, end);
|
||||
accText.caretOffset = end.value;
|
||||
break;
|
||||
case MOVEMENT_GRANULARITY_PARAGRAPH:
|
||||
accText.caretOffset = text.indexOf('\n', accText.caretOffset + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let newOffset = accText.caretOffset;
|
||||
if (oldOffset !== newOffset) {
|
||||
let msg = Presentation.textSelectionChanged(text, newOffset, newOffset,
|
||||
oldOffset, oldOffset);
|
||||
sendAsyncMessage('AccessFu:Present', msg);
|
||||
}
|
||||
}
|
||||
|
||||
function scroll(aMessage) {
|
||||
let vc = Utils.getVirtualCursor(content.document);
|
||||
|
||||
@ -262,6 +314,7 @@ addMessageListener(
|
||||
addMessageListener('AccessFu:Activate', activateCurrent);
|
||||
addMessageListener('AccessFu:ContextMenu', activateContextMenu);
|
||||
addMessageListener('AccessFu:Scroll', scroll);
|
||||
addMessageListener('AccessFu:MoveCaret', moveCaret);
|
||||
|
||||
if (!eventManager) {
|
||||
eventManager = new EventManager(this);
|
||||
@ -278,6 +331,7 @@ addMessageListener(
|
||||
removeMessageListener('AccessFu:Activate', activateCurrent);
|
||||
removeMessageListener('AccessFu:ContextMenu', activateContextMenu);
|
||||
removeMessageListener('AccessFu:Scroll', scroll);
|
||||
removeMessageListener('AccessFu:MoveCaret', moveCaret);
|
||||
|
||||
eventManager.stop();
|
||||
});
|
||||
|
@ -10,6 +10,7 @@ import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.util.UiAsyncTask;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
@ -286,7 +287,6 @@ public class GeckoAccessibility {
|
||||
AccessibilityNodeInfo.obtain(sVirtualCursorNode) :
|
||||
AccessibilityNodeInfo.obtain(host, virtualDescendantId);
|
||||
|
||||
|
||||
switch (virtualDescendantId) {
|
||||
case View.NO_ID:
|
||||
// This is the parent LayerView node, populate it with children.
|
||||
@ -304,6 +304,11 @@ public class GeckoAccessibility {
|
||||
info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
|
||||
info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
|
||||
info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
|
||||
info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
|
||||
info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
|
||||
info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER |
|
||||
AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD |
|
||||
AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
|
||||
break;
|
||||
}
|
||||
return info;
|
||||
@ -332,10 +337,36 @@ public class GeckoAccessibility {
|
||||
GeckoAppShell.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ActivateObject", null));
|
||||
return true;
|
||||
} else if (action == AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY && virtualViewId == VIRTUAL_CURSOR_POSITION) {
|
||||
} 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
|
||||
int granularity = arguments.getInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT);
|
||||
if (granularity < 0) {
|
||||
GeckoAppShell.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ActivateObject", null));
|
||||
} else {
|
||||
JSONObject movementData = new JSONObject();
|
||||
try {
|
||||
movementData.put("direction", "Next");
|
||||
movementData.put("granularity", granularity);
|
||||
} catch (JSONException e) {
|
||||
return true;
|
||||
}
|
||||
GeckoAppShell.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:MoveCaret", movementData.toString()));
|
||||
}
|
||||
return true;
|
||||
} else if (action == AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY &&
|
||||
virtualViewId == VIRTUAL_CURSOR_POSITION) {
|
||||
JSONObject movementData = new JSONObject();
|
||||
try {
|
||||
movementData.put("direction", "Previous");
|
||||
movementData.put("granularity", arguments.getInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT));
|
||||
} catch (JSONException e) {
|
||||
return true;
|
||||
}
|
||||
GeckoAppShell.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ActivateObject", null));
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:MoveCaret", movementData.toString()));
|
||||
return true;
|
||||
}
|
||||
return host.performAccessibilityAction(action, arguments);
|
||||
|
Loading…
Reference in New Issue
Block a user