Commit 323b3ec6 authored by Aaron Leventhal's avatar Aaron Leventhal Committed by Commit Bot

Normalize <select> focus events with other accessibility implementations

When a <select size=1> receives focus, a focus event should be fired on
the combobox/menupopupbutton object.

When the value changes in a collapsed state, only the value change event
should be fired, but not a focus or activedescendantchanged event.

When the value changes in an expanded state, then the focus and/or
activedescendantchanged events can be fired.

This fixes some strange behavior with NVDA when Alt+Down is used to open
the select.

Bug: 621510
Change-Id: I30fd744157ecbb5180d5c77f2713a73fa168397a
Reviewed-on: https://chromium-review.googlesource.com/1175034
Commit-Queue: Aaron Leventhal <aleventhal@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarNektarios Paisios <nektar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#583367}
parent c882c7cb
...@@ -500,11 +500,16 @@ BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendant( ...@@ -500,11 +500,16 @@ BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendant(
if (focus->GetRole() == ax::mojom::Role::kPopUpButton) { if (focus->GetRole() == ax::mojom::Role::kPopUpButton) {
BrowserAccessibility* child = focus->InternalGetChild(0); BrowserAccessibility* child = focus->InternalGetChild(0);
if (child && child->GetRole() == ax::mojom::Role::kMenuListPopup) { if (child && child->GetRole() == ax::mojom::Role::kMenuListPopup &&
!child->GetData().HasState(ax::mojom::State::kInvisible)) {
// The active descendant is found on the menu list popup, i.e. on the // The active descendant is found on the menu list popup, i.e. on the
// actual list and not on the button that opens it. // actual list and not on the button that opens it.
// If there is no active descendant, focus should stay on the button so // If there is no active descendant, focus should stay on the button so
// that Windows screen readers would enable their virtual cursor. // that Windows screen readers would enable their virtual cursor.
// Do not expose an activedescendant in a hidden/collapsed list, as
// screen readers expect the focus event to go to the button itself.
// Note that the AX hierarchy in this case is strange -- the active
// option is the only visible option, and is inside an invisible list.
if (child->GetIntAttribute(ax::mojom::IntAttribute::kActivedescendantId, if (child->GetIntAttribute(ax::mojom::IntAttribute::kActivedescendantId,
&active_descendant_id)) { &active_descendant_id)) {
active_descendant = child->manager()->GetFromID(active_descendant_id); active_descendant = child->manager()->GetFromID(active_descendant_id);
...@@ -512,7 +517,8 @@ BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendant( ...@@ -512,7 +517,8 @@ BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendant(
} }
} }
if (active_descendant) if (active_descendant &&
!active_descendant->GetData().HasState(ax::mojom::State::kInvisible))
return active_descendant; return active_descendant;
return focus; return focus;
......
...@@ -359,6 +359,11 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest, ...@@ -359,6 +359,11 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
RunEventTest(FILE_PATH_LITERAL("menulist-collapse.html")); RunEventTest(FILE_PATH_LITERAL("menulist-collapse.html"));
} }
IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
AccessibilityEventsMenuListCollapseNext) {
RunEventTest(FILE_PATH_LITERAL("menulist-collapse-next.html"));
}
// https://crbug.com/719030 // https://crbug.com/719030
IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest, IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
DISABLED_AccessibilityEventsMenuListExpand) { DISABLED_AccessibilityEventsMenuListExpand) {
......
EVENT_OBJECT_STATECHANGE on <option> role=ROLE_SYSTEM_LISTITEM name="Apple" FOCUSED,INVISIBLE,FOCUSABLE,SELECTABLE 1 of 3 EVENT_OBJECT_STATECHANGE on <option> role=ROLE_SYSTEM_LISTITEM name="Apple" INVISIBLE,FOCUSABLE,SELECTABLE 1 of 3
EVENT_OBJECT_VALUECHANGE on <select> role=ROLE_SYSTEM_COMBOBOX COLLAPSED,FOCUSABLE,HASPOPUP EVENT_OBJECT_VALUECHANGE on <select> role=ROLE_SYSTEM_COMBOBOX FOCUSED,COLLAPSED,FOCUSABLE,HASPOPUP
\ No newline at end of file \ No newline at end of file
EVENT_OBJECT_SELECTION on <option> role=ROLE_SYSTEM_LISTITEM name="Orange" SELECTED,FOCUSABLE,SELECTABLE 2 of 3
EVENT_OBJECT_STATECHANGE on <option> role=ROLE_SYSTEM_LISTITEM name="Apple" INVISIBLE,FOCUSABLE,SELECTABLE 1 of 3
EVENT_OBJECT_STATECHANGE on <option> role=ROLE_SYSTEM_LISTITEM name="Orange" SELECTED,FOCUSABLE,SELECTABLE 2 of 3
EVENT_OBJECT_VALUECHANGE on <select> role=ROLE_SYSTEM_COMBOBOX value="Orange" FOCUSED,COLLAPSED,FOCUSABLE,HASPOPUP
\ No newline at end of file
<!DOCTYPE html>
<html>
<body>
<select>
<option selected>Apple</option>
<option>Orange</option>
<option>Banana</option>
</select>
<script>
document.querySelector('select').focus();
function go() {
document.querySelector('select').selectedIndex = 1;
}
</script>
</body>
</html>
AXFocusedUIElementChanged on AXPopUpButton AXValue="Apple" AXFocusedUIElementChanged on AXPopUpButton AXValue="Apple"
\ No newline at end of file
EVENT_OBJECT_FOCUS on <select> role=ROLE_SYSTEM_COMBOBOX value="Apple" FOCUSED,COLLAPSED,FOCUSABLE,HASPOPUP EVENT_OBJECT_FOCUS on <select> role=ROLE_SYSTEM_COMBOBOX value="Apple" FOCUSED,COLLAPSED,FOCUSABLE,HASPOPUP
\ No newline at end of file
...@@ -221,8 +221,12 @@ void AXEventGenerator::OnIntAttributeChanged(AXTree* tree, ...@@ -221,8 +221,12 @@ void AXEventGenerator::OnIntAttributeChanged(AXTree* tree,
switch (attr) { switch (attr) {
case ax::mojom::IntAttribute::kActivedescendantId: case ax::mojom::IntAttribute::kActivedescendantId:
AddEvent(node, Event::ACTIVE_DESCENDANT_CHANGED); // Don't fire on invisible containers, as it confuses some screen readers,
active_descendant_changed_.push_back(node); // such as NVDA.
if (!node->data().HasState(ax::mojom::State::kInvisible)) {
AddEvent(node, Event::ACTIVE_DESCENDANT_CHANGED);
active_descendant_changed_.push_back(node);
}
break; break;
case ax::mojom::IntAttribute::kCheckedState: case ax::mojom::IntAttribute::kCheckedState:
AddEvent(node, Event::CHECKED_STATE_CHANGED); AddEvent(node, Event::CHECKED_STATE_CHANGED);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment