mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1182222 - Make Layerview support accessibility HTML navigation. r=yzen r=mfinkle
This commit is contained in:
parent
c2f13b2d03
commit
c5b2bc4dfb
@ -308,11 +308,15 @@ this.AccessFu = { // jshint ignore:line
|
||||
this._enableOrDisable();
|
||||
break;
|
||||
case 'Accessibility:NextObject':
|
||||
this.Input.moveCursor('moveNext', 'Simple', 'gesture');
|
||||
break;
|
||||
case 'Accessibility:PreviousObject':
|
||||
this.Input.moveCursor('movePrevious', 'Simple', 'gesture');
|
||||
{
|
||||
let rule = aData ?
|
||||
aData.substr(0, 1).toUpperCase() + aData.substr(1).toLowerCase() :
|
||||
'Simple';
|
||||
let method = aTopic.replace(/Accessibility:(\w+)Object/, 'move$1');
|
||||
this.Input.moveCursor(method, rule, 'gesture');
|
||||
break;
|
||||
}
|
||||
case 'Accessibility:ActivateObject':
|
||||
this.Input.activateCurrent(JSON.parse(aData));
|
||||
break;
|
||||
|
@ -35,14 +35,12 @@ import com.googlecode.eyesfree.braille.selfbraille.WriteData;
|
||||
public class GeckoAccessibility {
|
||||
private static final String LOGTAG = "GeckoAccessibility";
|
||||
private static final int VIRTUAL_ENTRY_POINT_BEFORE = 1;
|
||||
private static final int VIRTUAL_CURSOR_PREVIOUS = 2;
|
||||
private static final int VIRTUAL_CURSOR_POSITION = 3;
|
||||
private static final int VIRTUAL_CURSOR_NEXT = 4;
|
||||
private static final int VIRTUAL_ENTRY_POINT_AFTER = 5;
|
||||
private static final int VIRTUAL_CURSOR_POSITION = 2;
|
||||
private static final int VIRTUAL_ENTRY_POINT_AFTER = 3;
|
||||
|
||||
private static boolean sEnabled;
|
||||
// Used to store the JSON message and populate the event later in the code path.
|
||||
private static JSONObject sEventMessage;
|
||||
private static JSONObject sHoverEnter;
|
||||
private static AccessibilityNodeInfo sVirtualCursorNode;
|
||||
private static int sCurrentNode;
|
||||
|
||||
@ -158,6 +156,19 @@ public class GeckoAccessibility {
|
||||
if (!sEnabled)
|
||||
return;
|
||||
|
||||
final int eventType = message.optInt("eventType", -1);
|
||||
if (eventType < 0) {
|
||||
Log.e(LOGTAG, "No accessibility event type provided");
|
||||
return;
|
||||
}
|
||||
|
||||
sendAccessibilityEvent(message, eventType);
|
||||
}
|
||||
|
||||
public static void sendAccessibilityEvent (final JSONObject message, final int eventType) {
|
||||
if (!sEnabled)
|
||||
return;
|
||||
|
||||
final String exitView = message.optString("exitView");
|
||||
if (exitView.equals("moveNext")) {
|
||||
sCurrentNode = VIRTUAL_ENTRY_POINT_AFTER;
|
||||
@ -167,12 +178,6 @@ public class GeckoAccessibility {
|
||||
sCurrentNode = VIRTUAL_CURSOR_POSITION;
|
||||
}
|
||||
|
||||
final int eventType = message.optInt("eventType", -1);
|
||||
if (eventType < 0) {
|
||||
Log.e(LOGTAG, "No accessibility event type provided");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Versions.preJB) {
|
||||
// Before Jelly Bean we send events directly from here while spoofing the source by setting
|
||||
// the package and class name manually.
|
||||
@ -226,29 +231,24 @@ public class GeckoAccessibility {
|
||||
braille.optInt("selectionStart"), braille.optInt("selectionEnd"));
|
||||
}
|
||||
|
||||
if (eventType == AccessibilityEvent.TYPE_VIEW_HOVER_ENTER) {
|
||||
sHoverEnter = message;
|
||||
}
|
||||
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// If this is an accessibility focus, a lot of internal voodoo happens so we perform an
|
||||
// accessibility focus action on the view, and it in turn sends the right events.
|
||||
switch (eventType) {
|
||||
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
|
||||
sEventMessage = message;
|
||||
view.performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
|
||||
break;
|
||||
case AccessibilityEvent.TYPE_ANNOUNCEMENT:
|
||||
case AccessibilityEvent.TYPE_VIEW_SCROLLED:
|
||||
sEventMessage = null;
|
||||
final AccessibilityEvent accEvent = AccessibilityEvent.obtain(eventType);
|
||||
view.onInitializeAccessibilityEvent(accEvent);
|
||||
populateEventFromJSON(accEvent, message);
|
||||
view.getParent().requestSendAccessibilityEvent(view, accEvent);
|
||||
break;
|
||||
default:
|
||||
sEventMessage = message;
|
||||
view.sendAccessibilityEvent(eventType);
|
||||
break;
|
||||
final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
|
||||
event.setPackageName(GeckoAppShell.getContext().getPackageName());
|
||||
event.setClassName(GeckoAccessibility.class.getName());
|
||||
if (eventType == AccessibilityEvent.TYPE_ANNOUNCEMENT ||
|
||||
eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
|
||||
event.setSource(view, View.NO_ID);
|
||||
} else {
|
||||
event.setSource(view, VIRTUAL_CURSOR_POSITION);
|
||||
}
|
||||
populateEventFromJSON(event, message);
|
||||
view.requestSendAccessibilityEvent(view, event);
|
||||
}
|
||||
});
|
||||
|
||||
@ -296,28 +296,13 @@ public class GeckoAccessibility {
|
||||
public static class GeckoAccessibilityDelegate extends View.AccessibilityDelegate {
|
||||
AccessibilityNodeProvider mAccessibilityNodeProvider;
|
||||
|
||||
@Override
|
||||
public void onPopulateAccessibilityEvent (View host, AccessibilityEvent event) {
|
||||
super.onPopulateAccessibilityEvent(host, event);
|
||||
if (sEventMessage != null) {
|
||||
populateEventFromJSON(event, sEventMessage);
|
||||
event.setSource(host, sCurrentNode);
|
||||
}
|
||||
// We save the hover enter event so that we could reuse it for a subsequent accessibility focus event.
|
||||
if (event.getEventType() != AccessibilityEvent.TYPE_VIEW_HOVER_ENTER)
|
||||
sEventMessage = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessibilityNodeProvider getAccessibilityNodeProvider(final View host) {
|
||||
if (mAccessibilityNodeProvider == null)
|
||||
// The accessibility node structure for web content consists of 5 LayerView child nodes:
|
||||
// The accessibility node structure for web content consists of 3 LayerView child nodes:
|
||||
// 1. VIRTUAL_ENTRY_POINT_BEFORE: Represents the entry point before the LayerView.
|
||||
// 2. VIRTUAL_CURSOR_PREVIOUS: Represents the virtual cursor position that is previous to the
|
||||
// current one.
|
||||
// 3. VIRTUAL_CURSOR_POSITION: Represents the current position of the virtual cursor.
|
||||
// 4. VIRTUAL_CURSOR_NEXT: Represents the next virtual cursor position.
|
||||
// 5. VIRTUAL_ENTRY_POINT_AFTER: Represents the entry point after the LayerView.
|
||||
// 2. VIRTUAL_CURSOR_POSITION: Represents the current position of the virtual cursor.
|
||||
// 3. VIRTUAL_ENTRY_POINT_AFTER: Represents the entry point after the LayerView.
|
||||
mAccessibilityNodeProvider = new AccessibilityNodeProvider() {
|
||||
@Override
|
||||
public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualDescendantId) {
|
||||
@ -330,9 +315,7 @@ public class GeckoAccessibility {
|
||||
// This is the parent LayerView node, populate it with children.
|
||||
onInitializeAccessibilityNodeInfo(host, info);
|
||||
info.addChild(host, VIRTUAL_ENTRY_POINT_BEFORE);
|
||||
info.addChild(host, VIRTUAL_CURSOR_PREVIOUS);
|
||||
info.addChild(host, VIRTUAL_CURSOR_POSITION);
|
||||
info.addChild(host, VIRTUAL_CURSOR_NEXT);
|
||||
info.addChild(host, VIRTUAL_ENTRY_POINT_AFTER);
|
||||
break;
|
||||
default:
|
||||
@ -350,6 +333,8 @@ public class GeckoAccessibility {
|
||||
info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
|
||||
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
|
||||
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
|
||||
info.addAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT);
|
||||
info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT);
|
||||
info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER |
|
||||
AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD |
|
||||
AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
|
||||
@ -362,26 +347,14 @@ public class GeckoAccessibility {
|
||||
public boolean performAction (int virtualViewId, int action, Bundle arguments) {
|
||||
if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS) {
|
||||
// The accessibility focus is permanently on the middle node, VIRTUAL_CURSOR_POSITION.
|
||||
// When accessibility focus is requested on one of its siblings we move the virtual cursor
|
||||
// either forward or backward depending on which sibling was selected.
|
||||
// When we enter the view forward or backward we just ask Gecko to get focus, keeping the current position.
|
||||
|
||||
switch (virtualViewId) {
|
||||
case VIRTUAL_CURSOR_PREVIOUS:
|
||||
if (virtualViewId == VIRTUAL_CURSOR_POSITION && sHoverEnter != null) {
|
||||
GeckoAccessibility.sendAccessibilityEvent(sHoverEnter, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
|
||||
} else {
|
||||
GeckoAppShell.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:PreviousObject", null));
|
||||
return true;
|
||||
case VIRTUAL_CURSOR_NEXT:
|
||||
GeckoAppShell.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:NextObject", null));
|
||||
return true;
|
||||
case VIRTUAL_ENTRY_POINT_BEFORE:
|
||||
case VIRTUAL_ENTRY_POINT_AFTER:
|
||||
GeckoAppShell.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:Focus", "true"));
|
||||
default:
|
||||
break;
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:Focus", "true"));
|
||||
}
|
||||
return true;
|
||||
} else if (action == AccessibilityNodeInfo.ACTION_CLICK && virtualViewId == VIRTUAL_CURSOR_POSITION) {
|
||||
GeckoAppShell.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ActivateObject", null));
|
||||
@ -398,12 +371,28 @@ public class GeckoAccessibility {
|
||||
GeckoAppShell.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ScrollBackward", null));
|
||||
return true;
|
||||
} else if (action == AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT && virtualViewId == VIRTUAL_CURSOR_POSITION) {
|
||||
String traversalRule = "";
|
||||
if (arguments != null) {
|
||||
traversalRule = arguments.getString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING);
|
||||
}
|
||||
GeckoAppShell.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:NextObject", traversalRule));
|
||||
return true;
|
||||
} else if (action == AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT && virtualViewId == VIRTUAL_CURSOR_POSITION) {
|
||||
String traversalRule = "";
|
||||
if (arguments != null) {
|
||||
traversalRule = arguments.getString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING);
|
||||
}
|
||||
GeckoAppShell.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:PreviousObject", traversalRule));
|
||||
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;
|
||||
// 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) {
|
||||
if (granularity <= BRAILLE_CLICK_BASE_INDEX) {
|
||||
int keyIndex = BRAILLE_CLICK_BASE_INDEX - granularity;
|
||||
JSONObject activationData = new JSONObject();
|
||||
try {
|
||||
|
Loading…
Reference in New Issue
Block a user