Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Announce alerts through SemanticsService on Windows #36966

Merged
merged 21 commits into from
Oct 27, 2022
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
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -3059,9 +3059,13 @@ FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_texture_regi
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_value.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_view.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/flutter_linux.h
FILE: ../../../flutter/shell/platform/windows/accessibility_alert.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_alert.h
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_delegate_windows.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_delegate_windows.h
FILE: ../../../flutter/shell/platform/windows/accessibility_bridge_delegate_windows_unittests.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_root_node.cc
FILE: ../../../flutter/shell/platform/windows/accessibility_root_node.h
FILE: ../../../flutter/shell/platform/windows/angle_surface_manager.cc
FILE: ../../../flutter/shell/platform/windows/angle_surface_manager.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/dart_project_unittests.cc
Expand Down
4 changes: 4 additions & 0 deletions shell/platform/windows/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ source_set("flutter_windows_headers") {
source_set("flutter_windows_source") {
# Common Windows sources.
sources = [
"accessibility_alert.cc",
"accessibility_alert.h",
"accessibility_bridge_delegate_windows.cc",
"accessibility_bridge_delegate_windows.h",
"accessibility_root_node.cc",
"accessibility_root_node.h",
"angle_surface_manager.cc",
"angle_surface_manager.h",
"cursor_handler.cc",
Expand Down
168 changes: 168 additions & 0 deletions shell/platform/windows/accessibility_alert.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/shell/platform/windows/accessibility_alert.h"

#include "flutter/shell/platform/windows/accessibility_root_node.h"

namespace flutter {

AccessibilityAlert::AccessibilityAlert() : text_(L""), parent_(nullptr) {}

// IAccessible methods.

IFACEMETHODIMP AccessibilityAlert::accHitTest(LONG screen_physical_pixel_x,
LONG screen_physical_pixel_y,
VARIANT* child) {
child->vt = VT_EMPTY;
return S_FALSE;
}

// Performs the object's default action.
IFACEMETHODIMP AccessibilityAlert::accDoDefaultAction(VARIANT var_id) {
return E_FAIL;
}

// Retrieves an IDispatch interface pointer for the specified child.
IFACEMETHODIMP AccessibilityAlert::get_accChild(VARIANT var_child,
IDispatch** disp_child) {
if (V_VT(&var_child) == VT_I4 && V_I4(&var_child) == CHILDID_SELF) {
*disp_child = this;
AddRef();
return S_OK;
}
*disp_child = nullptr;
return E_FAIL;
}

// Retrieves the number of accessible children.
IFACEMETHODIMP AccessibilityAlert::get_accChildCount(LONG* child_count) {
*child_count = 0;
return S_OK;
}

// Retrieves the tooltip description.
IFACEMETHODIMP AccessibilityAlert::get_accDescription(VARIANT var_id,
BSTR* desc) {
*desc = SysAllocString(text_.c_str());
return S_OK;
}

// Retrieves the name of the specified object.
IFACEMETHODIMP AccessibilityAlert::get_accName(VARIANT var_id, BSTR* name) {
*name = SysAllocString(text_.c_str());
return S_OK;
}

// Retrieves the IDispatch interface of the object's parent.
IFACEMETHODIMP AccessibilityAlert::get_accParent(IDispatch** disp_parent) {
*disp_parent = parent_;
if (*disp_parent) {
(*disp_parent)->AddRef();
return S_OK;
}
return S_FALSE;
}

// Retrieves information describing the role of the specified object.
IFACEMETHODIMP AccessibilityAlert::get_accRole(VARIANT var_id, VARIANT* role) {
*role = {.vt = VT_I4, .lVal = ROLE_SYSTEM_ALERT};
return S_OK;
}

// Retrieves the current state of the specified object.
IFACEMETHODIMP AccessibilityAlert::get_accState(VARIANT var_id,
VARIANT* state) {
*state = {.vt = VT_I4, .lVal = STATE_SYSTEM_DEFAULT};
return S_OK;
}

// Gets the help string for the specified object.
IFACEMETHODIMP AccessibilityAlert::get_accHelp(VARIANT var_id, BSTR* help) {
*help = SysAllocString(L"");
return S_OK;
}

// Retrieve or set the string value associated with the specified object.
// Setting the value is not typically used by screen readers, but it's
// used frequently by automation software.
IFACEMETHODIMP AccessibilityAlert::get_accValue(VARIANT var_id, BSTR* value) {
*value = SysAllocString(text_.c_str());
return S_OK;
}

// IAccessible methods not implemented.
IFACEMETHODIMP AccessibilityAlert::get_accSelection(VARIANT* selected) {
selected->vt = VT_EMPTY;
return E_NOTIMPL;
}

IFACEMETHODIMP AccessibilityAlert::accSelect(LONG flags_sel, VARIANT var_id) {
return E_NOTIMPL;
}

IFACEMETHODIMP AccessibilityAlert::put_accValue(VARIANT var_id,
BSTR new_value) {
return E_NOTIMPL;
}

IFACEMETHODIMP AccessibilityAlert::get_accFocus(VARIANT* focus_child) {
focus_child->vt = VT_EMPTY;
return E_NOTIMPL;
}

IFACEMETHODIMP AccessibilityAlert::get_accHelpTopic(BSTR* help_file,
VARIANT var_id,
LONG* topic_id) {
if (help_file) {
*help_file = nullptr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it matter for the return value even if this method returns NotImpl?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation is modeled after the not-implemented method body in ax_platform_node_win.cc

}
if (topic_id) {
*topic_id = 0;
}
return E_NOTIMPL;
}

IFACEMETHODIMP AccessibilityAlert::put_accName(VARIANT var_id, BSTR put_name) {
return E_NOTIMPL;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment indicates the below methods are not part of IAccessible. Currently this is in the // IAccessible methods not implemented. section.

IFACEMETHODIMP AccessibilityAlert::get_accKeyboardShortcut(VARIANT var_id,
BSTR* access_key) {
*access_key = nullptr;
return E_NOTIMPL;
}

IFACEMETHODIMP AccessibilityAlert::accLocation(LONG* physical_pixel_left,
LONG* physical_pixel_top,
LONG* width,
LONG* height,
VARIANT var_id) {
return E_NOTIMPL;
}

IFACEMETHODIMP AccessibilityAlert::accNavigate(LONG nav_dir,
VARIANT start,
VARIANT* end) {
end->vt = VT_EMPTY;
return E_NOTIMPL;
}

IFACEMETHODIMP AccessibilityAlert::get_accDefaultAction(VARIANT var_id,
BSTR* default_action) {
*default_action = nullptr;
return E_NOTIMPL;
}

// End of IAccessible methods.

void AccessibilityAlert::SetText(const std::wstring& text) {
text_ = text;
}

void AccessibilityAlert::SetParent(AccessibilityRootNode* parent) {
parent_ = parent;
}

} // namespace flutter
110 changes: 110 additions & 0 deletions shell/platform/windows/accessibility_alert.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_ACCESSIBILITY_ALERT_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_ACCESSIBILITY_ALERT_H_

#include <atlbase.h>
#include <atlcom.h>
#include <oleacc.h>

#include <string>

namespace flutter {

class AccessibilityRootNode;

// An IAccessible node representing an alert read to the screen reader.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to mention a bit about how it works? and also mention this node is not interact-able by user

// When an announcement is requested by the framework, an instance of
// this class, if none exists already, is created and made a child of
// the root AccessibilityRootNode node, and is therefore also a sibling
// of the window's root node.
// This node is not interactable to the user.
class AccessibilityAlert : public CComObjectRootEx<CComMultiThreadModel>,
public IDispatchImpl<IAccessible> {
public:
BEGIN_COM_MAP(AccessibilityAlert)
COM_INTERFACE_ENTRY(IAccessible)
END_COM_MAP()
//
// IAccessible methods.
//

// Retrieves the child element or child object at a given point on the screen.
IFACEMETHODIMP accHitTest(LONG screen_physical_pixel_x,
LONG screen_physical_pixel_y,
VARIANT* child) override;

// Retrieves an IDispatch interface pointer for the specified child.
IFACEMETHODIMP get_accChild(VARIANT var_child,
IDispatch** disp_child) override;

// Retrieves the number of accessible children.
IFACEMETHODIMP get_accChildCount(LONG* child_count) override;

// Retrieves a string that describes the object's default action.
IFACEMETHODIMP get_accDefaultAction(VARIANT var_id,
BSTR* default_action) override;

// Retrieves the tooltip description.
IFACEMETHODIMP get_accDescription(VARIANT var_id, BSTR* desc) override;

// Retrieves the name of the specified object.
IFACEMETHODIMP get_accName(VARIANT var_id, BSTR* name) override;

// Retrieves the IDispatch interface of the object's parent.
IFACEMETHODIMP get_accParent(IDispatch** disp_parent) override;

// Retrieves information describing the role of the specified object.
IFACEMETHODIMP get_accRole(VARIANT var_id, VARIANT* role) override;

// Retrieves the current state of the specified object.
IFACEMETHODIMP get_accState(VARIANT var_id, VARIANT* state) override;

// Gets the help string for the specified object.
IFACEMETHODIMP get_accHelp(VARIANT var_id, BSTR* help) override;

// Retrieve the string value associated with the specified object.
IFACEMETHODIMP get_accValue(VARIANT var_id, BSTR* value) override;

// IAccessible methods not implemented.
IFACEMETHODIMP accLocation(LONG* physical_pixel_left,
LONG* physical_pixel_top,
LONG* width,
LONG* height,
VARIANT var_id) override;
IFACEMETHODIMP accNavigate(LONG nav_dir,
VARIANT start,
VARIANT* end) override;
IFACEMETHODIMP accDoDefaultAction(VARIANT var_id) override;
IFACEMETHODIMP get_accFocus(VARIANT* focus_child) override;
IFACEMETHODIMP get_accKeyboardShortcut(VARIANT var_id,
BSTR* access_key) override;
IFACEMETHODIMP get_accSelection(VARIANT* selected) override;
IFACEMETHODIMP accSelect(LONG flags_sel, VARIANT var_id) override;
IFACEMETHODIMP get_accHelpTopic(BSTR* help_file,
VARIANT var_id,
LONG* topic_id) override;
IFACEMETHODIMP put_accName(VARIANT var_id, BSTR put_name) override;
IFACEMETHODIMP put_accValue(VARIANT var_id, BSTR new_value) override;

// End of IAccessible methods.

AccessibilityAlert();
~AccessibilityAlert() = default;

// Sets the text of this alert to the provided message.
void SetText(const std::wstring& text);

void SetParent(AccessibilityRootNode* parent);

private:
std::wstring text_;

AccessibilityRootNode* parent_;
};

} // namespace flutter

#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_ACCESSIBILITY_ALERT_H_
Loading