| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/accessibility/platform/automation/automation_api_util.h" |
| #include "ui/accessibility/ax_enum_util.h" |
| #include "ui/accessibility/ax_event_generator.h" |
| #include "ui/accessibility/ax_position.h" |
| |
| namespace ui { |
| |
| bool ShouldIgnoreAXEventForAutomation(ax::mojom::Event event_type) { |
| // Important note: if you are getting here as a result of a compilation error |
| // while adding or removing enum values from ax::mojom::Event, please ensure |
| // you keep that enum in sync with EventType in |
| // extensions/common/api/automation.idl |
| // The stringified enum value gets mapped directly from one enum to another. |
| switch (event_type) { |
| // Generated by AXEventGenerator. This list have values we're interested |
| // from the intersection of AXEventGenerator::Event and |
| // ax::mojom::Event. |
| case ax::mojom::Event::kActiveDescendantChanged: |
| // TODO(crbug.com/1464633) Fully remove kAriaAttributeChangedDeprecated |
| // starting in 122, because although it was removed in 118, it is still |
| // present in earlier versions of LaCros. |
| case ax::mojom::Event::kAriaAttributeChangedDeprecated: |
| case ax::mojom::Event::kCheckedStateChanged: |
| case ax::mojom::Event::kChildrenChanged: |
| case ax::mojom::Event::kDocumentSelectionChanged: |
| case ax::mojom::Event::kDocumentTitleChanged: |
| case ax::mojom::Event::kExpandedChanged: |
| case ax::mojom::Event::kRowCollapsed: |
| case ax::mojom::Event::kRowCountChanged: |
| case ax::mojom::Event::kRowExpanded: |
| case ax::mojom::Event::kSelectedChildrenChanged: |
| return true; |
| |
| // All other ax events. |
| case ax::mojom::Event::kNone: |
| case ax::mojom::Event::kAlert: |
| case ax::mojom::Event::kAutocorrectionOccured: |
| case ax::mojom::Event::kBlur: |
| case ax::mojom::Event::kClicked: |
| case ax::mojom::Event::kControlsChanged: |
| case ax::mojom::Event::kEndOfTest: |
| case ax::mojom::Event::kFocus: |
| case ax::mojom::Event::kFocusAfterMenuClose: |
| case ax::mojom::Event::kFocusContext: |
| case ax::mojom::Event::kHide: |
| case ax::mojom::Event::kHitTestResult: |
| case ax::mojom::Event::kHover: |
| case ax::mojom::Event::kImageFrameUpdated: |
| case ax::mojom::Event::kLayoutComplete: |
| case ax::mojom::Event::kLiveRegionCreated: |
| case ax::mojom::Event::kLiveRegionChanged: |
| case ax::mojom::Event::kLoadComplete: |
| case ax::mojom::Event::kLoadStart: |
| case ax::mojom::Event::kLocationChanged: |
| case ax::mojom::Event::kMediaStartedPlaying: |
| case ax::mojom::Event::kMediaStoppedPlaying: |
| case ax::mojom::Event::kMenuEnd: |
| case ax::mojom::Event::kMenuListValueChangedDeprecated: |
| case ax::mojom::Event::kMenuPopupEnd: |
| case ax::mojom::Event::kMenuPopupStart: |
| case ax::mojom::Event::kMenuStart: |
| case ax::mojom::Event::kMouseCanceled: |
| case ax::mojom::Event::kMouseDragged: |
| case ax::mojom::Event::kMouseMoved: |
| case ax::mojom::Event::kMousePressed: |
| case ax::mojom::Event::kMouseReleased: |
| case ax::mojom::Event::kScrolledToAnchor: |
| case ax::mojom::Event::kScrollPositionChanged: |
| case ax::mojom::Event::kSelection: |
| case ax::mojom::Event::kSelectionAdd: |
| case ax::mojom::Event::kSelectionRemove: |
| case ax::mojom::Event::kShow: |
| case ax::mojom::Event::kStateChanged: |
| case ax::mojom::Event::kTextChanged: |
| case ax::mojom::Event::kWindowActivated: |
| case ax::mojom::Event::kWindowDeactivated: |
| case ax::mojom::Event::kWindowVisibilityChanged: |
| case ax::mojom::Event::kTextSelectionChanged: |
| case ax::mojom::Event::kTooltipClosed: |
| case ax::mojom::Event::kTooltipOpened: |
| case ax::mojom::Event::kTreeChanged: |
| case ax::mojom::Event::kValueChanged: |
| return false; |
| } |
| |
| NOTREACHED(); |
| } |
| |
| bool ShouldIgnoreGeneratedEventForAutomation( |
| AXEventGenerator::Event event_type) { |
| // Important note: if you are getting here as a result of a compilation error |
| // while adding or removing enum values from AXEventGenerator::Event, |
| // please ensure you keep that enum in sync with EventType in |
| // extensions/common/api/automation.idl |
| // The stringified enum value gets mapped directly from one enum to another. |
| switch (event_type) { |
| // These enum values should be mapped to automation.idl. |
| case AXEventGenerator::Event::ACCESS_KEY_CHANGED: |
| case AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED: |
| case AXEventGenerator::Event::ALERT: |
| case AXEventGenerator::Event::ARIA_CURRENT_CHANGED: |
| case AXEventGenerator::Event::ARIA_NOTIFICATIONS_POSTED: |
| case AXEventGenerator::Event::ATOMIC_CHANGED: |
| case AXEventGenerator::Event::AUTO_COMPLETE_CHANGED: |
| case AXEventGenerator::Event::AUTOFILL_AVAILABILITY_CHANGED: |
| case AXEventGenerator::Event::BUSY_CHANGED: |
| case AXEventGenerator::Event::CARET_BOUNDS_CHANGED: |
| case AXEventGenerator::Event::CHECKED_STATE_CHANGED: |
| case AXEventGenerator::Event::CHECKED_STATE_DESCRIPTION_CHANGED: |
| case AXEventGenerator::Event::CHILDREN_CHANGED: |
| case AXEventGenerator::Event::COLLAPSED: |
| case AXEventGenerator::Event::CONTROLS_CHANGED: |
| case AXEventGenerator::Event::DETAILS_CHANGED: |
| case AXEventGenerator::Event::DESCRIBED_BY_CHANGED: |
| case AXEventGenerator::Event::DESCRIPTION_CHANGED: |
| case AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: |
| case AXEventGenerator::Event::DOCUMENT_TITLE_CHANGED: |
| case AXEventGenerator::Event::EDITABLE_TEXT_CHANGED: |
| case AXEventGenerator::Event::ENABLED_CHANGED: |
| case AXEventGenerator::Event::EXPANDED: |
| case AXEventGenerator::Event::FOCUS_CHANGED: |
| case AXEventGenerator::Event::FLOW_FROM_CHANGED: |
| case AXEventGenerator::Event::FLOW_TO_CHANGED: |
| case AXEventGenerator::Event::HASPOPUP_CHANGED: |
| case AXEventGenerator::Event::HIERARCHICAL_LEVEL_CHANGED: |
| case AXEventGenerator::Event::IGNORED_CHANGED: |
| case AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED: |
| case AXEventGenerator::Event::INVALID_STATUS_CHANGED: |
| case AXEventGenerator::Event::KEY_SHORTCUTS_CHANGED: |
| case AXEventGenerator::Event::LABELED_BY_CHANGED: |
| case AXEventGenerator::Event::LANGUAGE_CHANGED: |
| case AXEventGenerator::Event::LAYOUT_INVALIDATED: |
| case AXEventGenerator::Event::LIVE_REGION_CHANGED: |
| case AXEventGenerator::Event::LIVE_REGION_CREATED: |
| case AXEventGenerator::Event::LIVE_REGION_NODE_CHANGED: |
| case AXEventGenerator::Event::LIVE_RELEVANT_CHANGED: |
| case AXEventGenerator::Event::LIVE_STATUS_CHANGED: |
| case AXEventGenerator::Event::MENU_POPUP_END: |
| case AXEventGenerator::Event::MENU_POPUP_START: |
| case AXEventGenerator::Event::MENU_ITEM_SELECTED: |
| case AXEventGenerator::Event::MULTILINE_STATE_CHANGED: |
| case AXEventGenerator::Event::MULTISELECTABLE_STATE_CHANGED: |
| case AXEventGenerator::Event::NAME_CHANGED: |
| case AXEventGenerator::Event::OBJECT_ATTRIBUTE_CHANGED: |
| case AXEventGenerator::Event::ORIENTATION_CHANGED: |
| case AXEventGenerator::Event::PARENT_CHANGED: |
| case AXEventGenerator::Event::PLACEHOLDER_CHANGED: |
| case AXEventGenerator::Event::POSITION_IN_SET_CHANGED: |
| case AXEventGenerator::Event::RELATED_NODE_CHANGED: |
| case AXEventGenerator::Event::READONLY_CHANGED: |
| case AXEventGenerator::Event::REQUIRED_STATE_CHANGED: |
| case AXEventGenerator::Event::ROLE_CHANGED: |
| case AXEventGenerator::Event::ROW_COUNT_CHANGED: |
| case AXEventGenerator::Event::SCROLL_HORIZONTAL_POSITION_CHANGED: |
| case AXEventGenerator::Event::SCROLL_VERTICAL_POSITION_CHANGED: |
| case AXEventGenerator::Event::SELECTED_CHANGED: |
| case AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED: |
| case AXEventGenerator::Event::SELECTED_VALUE_CHANGED: |
| case AXEventGenerator::Event::TEXT_SELECTION_CHANGED: |
| case AXEventGenerator::Event::SET_SIZE_CHANGED: |
| case AXEventGenerator::Event::SORT_CHANGED: |
| case AXEventGenerator::Event::STATE_CHANGED: |
| case AXEventGenerator::Event::SUBTREE_CREATED: |
| case AXEventGenerator::Event::TEXT_ATTRIBUTE_CHANGED: |
| case AXEventGenerator::Event::VALUE_IN_TEXT_FIELD_CHANGED: |
| case AXEventGenerator::Event::RANGE_VALUE_CHANGED: |
| case AXEventGenerator::Event::RANGE_VALUE_MAX_CHANGED: |
| case AXEventGenerator::Event::RANGE_VALUE_MIN_CHANGED: |
| case AXEventGenerator::Event::RANGE_VALUE_STEP_CHANGED: |
| return false; |
| |
| // These enum values can be ignored and should not be mapped. |
| case AXEventGenerator::Event::NONE: |
| case AXEventGenerator::Event::ATK_TEXT_OBJECT_ATTRIBUTE_CHANGED: |
| case AXEventGenerator::Event::WIN_IACCESSIBLE_STATE_CHANGED: |
| return true; |
| } |
| |
| NOTREACHED(); |
| } |
| |
| std::tuple<ax::mojom::Event, AXEventGenerator::Event> |
| MakeTupleForAutomationFromEventTypes( |
| const ax::mojom::Event& ax_event, |
| const AXEventGenerator::Event& generated_event) { |
| std::tuple<ax::mojom::Event, AXEventGenerator::Event> result; |
| // Prefer generated events if they exist. |
| if (generated_event != AXEventGenerator::Event::NONE) { |
| result = std::make_tuple(ax::mojom::Event::kNone, generated_event); |
| } else { |
| // For events that are available as AX events and generated events, use the |
| // generated type. |
| AXEventGenerator::Event equivalent_event = AXEventGenerator::Event::NONE; |
| MaybeParseGeneratedEvent(ToString(ax_event), &equivalent_event); |
| if (equivalent_event != AXEventGenerator::Event::NONE) |
| result = std::make_tuple(ax::mojom::Event::kNone, equivalent_event); |
| else |
| result = std::make_tuple(ax_event, AXEventGenerator::Event::NONE); |
| } |
| |
| // At most one of the AXEvent / generated event should be populated. |
| DCHECK(std::get<0>(result) == ax::mojom::Event::kNone || |
| std::get<1>(result) == AXEventGenerator::Event::NONE); |
| |
| return result; |
| } |
| |
| std::tuple<ax::mojom::Event, AXEventGenerator::Event> |
| AutomationEventTypeToAXEventTuple(const char* event_type_string) { |
| // Prefer generated event types if they exist. |
| AXEventGenerator::Event generated_event = AXEventGenerator::Event::NONE; |
| MaybeParseGeneratedEvent(event_type_string, &generated_event); |
| if (generated_event != AXEventGenerator::Event::NONE) { |
| return std::tuple<ax::mojom::Event, AXEventGenerator::Event>( |
| ax::mojom::Event::kNone, generated_event); |
| } |
| |
| // Otherwise use the AX event type. |
| auto ax_event = MaybeParseAXEnum<ax::mojom::Event>(event_type_string); |
| return std::tuple<ax::mojom::Event, AXEventGenerator::Event>( |
| ax_event.value_or(ax::mojom::Event::kNone), |
| AXEventGenerator::Event::NONE); |
| } |
| |
| AXPositionKind StringToAXPositionKind(const std::string& type) { |
| if (type == "tree") { |
| return AXPositionKind::TREE_POSITION; |
| } else if (type == "text") { |
| return AXPositionKind::TEXT_POSITION; |
| } |
| |
| return AXPositionKind::NULL_POSITION; |
| } |
| |
| } // namespace ui |