Skip to content
Permalink
Browse files
Extend keyboard navigation to allow directional navigation
https://bugs.webkit.org/show_bug.cgi?id=18662

Reviewed by Simon Fraser, Eric Seidel and Darin Adler.
Patch by Antonio Gomes <tonikitoo@webkit.org>
Based on the initial work of Marco Barisione <marco.barisione@collabora.co.uk>

This patch implements the core logic of the 'Spatial Navigation' feature [1].
It improves the accessibility support of WebCore by extending the basic keyboard
navigation currently available (based on Tab forward and backward) with the
addition of a two-dimensional directional navigation by using Left, Right, Up and
Down arrow keys to move to the "nearest" element in the corresponding direction.

Highlights:
* Feature is turned off by default in Settings. Port specific APIs need to be added
  for toggling it on/off.
* Only elements viewed in the current viewport can have focus move to it. If the
  "nearest" is not in viewport dimensions, then a scroll-in-direction action is
  performed.
* The layout tests added run on Qt's DRT only for now (skipped for Mac, Win and Gtk).

Known issues (to be covered in follow-up bugs):
* Add port specific hooks to each DRT to enable/disable Spatial Navigation.
* Support for spatial navigation through form elements (<input>, <select>, etc)
  is be added.
* Make navigation keys customizable. It currently works with arrows keys only
  (up, down, right and left).
* Make it support modifiers (Alt, Ctrl and Shift).

[1] http://en.wikipedia.org/wiki/Spatial_navigation

* Android.mk:
* GNUmakefile.am:
* WebCore.gypi:
* WebCore.pro:
* WebCore.vcproj/WebCore.vcproj:
* page/EventHandler.cpp:
(WebCore::EventHandler::defaultKeyboardEventHandler):
(WebCore::EventHandler::focusDirectionForKey):
(WebCore::EventHandler::defaultArrowEventHandler):
* page/EventHandler.h:
* page/FocusController.cpp:
(WebCore::FocusController::advanceFocus):
(WebCore::FocusController::advanceFocusInDocumentOrder):
(WebCore::FocusController::advanceFocusDirectionally):
(WebCore::updateFocusCandidateIfCloser):
(WebCore::FocusController::findFocusableNodeInDirection):
(WebCore::FocusController::deepFindFocusableNodeInDirection):
* page/FocusController.h:
* page/FocusDirection.h:
(WebCore::):
* page/Settings.cpp:
(WebCore::Settings::Settings):
(WebCore::Settings::setSpatialNavigationEnabled):
* page/Settings.h:
(WebCore::Settings::isSpatialNavigationEnabled):
* page/SpatialNavigation.cpp: Added.
(WebCore::distanceInDirection):
(WebCore::renderRectRelativeToRootDocument):
(WebCore::alignmentForRects):
(WebCore::isHorizontalMove):
(WebCore::areRectsFullyAligned):
(WebCore::areRectsPartiallyAligned):
(WebCore::spatialDistance):
(WebCore::isRectInDirection):
(WebCore::hasOffscreenRect):
(WebCore::scrollInDirection):
(WebCore::isInRootDocument):
(WebCore::deflateIfOverlapped):
* page/SpatialNavigation.h: Added.
(WebCore::):
(WebCore::FocusCandidate::FocusCandidate):

Canonical link: https://commits.webkit.org/46840@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@55543 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
Antonio Gomes committed Mar 4, 2010
1 parent 79e004e commit b76849d54cc44beb3354554aa7efabec025e4183
Showing 15 changed files with 916 additions and 5 deletions.
@@ -351,6 +351,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
page/Screen.cpp \
page/SecurityOrigin.cpp \
page/Settings.cpp \
page/SpatialNavigation.cpp \
page/UserContentURLPattern.cpp \
page/WindowFeatures.cpp \
page/WorkerNavigator.cpp \
@@ -1,3 +1,78 @@
2010-03-02 Antonio Gomes <tonikitoo@webkit.org>

Reviewed by Simon Fraser, Eric Seidel and Darin Adler.
Patch by Antonio Gomes <tonikitoo@webkit.org>
Based on the initial work of Marco Barisione <marco.barisione@collabora.co.uk>

Extend keyboard navigation to allow directional navigation
https://bugs.webkit.org/show_bug.cgi?id=18662

This patch implements the core logic of the 'Spatial Navigation' feature [1].
It improves the accessibility support of WebCore by extending the basic keyboard
navigation currently available (based on Tab forward and backward) with the
addition of a two-dimensional directional navigation by using Left, Right, Up and
Down arrow keys to move to the "nearest" element in the corresponding direction.

Highlights:
* Feature is turned off by default in Settings. Port specific APIs need to be added
for toggling it on/off.
* Only elements viewed in the current viewport can have focus move to it. If the
"nearest" is not in viewport dimensions, then a scroll-in-direction action is
performed.

Known issues (to be covered in follow-up bugs):
* Add port specific hooks to each DRT to enable/disable Spatial Navigation.
* Support for spatial navigation through form elements (<input>, <select>, etc)
is be added.
* Make navigation keys customizable. It currently works with arrows keys only
(up, down, right and left).
* Make it support modifiers (Alt, Ctrl and Shift).
* Improve support on scrollable content.

[1] http://en.wikipedia.org/wiki/Spatial_navigation

* Android.mk:
* GNUmakefile.am:
* WebCore.gypi:
* WebCore.pro:
* WebCore.vcproj/WebCore.vcproj:
* page/EventHandler.cpp:
(WebCore::EventHandler::defaultKeyboardEventHandler):
(WebCore::EventHandler::focusDirectionForKey):
(WebCore::EventHandler::defaultArrowEventHandler):
* page/EventHandler.h:
* page/FocusController.cpp:
(WebCore::FocusController::advanceFocus):
(WebCore::FocusController::advanceFocusInDocumentOrder):
(WebCore::FocusController::advanceFocusDirectionally):
(WebCore::updateFocusCandidateIfCloser):
(WebCore::FocusController::findFocusableNodeInDirection):
(WebCore::FocusController::deepFindFocusableNodeInDirection):
* page/FocusController.h:
* page/FocusDirection.h:
(WebCore::):
* page/Settings.cpp:
(WebCore::Settings::Settings):
(WebCore::Settings::setSpatialNavigationEnabled):
* page/Settings.h:
(WebCore::Settings::isSpatialNavigationEnabled):
* page/SpatialNavigation.cpp: Added.
(WebCore::distanceInDirection):
(WebCore::renderRectRelativeToRootDocument):
(WebCore::alignmentForRects):
(WebCore::isHorizontalMove):
(WebCore::areRectsFullyAligned):
(WebCore::areRectsPartiallyAligned):
(WebCore::spatialDistance):
(WebCore::isRectInDirection):
(WebCore::hasOffscreenRect):
(WebCore::scrollInDirection):
(WebCore::isInRootDocument):
(WebCore::deflateIfOverlapped):
* page/SpatialNavigation.h: Added.
(WebCore::):
(WebCore::FocusCandidate::FocusCandidate):

2010-03-04 Beth Dakin <bdakin@apple.com>

Reviewed by Anders Carlsson.
@@ -1420,6 +1420,8 @@ webcore_sources += \
WebCore/page/SecurityOriginHash.h \
WebCore/page/Settings.cpp \
WebCore/page/Settings.h \
WebCore/page/SpatialNavigation.cpp \
WebCore/page/SpatialNavigation.h \
WebCore/page/UserContentURLPattern.cpp \
WebCore/page/UserContentURLPattern.h \
WebCore/page/UserScript.h \
@@ -1883,6 +1883,8 @@
'page/SecurityOriginHash.h',
'page/Settings.cpp',
'page/Settings.h',
'page/SpatialNavigation.h',
'page/SpatialNavigation.cpp',
'page/UserContentURLPattern.cpp',
'page/UserContentURLPattern.h',
'page/UserScript.h',
@@ -773,6 +773,7 @@ SOURCES += \
page/SecurityOrigin.cpp \
page/Screen.cpp \
page/Settings.cpp \
page/SpatialNavigation.cpp \
page/UserContentURLPattern.cpp \
page/WindowFeatures.cpp \
page/XSSAuditor.cpp \
@@ -1479,6 +1480,7 @@ HEADERS += \
page/Screen.h \
page/SecurityOrigin.h \
page/Settings.h \
page/SpatialNavigation.h \
page/WindowFeatures.h \
page/WorkerNavigator.h \
page/XSSAuditor.h \
@@ -20972,6 +20972,14 @@
RelativePath="..\page\Settings.h"
>
</File>
<File
RelativePath="..\page\SpatialNavigation.cpp"
>
</File>
<File
RelativePath="..\page\SpatialNavigation.h"
>
</File>
<File
RelativePath="..\page\UserContentURLPattern.cpp"
>
@@ -2174,10 +2174,15 @@ void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
return;
if (event->keyIdentifier() == "U+0009")
defaultTabEventHandler(event);
else {
FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
if (direction != FocusDirectionNone)
defaultArrowEventHandler(direction, event);
}

// provides KB navigation and selection for enhanced accessibility users
if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
handleKeyboardSelectionMovement(event);
// provides KB navigation and selection for enhanced accessibility users
if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
handleKeyboardSelectionMovement(event);
}
if (event->type() == eventNames().keypressEvent) {
m_frame->editor()->handleKeyboardEvent(event);
@@ -2188,6 +2193,27 @@ void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
}
}

FocusDirection EventHandler::focusDirectionForKey(const AtomicString& keyIdentifier) const
{
DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down"));
DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up"));
DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left"));
DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right"));

FocusDirection retVal = FocusDirectionNone;

if (keyIdentifier == Down)
retVal = FocusDirectionDown;
else if (keyIdentifier == Up)
retVal = FocusDirectionUp;
else if (keyIdentifier == Left)
retVal = FocusDirectionLeft;
else if (keyIdentifier == Right)
retVal = FocusDirectionRight;

return retVal;
}

#if ENABLE(DRAG_SUPPORT)
bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const
{
@@ -2482,6 +2508,27 @@ void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)

#endif

void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event)
{
if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
return;

Page* page = m_frame->page();
if (!page)
return;

if (!page->settings() || !page->settings()->isSpatialNavigationEnabled())
return;

// Arrows and other possible directional navigation keys can be used in design
// mode editing.
if (m_frame->document()->inDesignMode())
return;

if (page->focusController()->advanceFocus(focusDirection, event))
event->setDefaultHandled();
}

void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
{
// We should only advance focus on tabs if no special modifier keys are held down.
@@ -27,6 +27,7 @@
#define EventHandler_h

#include "DragActions.h"
#include "FocusDirection.h"
#include "PlatformMouseEvent.h"
#include "ScrollTypes.h"
#include "Timer.h"
@@ -308,6 +309,7 @@ class EventHandler : public Noncopyable {

void defaultSpaceEventHandler(KeyboardEvent*);
void defaultTabEventHandler(KeyboardEvent*);
void defaultArrowEventHandler(FocusDirection, KeyboardEvent*);

#if ENABLE(DRAG_SUPPORT)
void allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const;
@@ -330,6 +332,8 @@ class EventHandler : public Noncopyable {

void setFrameWasScrolledByUser();

FocusDirection focusDirectionForKey(const AtomicString&) const;

bool capturesDragging() const { return m_capturesDragging; }

#if PLATFORM(MAC) && defined(__OBJC__) && !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE)

0 comments on commit b76849d

Please sign in to comment.