Small tweaks to improve toolbar keyboard accessibility: Put focus rects
around more controls (including location bar, only when in full keyboard access mode). Fix accessible names. Fix spacebar to activate menu buttons. Remove methods for child focus, they're not needed anymore. BUG=none TEST=none Review URL: http://codereview.chromium.org/2817022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50462 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
chrome/browser
chromeos
status
views
views
@ -27,6 +27,7 @@ void StatusAreaButton::Paint(gfx::Canvas* canvas, bool for_drag) {
|
||||
DrawPressed(canvas);
|
||||
}
|
||||
DrawIcon(canvas);
|
||||
PaintFocusBorder(canvas);
|
||||
}
|
||||
|
||||
gfx::Size StatusAreaButton::GetPreferredSize() {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "base/logging.h"
|
||||
#include "chrome/browser/view_ids.h"
|
||||
#include "chrome/browser/views/frame/browser_view.h"
|
||||
#include "chrome/browser/views/location_bar/location_bar_view.h"
|
||||
#include "chrome/browser/views/accessible_toolbar_view.h"
|
||||
#include "views/controls/button/menu_button.h"
|
||||
#include "views/controls/native/native_view_host.h"
|
||||
@ -81,12 +82,6 @@ bool AccessibleToolbarView::SetToolbarFocusAndFocusDefault(
|
||||
return SetToolbarFocus(view_storage_id, GetDefaultFocusableChild());
|
||||
}
|
||||
|
||||
void AccessibleToolbarView::RemoveToolbarFocusIfNoChildHasFocus() {
|
||||
views::View* focused_view = focus_manager_->GetFocusedView();
|
||||
if (toolbar_has_focus_ && (!focused_view || !IsParentOf(focused_view)))
|
||||
RemoveToolbarFocus();
|
||||
}
|
||||
|
||||
void AccessibleToolbarView::RemoveToolbarFocus() {
|
||||
focus_manager_->RemoveFocusChangeListener(this);
|
||||
toolbar_has_focus_ = false;
|
||||
@ -98,6 +93,12 @@ void AccessibleToolbarView::RemoveToolbarFocus() {
|
||||
focus_manager_->UnregisterAccelerator(right_key_, this);
|
||||
}
|
||||
|
||||
void AccessibleToolbarView::RemoveToolbarFocusIfNoChildHasFocus() {
|
||||
views::View* focused_view = focus_manager_->GetFocusedView();
|
||||
if (toolbar_has_focus_ && (!focused_view || !IsParentOf(focused_view)))
|
||||
RemoveToolbarFocus();
|
||||
}
|
||||
|
||||
void AccessibleToolbarView::RestoreLastFocusedView() {
|
||||
views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
|
||||
views::View* last_focused_view =
|
||||
@ -142,10 +143,11 @@ views::FocusTraversable* AccessibleToolbarView::GetPaneFocusTraversable() {
|
||||
|
||||
bool AccessibleToolbarView::AcceleratorPressed(
|
||||
const views::Accelerator& accelerator) {
|
||||
// Special case: don't handle arrows for native views, like the
|
||||
// location bar's edit text view, which needs them for text editing.
|
||||
// Special case: don't handle arrows for certain views, like the
|
||||
// location bar's edit text view, which need them for text editing.
|
||||
views::View* focused_view = focus_manager_->GetFocusedView();
|
||||
if (focused_view->GetClassName() == views::NativeViewHost::kViewClassName &&
|
||||
if ((focused_view->GetClassName() == LocationBarView::kViewClassName ||
|
||||
focused_view->GetClassName() == views::NativeViewHost::kViewClassName) &&
|
||||
(accelerator.GetKeyCode() == base::VKEY_LEFT ||
|
||||
accelerator.GetKeyCode() == base::VKEY_RIGHT)) {
|
||||
return false;
|
||||
|
@ -31,13 +31,13 @@ class AccessibleToolbarView : public views::View,
|
||||
// if the user escapes. If |initial_focus| is not NULL, that control will get
|
||||
// the initial focus, if it's enabled and focusable. Returns true if
|
||||
// the toolbar was able to receive focus.
|
||||
bool SetToolbarFocus(int view_storage_id, View* initial_focus);
|
||||
virtual bool SetToolbarFocus(int view_storage_id, View* initial_focus);
|
||||
|
||||
// Set focus to the toolbar with complete keyboard access, with the
|
||||
// focus initially set to the default child. Focus will be restored
|
||||
// to the ViewStorage with id |view_storage_id| if the user escapes.
|
||||
// Returns true if the toolbar was able to receive focus.
|
||||
bool SetToolbarFocusAndFocusDefault(int view_storage_id);
|
||||
virtual bool SetToolbarFocusAndFocusDefault(int view_storage_id);
|
||||
|
||||
// Overridden from views::View:
|
||||
virtual FocusTraversable* GetPaneFocusTraversable();
|
||||
@ -59,12 +59,13 @@ class AccessibleToolbarView : public views::View,
|
||||
// other than the first focusable child.
|
||||
virtual views::View* GetDefaultFocusableChild() { return NULL; }
|
||||
|
||||
// Remove toolbar focus.
|
||||
virtual void RemoveToolbarFocus();
|
||||
|
||||
// Remove toolbar focus unless a child (including indirect children)
|
||||
// still has the focus.
|
||||
void RemoveToolbarFocusIfNoChildHasFocus();
|
||||
|
||||
void RemoveToolbarFocus();
|
||||
|
||||
void RestoreLastFocusedView();
|
||||
|
||||
View* GetFirstFocusableChild();
|
||||
|
@ -57,16 +57,6 @@ class BrowserViewsAccessibilityTest : public InProcessBrowserTest {
|
||||
browser()->window()->GetNativeHandle());
|
||||
}
|
||||
|
||||
// Retrieves and initializes an instance of LocationBarView.
|
||||
LocationBarView* GetLocationBarView() {
|
||||
BrowserWindowTesting* browser_window_testing = GetBrowserWindowTesting();
|
||||
|
||||
if (!browser_window_testing)
|
||||
return NULL;
|
||||
|
||||
return GetBrowserWindowTesting()->GetLocationBarView();
|
||||
}
|
||||
|
||||
// Retrieves and initializes an instance of ToolbarView.
|
||||
ToolbarView* GetToolbarView() {
|
||||
BrowserWindowTesting* browser_window_testing = GetBrowserWindowTesting();
|
||||
@ -231,16 +221,6 @@ IN_PROC_BROWSER_TEST_F(BrowserViewsAccessibilityTest,
|
||||
l10n_util::GetString(IDS_ACCNAME_STAR), ROLE_SYSTEM_PUSHBUTTON);
|
||||
}
|
||||
|
||||
// Retrieve accessibility object for location bar view and verify accessibility
|
||||
// info.
|
||||
IN_PROC_BROWSER_TEST_F(BrowserViewsAccessibilityTest,
|
||||
TestLocationBarViewAccObj) {
|
||||
// Verify location bar MSAA name and role.
|
||||
TestViewAccessibilityObject(GetLocationBarView(),
|
||||
l10n_util::GetString(IDS_ACCNAME_LOCATION),
|
||||
ROLE_SYSTEM_GROUPING);
|
||||
}
|
||||
|
||||
// Retrieve accessibility object for Page menu button and verify accessibility
|
||||
// info.
|
||||
IN_PROC_BROWSER_TEST_F(BrowserViewsAccessibilityTest, TestPageMenuAccObj) {
|
||||
@ -291,4 +271,3 @@ IN_PROC_BROWSER_TEST_F(BrowserViewsAccessibilityTest,
|
||||
acc_obj->Release();
|
||||
}
|
||||
} // Namespace.
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#endif
|
||||
|
||||
#include "app/drag_drop_types.h"
|
||||
#include "app/l10n_util.h"
|
||||
#include "app/resource_bundle.h"
|
||||
#include "app/theme_provider.h"
|
||||
#include "chrome/app/chrome_dll_resource.h"
|
||||
@ -29,6 +30,7 @@
|
||||
#include "gfx/canvas.h"
|
||||
#include "gfx/color_utils.h"
|
||||
#include "gfx/skia_util.h"
|
||||
#include "grit/generated_resources.h"
|
||||
#include "grit/theme_resources.h"
|
||||
#include "views/drag_utils.h"
|
||||
|
||||
@ -42,6 +44,8 @@ using views::View;
|
||||
const int LocationBarView::kVertMargin = 2;
|
||||
const int LocationBarView::kEdgeThickness = 2;
|
||||
const int LocationBarView::kItemPadding = 3;
|
||||
const char LocationBarView::kViewClassName[] =
|
||||
"browser/views/location_bar/LocationBarView";
|
||||
|
||||
// Convenience: Total space at the edges of the bar.
|
||||
const int kEdgePadding =
|
||||
@ -94,6 +98,7 @@ LocationBarView::LocationBarView(Profile* profile,
|
||||
star_view_(NULL),
|
||||
mode_(mode),
|
||||
force_hidden_count_(0),
|
||||
show_focus_rect_(false),
|
||||
ALLOW_THIS_IN_INITIALIZER_LIST(first_run_bubble_(this)) {
|
||||
DCHECK(profile_);
|
||||
SetID(VIEW_ID_LOCATION_BAR);
|
||||
@ -155,6 +160,8 @@ void LocationBarView::Init() {
|
||||
AddChildView(location_entry_view_);
|
||||
location_entry_view_->set_focus_view(this);
|
||||
location_entry_view_->Attach(location_entry_->GetNativeView());
|
||||
location_entry_view_->SetAccessibleName(
|
||||
l10n_util::GetString(IDS_ACCNAME_LOCATION));
|
||||
|
||||
selected_keyword_view_ =
|
||||
new SelectedKeywordView(kSelectedKeywordBackgroundImages,
|
||||
@ -554,12 +561,26 @@ void LocationBarView::Paint(gfx::Canvas* canvas) {
|
||||
canvas->FillRectInt(color, bounds.x(), bounds.y(), bounds.width(),
|
||||
bounds.height());
|
||||
}
|
||||
|
||||
if (show_focus_rect_ && HasFocus()) {
|
||||
gfx::Rect r = location_entry_view_->bounds();
|
||||
#if defined(OS_WIN)
|
||||
canvas->DrawFocusRect(r.x() - 1, r.y() - 1, r.width() + 2, r.height() + 2);
|
||||
#else
|
||||
canvas->DrawFocusRect(r.x() - 1, r.y(), r.width() + 2, r.height());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void LocationBarView::VisibleBoundsInRootChanged() {
|
||||
location_entry_->ClosePopup();
|
||||
}
|
||||
|
||||
void LocationBarView::SetShowFocusRect(bool show) {
|
||||
show_focus_rect_ = show;
|
||||
SchedulePaint();
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
bool LocationBarView::OnMousePressed(const views::MouseEvent& event) {
|
||||
UINT msg;
|
||||
@ -839,6 +860,10 @@ void LocationBarView::ShowFirstRunBubbleInternal(
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string LocationBarView::GetClassName() const {
|
||||
return kViewClassName;
|
||||
}
|
||||
|
||||
bool LocationBarView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) {
|
||||
if (keyword_hint_view_->IsVisible() &&
|
||||
views::FocusManager::IsTabTraversalKeyEvent(e)) {
|
||||
|
@ -59,6 +59,9 @@ class LocationBarView : public LocationBar,
|
||||
public views::DragController,
|
||||
public AutocompleteEditController {
|
||||
public:
|
||||
// The location bar view's class name.
|
||||
static const char kViewClassName[];
|
||||
|
||||
class Delegate {
|
||||
public:
|
||||
// Should return the current tab contents.
|
||||
@ -150,6 +153,11 @@ class LocationBarView : public LocationBar,
|
||||
// to close its popup.
|
||||
virtual void VisibleBoundsInRootChanged();
|
||||
|
||||
// Set if we should show a focus rect while the location entry field is
|
||||
// focused. Used when the toolbar is in full keyboard accessibility mode.
|
||||
// Repaints if necessary.
|
||||
virtual void SetShowFocusRect(bool show);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Event Handlers
|
||||
virtual bool OnMousePressed(const views::MouseEvent& event);
|
||||
@ -170,6 +178,7 @@ class LocationBarView : public LocationBar,
|
||||
virtual std::wstring GetTitle() const;
|
||||
|
||||
// Overridden from views::View:
|
||||
virtual std::string GetClassName() const;
|
||||
virtual bool SkipDefaultKeyEventProcessing(const views::KeyEvent& e);
|
||||
virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
|
||||
|
||||
@ -343,6 +352,10 @@ class LocationBarView : public LocationBar,
|
||||
// We should actually be hidden iff this is greater than zero.
|
||||
int force_hidden_count_;
|
||||
|
||||
// True if we should show a focus rect while the location entry field is
|
||||
// focused. Used when the toolbar is in full keyboard accessibility mode.
|
||||
bool show_focus_rect_;
|
||||
|
||||
// Used schedule a task for the first run info bubble.
|
||||
ScopedRunnableMethodFactory<LocationBarView> first_run_bubble_;
|
||||
|
||||
|
@ -149,7 +149,6 @@ void ToolbarView::Init(Profile* profile) {
|
||||
location_bar_ = new LocationBarView(profile, browser_->command_updater(),
|
||||
model_, this, (display_mode_ == DISPLAYMODE_LOCATION) ?
|
||||
LocationBarView::POPUP : LocationBarView::NORMAL);
|
||||
location_bar_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_LOCATION));
|
||||
|
||||
reload_ = new ReloadButton(location_bar_, browser_);
|
||||
reload_->set_triggerable_event_flags(views::Event::EF_LEFT_BUTTON_DOWN |
|
||||
@ -275,6 +274,18 @@ void ToolbarView::SetCollapsed(bool val) {
|
||||
location_bar_->PopForceHidden();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ToolbarView, AccessibleToolbarView overrides:
|
||||
|
||||
bool ToolbarView::SetToolbarFocus(
|
||||
int view_storage_id, views::View* initial_focus) {
|
||||
if (!AccessibleToolbarView::SetToolbarFocus(view_storage_id, initial_focus))
|
||||
return false;
|
||||
|
||||
location_bar_->SetShowFocusRect(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ToolbarView, Menu::BaseControllerDelegate overrides:
|
||||
|
||||
@ -566,10 +577,17 @@ void ToolbarView::ThemeChanged() {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ToolbarView, protected:
|
||||
|
||||
// Override this so that when the user presses F6 to rotate toolbar panes,
|
||||
// the location bar gets focus, not the first control in the toolbar.
|
||||
views::View* ToolbarView::GetDefaultFocusableChild() {
|
||||
return location_bar_;
|
||||
}
|
||||
|
||||
void ToolbarView::RemoveToolbarFocus() {
|
||||
AccessibleToolbarView::RemoveToolbarFocus();
|
||||
location_bar_->SetShowFocusRect(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ToolbarView, private:
|
||||
|
||||
|
@ -87,6 +87,9 @@ class ToolbarView : public AccessibleToolbarView,
|
||||
bool collapsed() const { return collapsed_; }
|
||||
void SetCollapsed(bool val);
|
||||
|
||||
// Overridden from AccessibleToolbarView
|
||||
virtual bool SetToolbarFocus(int view_storage_id, View* initial_focus);
|
||||
|
||||
// Overridden from Menu::BaseControllerDelegate:
|
||||
virtual bool GetAcceleratorInfo(int id, menus::Accelerator* accel);
|
||||
|
||||
@ -125,9 +128,10 @@ class ToolbarView : public AccessibleToolbarView,
|
||||
virtual void ThemeChanged();
|
||||
|
||||
protected:
|
||||
// Override this so that when the user presses F6 to rotate toolbar panes,
|
||||
// the location bar gets focus, not the first control in the toolbar.
|
||||
|
||||
// Overridden from AccessibleToolbarView
|
||||
virtual views::View* GetDefaultFocusableChild();
|
||||
virtual void RemoveToolbarFocus();
|
||||
|
||||
private:
|
||||
// Returns the number of pixels above the location bar in non-normal display.
|
||||
|
@ -710,10 +710,8 @@ void ViewAccessibility::SetState(VARIANT* msaa_state, views::View* view) {
|
||||
// Check both for actual View focus, as well as accessibility focus.
|
||||
views::View* parent = view->GetParent();
|
||||
|
||||
if (view->HasFocus() ||
|
||||
(parent && parent->GetAccFocusedChildView() == view)) {
|
||||
if (view->HasFocus())
|
||||
msaa_state->lVal |= STATE_SYSTEM_FOCUSED;
|
||||
}
|
||||
|
||||
// Add on any view-specific states.
|
||||
AccessibilityTypes::State state;
|
||||
|
@ -226,6 +226,13 @@ bool MenuButton::OnKeyPressed(const KeyEvent& e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MenuButton::OnKeyReleased(const KeyEvent& e) {
|
||||
// Override CustomButton's implementation, which presses the button when
|
||||
// you press space and clicks it when you release space. For a MenuButton
|
||||
// we always activate the menu on key press.
|
||||
return false;
|
||||
}
|
||||
|
||||
// The reason we override View::OnMouseExited is because we get this event when
|
||||
// we display the menu. If we don't override this method then
|
||||
// BaseButton::OnMouseExited will get the event and will set the button's state
|
||||
|
@ -59,6 +59,7 @@ class MenuButton : public TextButton {
|
||||
virtual void OnMouseReleased(const MouseEvent& e, bool canceled);
|
||||
virtual void OnMouseExited(const MouseEvent& event);
|
||||
virtual bool OnKeyPressed(const KeyEvent& e);
|
||||
virtual bool OnKeyReleased(const KeyEvent& e);
|
||||
|
||||
// Accessibility accessors, overridden from View.
|
||||
virtual bool GetAccessibleDefaultAction(std::wstring* action);
|
||||
|
11
views/view.h
11
views/view.h
@ -608,17 +608,6 @@ class View : public AcceleratorTarget {
|
||||
// re-used, otherwise a new instance will be created.
|
||||
ViewAccessibilityWrapper* GetViewAccessibilityWrapper();
|
||||
|
||||
// Accessor used to determine if a child view (leaf) has accessibility focus.
|
||||
// Returns NULL if there are no children, or if none of the children has
|
||||
// accessibility focus.
|
||||
virtual View* GetAccFocusedChildView() { return NULL; }
|
||||
|
||||
// Try to give accessibility focus to a given child view. Returns true on
|
||||
// success. Returns false if this view isn't already focused, if it doesn't
|
||||
// support accessibility focus for children, or if the given view isn't a
|
||||
// valid child view that can receive accessibility focus.
|
||||
virtual bool SetAccFocusedChildView(View* child_view) { return false; }
|
||||
|
||||
// Utility functions
|
||||
|
||||
// Note that the utility coordinate conversions functions always operate on
|
||||
|
Reference in New Issue
Block a user