Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions shell/platform/windows/accessibility_bridge_windows.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,8 @@ void AccessibilityBridgeWindows::OnAccessibilityEvent(
// only for the focused node whose selection has changed. If a valid
// caret and selection exist in the app tree, they must both be within
// the focus node.
ui::AXNode::AXID focus_id = GetAXTreeData().sel_focus_object_id;
auto focus_delegate =
GetFlutterPlatformNodeDelegateFromID(focus_id).lock();
if (!focus_delegate) {
auto focus_delegate = GetFocusedNode().lock();
if (focus_delegate) {
win_delegate =
std::static_pointer_cast<FlutterPlatformNodeDelegateWindows>(
focus_delegate);
Expand Down Expand Up @@ -204,4 +202,10 @@ bool AccessibilityBridgeWindows::IsAXFragmentRootAControlElement() {
return true;
}

std::weak_ptr<FlutterPlatformNodeDelegate>
AccessibilityBridgeWindows::GetFocusedNode() {
ui::AXNode::AXID focus_id = GetAXTreeData().sel_focus_object_id;
return GetFlutterPlatformNodeDelegateFromID(focus_id);
}

} // namespace flutter
3 changes: 3 additions & 0 deletions shell/platform/windows/accessibility_bridge_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ class AccessibilityBridgeWindows : public AccessibilityBridge,
std::shared_ptr<FlutterPlatformNodeDelegate>
CreateFlutterPlatformNodeDelegate() override;

// Retrieve the focused node for accessibility events.
virtual std::weak_ptr<FlutterPlatformNodeDelegate> GetFocusedNode();

private:
FlutterWindowsView* view_;

Expand Down
49 changes: 44 additions & 5 deletions shell/platform/windows/accessibility_bridge_windows_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class AccessibilityBridgeWindowsSpy : public AccessibilityBridgeWindows {

void SetFocus(std::shared_ptr<FlutterPlatformNodeDelegateWindows>
node_delegate) override {
focused_nodes_.push_back(node_delegate->GetAXNode()->id());
focused_nodes_.push_back(std::move(node_delegate));
}

void ResetRecords() {
Expand All @@ -62,11 +62,24 @@ class AccessibilityBridgeWindowsSpy : public AccessibilityBridgeWindows {
return dispatched_events_;
}

const std::vector<int32_t> focused_nodes() const { return focused_nodes_; }
const std::vector<int32_t> focused_nodes() const {
std::vector<int32_t> ids;
std::transform(focused_nodes_.begin(), focused_nodes_.end(),
std::back_inserter(ids),
[](std::shared_ptr<FlutterPlatformNodeDelegate> node) {
return node->GetAXNode()->id();
});
return ids;
}

protected:
std::weak_ptr<FlutterPlatformNodeDelegate> GetFocusedNode() override {
return focused_nodes_.back();
}

private:
std::vector<MsaaEvent> dispatched_events_;
std::vector<int32_t> focused_nodes_;
std::vector<std::shared_ptr<FlutterPlatformNodeDelegate>> focused_nodes_;

FML_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridgeWindowsSpy);
};
Expand Down Expand Up @@ -189,6 +202,32 @@ void ExpectWinEventFromAXEvent(int32_t node_id,
EXPECT_EQ(bridge->dispatched_events()[0].event_type, expected_event);
}

void ExpectWinEventFromAXEventOnFocusNode(int32_t node_id,
ui::AXEventGenerator::Event ax_event,
ax::mojom::Event expected_event,
int32_t focus_id) {
auto window_binding_handler =
std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
FlutterWindowsViewSpy view(std::move(window_binding_handler));
view.SetEngine(GetTestEngine());
view.OnUpdateSemanticsEnabled(true);

auto bridge = GetAccessibilityBridgeSpy(view.GetEngine());
PopulateAXTree(bridge);

bridge->ResetRecords();
auto focus_delegate =
bridge->GetFlutterPlatformNodeDelegateFromID(focus_id).lock();
bridge->SetFocus(std::static_pointer_cast<FlutterPlatformNodeDelegateWindows>(
focus_delegate));
bridge->OnAccessibilityEvent({AXNodeFromID(bridge, node_id),
{ax_event, ax::mojom::EventFrom::kNone, {}}});
ASSERT_EQ(bridge->dispatched_events().size(), 1);
EXPECT_EQ(bridge->dispatched_events()[0].event_type, expected_event);
EXPECT_EQ(bridge->dispatched_events()[0].node_delegate->GetAXNode()->id(),
focus_id);
}

} // namespace

TEST(AccessibilityBridgeWindows, GetParent) {
Expand Down Expand Up @@ -342,9 +381,9 @@ TEST(AccessibilityBridgeWindows, OnAccessibilityStateChanged) {
}

TEST(AccessibilityBridgeWindows, OnDocumentSelectionChanged) {
ExpectWinEventFromAXEvent(
ExpectWinEventFromAXEventOnFocusNode(
1, ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED,
ax::mojom::Event::kDocumentSelectionChanged);
ax::mojom::Event::kDocumentSelectionChanged, 2);
}

} // namespace testing
Expand Down