blob: 8bc58242717b511da7cc0b57d18aa83f0437eeb5 [file] [log] [blame]
// 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