diff options
-rw-r--r-- | views/accessibility/accessibility_types.h | 12 | ||||
-rw-r--r-- | views/accessibility/view_accessibility.cc | 38 | ||||
-rw-r--r-- | views/accessibility/view_accessibility.h | 4 | ||||
-rw-r--r-- | views/focus/focus_manager_win.cc | 3 | ||||
-rw-r--r-- | views/view.h | 6 | ||||
-rw-r--r-- | views/view_gtk.cc | 4 | ||||
-rw-r--r-- | views/view_win.cc | 13 | ||||
-rw-r--r-- | views/widget/widget_win.cc | 34 | ||||
-rw-r--r-- | views/widget/widget_win.h | 30 |
9 files changed, 136 insertions, 8 deletions
diff --git a/views/accessibility/accessibility_types.h b/views/accessibility/accessibility_types.h index 882b8a1..7dd991c 100644 --- a/views/accessibility/accessibility_types.h +++ b/views/accessibility/accessibility_types.h @@ -64,6 +64,18 @@ class AccessibilityTypes { ROLE_WINDOW }; + // This defines an enumeration of the supported accessibility events in our + // Views (e.g. used in View::NotifyAccessibilityEvent). Any interface using + // events must provide a conversion to its own events (see e.g. + // ViewAccessibility::MSAAEvent). + enum Event { + EVENT_FOCUS, + EVENT_MENUSTART, + EVENT_MENUEND, + EVENT_MENUPOPUPSTART, + EVENT_MENUPOPUPEND + }; + private: // Do not instantiate this class. AccessibilityTypes() {} diff --git a/views/accessibility/view_accessibility.cc b/views/accessibility/view_accessibility.cc index 67aaaf2..2dad53d 100644 --- a/views/accessibility/view_accessibility.cc +++ b/views/accessibility/view_accessibility.cc @@ -290,9 +290,24 @@ STDMETHODIMP ViewAccessibility::get_accChild(VARIANT var_child, // Check to see if child is out-of-bounds. if (IsValidChild((var_child.lVal - 1), view_)) { child_view = view_->GetChildViewAt(var_child.lVal - 1); + + // Parents handle leaf IAccessible's. + if (child_view && child_view->GetChildViewCount() == 0) + return S_FALSE; } else { - // Child is located elsewhere in the hierarchy, get ID and adjust for MSAA. - child_view = view_->GetViewByID(static_cast<int>(var_child.lVal)); + // Child is located elsewhere in this view's subtree. + // Positive child id's are 1-based indexes so you can iterate over all + // children, and negative values are direct references to objects. + // Note that we return full IAccessible's for leafs that have + // negative child id's. + if (var_child.lVal > 0) { + child_view = view_->GetViewByID(static_cast<int>(var_child.lVal)); + } else { + // Retrieve it from our cache of views that have fired events. + views::WidgetWin* view_widget = + static_cast<views::WidgetWin*>(view_->GetWidget()); + child_view = view_widget->GetAccessibilityViewEventAt(var_child.lVal); + } } if (!child_view) { @@ -756,6 +771,25 @@ STDMETHODIMP ViewAccessibility::put_accValue(VARIANT var_id, BSTR put_val) { return E_NOTIMPL; } +int32 ViewAccessibility::MSAAEvent(AccessibilityTypes::Event event) { + switch (event) { + case AccessibilityTypes::EVENT_FOCUS: + return EVENT_OBJECT_FOCUS; + case AccessibilityTypes::EVENT_MENUSTART: + return EVENT_SYSTEM_MENUSTART; + case AccessibilityTypes::EVENT_MENUEND: + return EVENT_SYSTEM_MENUEND; + case AccessibilityTypes::EVENT_MENUPOPUPSTART: + return EVENT_SYSTEM_MENUPOPUPSTART; + case AccessibilityTypes::EVENT_MENUPOPUPEND: + return EVENT_SYSTEM_MENUPOPUPEND; + default: + // Not supported or invalid event. + NOTREACHED(); + return -1; + } +} + int32 ViewAccessibility::MSAARole(AccessibilityTypes::Role role) { switch (role) { case AccessibilityTypes::ROLE_APPLICATION: diff --git a/views/accessibility/view_accessibility.h b/views/accessibility/view_accessibility.h index d2472fb..4bb168c 100644 --- a/views/accessibility/view_accessibility.h +++ b/views/accessibility/view_accessibility.h @@ -103,6 +103,10 @@ class ATL_NO_VTABLE ViewAccessibility STDMETHODIMP put_accName(VARIANT var_id, BSTR put_name); STDMETHODIMP put_accValue(VARIANT var_id, BSTR put_val); + // Returns a conversion from the event (as defined in accessibility_types.h) + // to an MSAA event. + static int32 MSAAEvent(AccessibilityTypes::Event event); + // Returns a conversion from the Role (as defined in accessibility_types.h) // to an MSAA role. static int32 MSAARole(AccessibilityTypes::Role role); diff --git a/views/focus/focus_manager_win.cc b/views/focus/focus_manager_win.cc index 4d897ac..b08bf15 100644 --- a/views/focus/focus_manager_win.cc +++ b/views/focus/focus_manager_win.cc @@ -16,8 +16,7 @@ void FocusManager::ClearNativeFocus() { // We need to let assistive technologies know which child view got focus so // they can obtain the proper accessibility object for that child view. if (focused_view_) { - ::NotifyWinEvent(EVENT_OBJECT_FOCUS, widget_->GetNativeView(), OBJID_CLIENT, - static_cast<LONG>(focused_view_->GetID())); + focused_view_->NotifyAccessibilityEvent(AccessibilityTypes::EVENT_FOCUS); } } diff --git a/views/view.h b/views/view.h index f6d1efa..2b50f04 100644 --- a/views/view.h +++ b/views/view.h @@ -554,7 +554,11 @@ class View : public AcceleratorTarget { // Accessibility support // TODO(klink): Move all this out to a AccessibleInfo wrapper class. - // + + // Notify the platform specific accessibility client of changes in the user + // interface. + virtual void NotifyAccessibilityEvent(AccessibilityTypes::Event event_type); + // Returns the MSAA default action of the current view. The string returned // describes the default action that will occur when executing // IAccessible::DoDefaultAction. For instance, default action of a button is diff --git a/views/view_gtk.cc b/views/view_gtk.cc index 7621d0f..049dfe8 100644 --- a/views/view_gtk.cc +++ b/views/view_gtk.cc @@ -20,6 +20,10 @@ int View::GetMenuShowDelay() { return kShowFolderDropMenuDelay; } +void View::NotifyAccessibilityEvent(AccessibilityTypes::Event event_type) { + // Not implemented on GTK. +} + ViewAccessibilityWrapper* View::GetViewAccessibilityWrapper() { NOTIMPLEMENTED(); return NULL; diff --git a/views/view_win.cc b/views/view_win.cc index bce8fa8..3079b5c 100644 --- a/views/view_win.cc +++ b/views/view_win.cc @@ -8,10 +8,12 @@ #include "base/string_util.h" #include "gfx/canvas.h" #include "gfx/path.h" +#include "views/accessibility/view_accessibility.h" #include "views/accessibility/view_accessibility_wrapper.h" #include "views/border.h" #include "views/widget/root_view.h" #include "views/widget/widget.h" +#include "views/widget/widget_win.h" namespace views { @@ -28,6 +30,17 @@ int View::GetMenuShowDelay() { return delay; } +// Notifies accessibility clients of the event_type on this view. +// Clients will call get_accChild found in ViewAccessibility with the supplied +// child id we generate here to retrieve the IAccessible associated with this +// view. +void View::NotifyAccessibilityEvent(AccessibilityTypes::Event event_type) { + WidgetWin* view_widget = static_cast<WidgetWin*>(GetWidget()); + int child_id = view_widget->AddAccessibilityViewEvent(this); + ::NotifyWinEvent(ViewAccessibility::MSAAEvent(event_type), + view_widget->GetNativeView(), OBJID_CLIENT, child_id); +} + ViewAccessibilityWrapper* View::GetViewAccessibilityWrapper() { if (accessibility_.get() == NULL) { accessibility_.reset(new ViewAccessibilityWrapper(this)); diff --git a/views/widget/widget_win.cc b/views/widget/widget_win.cc index 90cffe5..332365a 100644 --- a/views/widget/widget_win.cc +++ b/views/widget/widget_win.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -57,7 +57,9 @@ WidgetWin::WidgetWin() is_mouse_down_(false), is_window_(false), restore_focus_when_enabled_(false), - delegate_(NULL) { + delegate_(NULL), + accessibility_view_events_index_(-1), + accessibility_view_events_(kMaxAccessibilityViewEvents) { } WidgetWin::~WidgetWin() { @@ -112,6 +114,31 @@ void WidgetWin::SetUseLayeredBuffer(bool use_layered_buffer) { contents_.reset(NULL); } +View* WidgetWin::GetAccessibilityViewEventAt(int id) { + // Convert from MSAA child id. + id = -(id + 1); + DCHECK(id >= 0 && id < kMaxAccessibilityViewEvents); + return accessibility_view_events_[id]; +} + +int WidgetWin::AddAccessibilityViewEvent(View* view) { + accessibility_view_events_index_ = + (accessibility_view_events_index_ + 1) % kMaxAccessibilityViewEvents; + accessibility_view_events_[accessibility_view_events_index_] = view; + + // Convert to MSAA child id. + return -(accessibility_view_events_index_ + 1); +} + +void WidgetWin::ClearAccessibilityViewEvent(View* view) { + for (std::vector<View*>::iterator it = accessibility_view_events_.begin(); + it != accessibility_view_events_.end(); + ++it) { + if (*it == view) + *it = NULL; + } +} + /////////////////////////////////////////////////////////////////////////////// // Widget implementation: @@ -428,6 +455,9 @@ void WidgetWin::ViewHierarchyChanged(bool is_add, View *parent, View *child) { if (drop_target_.get()) drop_target_->ResetTargetViewIfEquals(child); + + if (!is_add) + ClearAccessibilityViewEvent(child); } diff --git a/views/widget/widget_win.h b/views/widget/widget_win.h index 699d60e3..98da389 100644 --- a/views/widget/widget_win.h +++ b/views/widget/widget_win.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,6 +10,8 @@ #include <atlcrack.h> #include <atlmisc.h> +#include <vector> + #include "app/win/window_impl.h" #include "base/message_loop.h" #include "base/scoped_comptr_win.h" @@ -92,6 +94,21 @@ class WidgetWin : public app::WindowImpl, can_update_layered_window_ = can_update_layered_window; } + // Obtain the view event with the given MSAA child id. Used in + // ViewAccessibility::get_accChild to support requests for children of + // windowless controls. May return NULL (see ViewHierarchyChanged). + View* GetAccessibilityViewEventAt(int id); + + // Add a view that has recently fired an accessibility event. Returns a MSAA + // child id which is generated by: -(index of view in vector + 1) which + // guarantees a negative child id. This distinguishes the view from + // positive MSAA child id's which are direct leaf children of views that have + // associated hWnd's (e.g. WidgetWin). + int AddAccessibilityViewEvent(View* view); + + // Clear a view that has recently been removed on a hierarchy change. + void ClearAccessibilityViewEvent(View* view); + BEGIN_MSG_MAP_EX(WidgetWin) // Range handlers must go first! MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange) @@ -549,6 +566,17 @@ class WidgetWin : public app::WindowImpl, // Non owned pointer to optional delegate. May be NULL if no delegate is // being used. WidgetDelegate* delegate_; + + // The maximum number of view events in our vector below. + static const int kMaxAccessibilityViewEvents = 20; + + // A vector used to access views for which we have sent notifications to + // accessibility clients. It is used as a circular queue. + std::vector<View*> accessibility_view_events_; + + // The current position of the view events vector. When incrementing, + // we always mod this value with the max view events above . + int accessibility_view_events_index_; }; } // namespace views |