Bug 376011 - [accessibility] Eclipse 4.2 tab traversal needs refining (Clicking on a toolbar no longer activates the view)
Summary: [accessibility] Eclipse 4.2 tab traversal needs refining (Clicking on a toolb...
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 4.2   Edit
Hardware: PC Windows 7
: P3 major (vote)
Target Milestone: 4.2.2+   Edit
Assignee: Eric Moffatt CLA
QA Contact:
URL:
Whiteboard:
Keywords: accessibility
: 403313 (view as bug list)
Depends on: 379263 384162 402476
Blocks: 456321
  Show dependency tree
 
Reported: 2012-04-03 16:32 EDT by Carolyn MacLeod CLA
Modified: 2014-12-30 04:50 EST (History)
10 users (show)

See Also:


Attachments
CTabFolderTraversalTest.java (4.91 KB, text/plain)
2012-04-03 16:32 EDT, Carolyn MacLeod CLA
no flags Details
Modified snippet to emulate Eclipse UI behavior (5.87 KB, application/octet-stream)
2012-05-25 13:12 EDT, Carolyn MacLeod CLA
no flags Details
Updated patch that has better handling for arrows within a folder (6.02 KB, text/x-java)
2012-06-13 11:37 EDT, Eric Moffatt CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Carolyn MacLeod CLA 2012-04-03 16:32:06 EDT
Created attachment 213531 [details]
CTabFolderTraversalTest.java

Eclipse 4.2 M6

Traverse around the Java perspective using the tab key on the keyboard.
As always, you need to use Ctrl+Tab to traverse out of a multi-line text in the forward direction, and Ctrl+Shift+Tab to traverse out of a multi-line text in the reverse direction. For other controls, it is sufficient to use Tab and Shift+Tab for forward/reverse traversal.

Notice that the traversal behavior is "different" from Eclipse 3.8, in that you do not get "stuck" in a View or Editor stack - you can, in fact, traverse everywhere in the perspective simply by using combinations of the Tab key, which is good.

However, notice also that the behavior seems difficult to predict, because sometimes when you traverse to a CTabItem, focus is forced into the CTabItem's content, and sometimes it isn't. Reverse traversal usually follows a different path than forward traversal.

What is actually happening is that whenever a new stack is "Activated", focus is being given to the contents of the CTabItem. This makes sense for mouse and programmatic activation of a stack, however if the activation comes from the keyboard, this behavior does not feel intuitive.

We need to make keyboard traversal through perspectives follow the expected path. I have attached an SWT snippet that mocks up a simple perspective using e4 CTabFolders. The "force focus into contents on activation" behavior is not enabled at all in this snippet, so that we can see what the "natural" tab order is.

I am not quite sure at this point what the best way to implement the desired behavior is. It may have to be a combined effort between Platform UI and SWT.

CCing Eric and Paul for the Platform UI take on things, and SSQ and Bog for SWT policy and e4 CTabFolder opinions. I think the easiest would be if SWT could guarantee a keyCode in the SWT.Activate Event object whenever Activate comes from the keyboard. Alas, that is not the current behavior of Activate, and I do not know if it is possible to guarantee this on all platforms. If it is, then Platform UI can use the SWT.Activate event.keyCode on CTabFolders as a flag to NOT force focus to the contents, so that keyboard users can follow a natural tab order.
Comment 1 Carolyn MacLeod CLA 2012-04-03 16:40:33 EDT
This must be fixed in some satisfactory way by the time 4.2 ships in order to pass the accessibility checklist.

CCing McQ because we discussed this issue on the whiteboard last week, and his suggestion was to go with the natural platform behavior, which is what we see when running the attached snippet.
Comment 2 Eric Moffatt CLA 2012-05-01 11:12:28 EDT
Carolyn, we are currently responding to the SWT.Activate event, is there any way to tell whether this is coming from the KB or not ?
Comment 3 Eric Moffatt CLA 2012-05-01 11:15:17 EDT
We'll take a look at this in RC1...
Comment 4 Eric Moffatt CLA 2012-05-01 11:22:49 EDT
Why would we fail accessibility because of this ? Ctrl-3 can get you to any view faster than tabbing...(just askin'...;-).
Comment 5 Markus Keller CLA 2012-05-07 08:41:57 EDT
(In reply to comment #4)
> Why would we fail accessibility because of this ?

Because it's unpredictable:
> Reverse traversal usually follows a different path than forward traversal.
Comment 6 Oleg Besedin CLA 2012-05-09 10:52:09 EDT
why is there a focus event on CTabFolder traversal?

Consider this example. Let's say we are in the editor stack with several open editors. 
- press Ctrl+Shift+Tab -> focus is on the stack's "minimize" button. Weird, but OK.
- press Shift+Tab till we get to an editor tab. Note that we do not fall into the editor on the first tab
- press Shift+Tab again to switch to a different editor tab. This time focus shifts to the editor.

The focus events is generated in the following call stack (breakpoint on PartServiceImpl line with "invoke(object, Focus.class,"):

Shell.setActiveControl(Control) line: 1447   =>(2)
Tree(Control).sendFocusEvent(int) line: 2836	
Tree(Widget).wmSetFocus(long, long, long) line: 2417	
Tree(Control).WM_SETFOCUS(long, long) line: 5152	
Tree.WM_SETFOCUS(long, long) line: 7064	
Tree(Control).windowProc(long, int, long, long) line: 4598	
Tree.windowProc(long, int, long, long) line: 5958	
Display.windowProc(long, long, long, long) line: 4976	
OS.SetFocus(long) line: not available [native method]	
Tree(Control).forceFocus() line: 1098	
Tree(Control).setTabItemFocus() line: 3650	
Tree(Composite).setTabGroupFocus() line: 1145	
CTabFolder(Control).traverseGroup(boolean) line: 4293 => (1)
CTabFolder(Control).traverse(Event) line: 4058	
CTabFolder(Control).translateTraversal(MSG) line: 4032	
CTabFolder(Composite).translateTraversal(MSG) line: 1206	
Display.translateTraversal(MSG, Control) line: 4794	

To my eyes the call stack looks rather strange.

(1): CTabFolder(Control).traverseGroup(boolean) line: 4293	

At this line code gets a list of 100+ widgets of all different types and calls #setTabGroupFocus() on each. The widget that gets us is the Tree from one of the navigators (Package Explorer most likley).

(2): Shell.setActiveControl(Control) line: 1447 

At this line Shell gets that navigator tree set as an active control.

That triggers listeners that eventually cause a focus event on the part.

Note that we are navigating editor stack here which does not have any trees in it.
Comment 7 Carolyn MacLeod CLA 2012-05-25 13:07:30 EDT
(In reply to comment 6):
> - press Shift+Tab again to switch to a different editor tab.
I assume you mean "press left or right arrow to switch to a different editor tab", because Shift+Tab traverses to the next "tab traversal group" (which would likely be the part stack containing the Package Explorer in this case). Arrows traverse to the next "tab traversal item", so you need to type arrow to get to a different editor tab.

> This time focus shifts to the editor.
I guess that Eclipse UI must force focus to the CTabItem's control (the editor) when a CTabItem is 'selected'? (as well as when it is 'activated'). Correct?

I modified the snippet to (sort of) emulate the Eclipse UI behavior.
There are 2 booleans at the top of the snippet. If they are both false, then you get regular platform traversal behavior. If they are both true, then you get Eclipse-ish behavior. However, in Eclipse, it is possible to type arrow keys too fast and get non-deterministic behavior (focus shifts to whichever editor you manage to arrow to). With the snippet, I am unable to type fast enough to create a problem. Is it possible that Eclipse is using a timer to asynchronously switch the focus?

> To my eyes the call stack looks rather strange.
I think (?) that maybe the call stack you are looking at is the traversal over to the Package Explorer Tree after pressing Shift+Tab from one of the editor CTabItems? In which case, you would expect focus to go to the Tree next?

Just to double-check, Eclipse UI is definitely switching the focus inside an asyncExec - correct? (I tried switching focus without asynching in my snippet, and I did get some unpredictable behavior).
Comment 8 Carolyn MacLeod CLA 2012-05-25 13:12:54 EDT
Created attachment 216308 [details]
Modified snippet to emulate Eclipse UI behavior

If the non-deterministic behavior can be removed for 4.2.1, then I think it might be possible to explain that forward traversal is different from reverse traversal. We need to get together before 4.2.1 and determine what the behavior *should* be.
Comment 9 Eric Moffatt CLA 2012-06-12 14:41:34 EDT
Note to self: Make sure that whatever story we end up with also works with minimized stacks. At present while we can Ctrl-Tab to the ToolBar representing the stack and arrow around in it, hitting 'Enter' does *not* open/activate the view associated with the tool item...
Comment 10 Eric Moffatt CLA 2012-06-13 11:37:20 EDT
Created attachment 217291 [details]
Updated patch that has better handling for arrows within a folder


This is only a slight change to the original. What it does is inhibit the focus on both selection and activation if the tab change was the result of an arrow traversal.

We need to ensure that this approach will work on all platforms (or determine one that does...;-).
Comment 11 Eric Moffatt CLA 2012-06-21 15:23:15 EDT
commit 7e4f7fe862a8927af779392e2478906c30695916 (in pwebster/start_421)

This implements the traversal handling we want for accessibility...

Carolyn, thanks a heap for providing the SWT snippet, you can pass the bug back to me now if you want...;-).
Comment 12 Carolyn MacLeod CLA 2012-06-21 16:10:51 EDT
All yours man - thanks for giving this so much attention - it's appreciated!
Please make sure it goes into both 4.2.1 and 4.3.

As soon as you have a build, we'll double-check that it does what we want on the other platforms.

Then we still have to come up with some good doc. Some places to put this doc:
- http://help.eclipse.org/juno/index.jsp?topic=/org.eclipse.platform.doc.user/concepts/accessibility/text_editor.htm
 (same as Help -> Help Contents > Workbench User Guide > Concepts > Accessibility features in Eclipse)
 (this also has 3 sub-pages... we could add another sub-page, if that's useful)
- http://wiki.eclipse.org/Accessibility

Does UI have a good place to put this information? (or maybe add a link from a UI page to one of the above places)?
Comment 13 Eric Moffatt CLA 2012-08-14 14:12:41 EDT
I just went through the various scenarios for this on Paul's Linux box and everything appears to be working as expected.

Still need to check on the Mac..
Comment 14 Carolyn MacLeod CLA 2012-09-28 10:22:38 EDT
Tried 0920-1300 on Mac. There are a number of issues:
- apparently we cannot set focus programmatically to trees (probably a different bug)
- tab traversal through toolbars "stalls" on the first inactive item (also a different bug)
- we got into a state where the tab had focus and Enter did not move focus into the view (this problem even happened on Windows - not sure how to replicate it)
Comment 15 Carolyn MacLeod CLA 2012-09-28 10:47:39 EDT
I ran the SWT snippet from comment 10 on Mac, and sure enough, whenever there's a tree in the view, the view does not take focus during keyboard navigation.

I can also get the focus "stuck" somewhere in a toolbar simply by navigating with shift+tab through the toolbar and then, when nothing seems to have focus, type arrow keys.

Both of these are SWT bugs. SSQ, does either of these sound familiar?
Comment 16 Carolyn MacLeod CLA 2012-09-28 11:15:53 EDT
> SSQ, does either of these sound familiar?

I thought we fixed the focus getting stuck problem in bug 375619. Apparently there is still a problem in there somewhere. To replicate, run the snippet in comment 10, use the mouse to put focus on "method1()" in the "Package Explorer", and type shift+tab 7 times. (notice that there are 2 invisible items at the front of each toolbar - this is also a problem). Now type tab twice. Keyboard focus is now lost forever and you need to use the mouse to get it back.
Comment 17 Carolyn MacLeod CLA 2012-09-28 13:09:07 EDT
Found, fixed, and backported the traversal problem in toolbar - it was a 64-bit problem, described in bug 390713.
Comment 18 Carolyn MacLeod CLA 2012-09-28 17:54:31 EDT
Found and fixed the problem in Tree (was also a problem in Table). This is not a problem in 4.2.2 or 3.8.2 because it was recently introduced. See bug 390734 for details.
Comment 19 Carolyn MacLeod CLA 2012-09-28 17:56:54 EDT
So, the SWT bugs have been cleared up. Now, we wait for a build and we try it again in Eclipse on Mac. We also need to really hammer on it in Windows and GTK.
We should finish the doc, too (see comment 12).
Comment 20 Paul Webster CLA 2013-01-11 14:02:35 EST
Defered to 4.3
Comment 21 Paul Webster CLA 2013-02-26 14:06:45 EST
I made the change at http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?id=67a779fd208e9ff629d53a58fa78e8378a0a6cd9

Carolyn, does this look good?

PW
Comment 22 Carolyn MacLeod CLA 2013-02-26 14:30:58 EST
Perfect - thanks, Paul!

This change, plus the fixes in the 2 dependent bugs (bug 379263 and bug 384162), go together to make a solution that I am very happy with.

Traversal with the tab key in both the forward (tab or ctrl+tab) and reverse (shift+tab or ctrl+shift+tab) direction feels very natural, as well as symmetrical (forward and reverse traverse through the same controls) and comprehensive (the user can traverse to and through every stack). Also, if focus is on a page tab, the user can type Enter to traverse directly to the page tab contents.

I have tested this on Windows, Mac, and Linux, with and without a screen reader.

Leaving the bug open as a reminder to backport to 4.2.2+.
Comment 23 Carolyn MacLeod CLA 2013-03-19 15:47:03 EDT
This can be backported to R4_2_maintenance now, and then marked fixed.
The blocking bugs are already backported.
Comment 24 Carolyn MacLeod CLA 2013-03-22 12:07:57 EDT
(Note that this does not need to be backported to 3.8.2+... only to 4.2.2+).
Comment 25 Paul Webster CLA 2013-04-01 11:06:57 EDT
This breaks clicking on a view toolbar in 4.x so I'd suggest not backporting this fix at the moment.

PW
Comment 26 Carolyn MacLeod CLA 2013-04-01 12:14:18 EDT
We need to backport it, so we need to fix clicking on a view toolbar.
SSQ, did you say you had an idea for how to fix this?
Comment 27 Silenio Quarti CLA 2013-04-01 13:05:43 EDT
(In reply to comment #26)
> We need to backport it, so we need to fix clicking on a view toolbar.
> SSQ, did you say you had an idea for how to fix this?

The idea was to put the SWT.Activate listener back only run the code when the SWT.Activate event is coming from a mouse event.  This would require us to start setting a detail on the SWT.Activate event.  Similar to the SWT.MenuDetect event.
Comment 28 Carolyn MacLeod CLA 2013-04-02 09:58:54 EDT
Paul and Eric, if we gave you the ability to know if an Activate came from the keyboard or mouse, would you be able to use that to fix the "activate when clicking on a view toolbar" problem?
Comment 29 Carolyn MacLeod CLA 2013-04-05 10:18:37 EDT
OK, you can now tell if an SWT.Activate came from an SWT.MouseDown or not.

So you can add that SWT.Activate listener back on to the CTabFolder in StackRenderer.hookControllerLogic() (at approx line 969, after the line for ctf.addCTabFolder2Listener(closeListener); )

This time, check if (event.detail == SWT.MouseDown) before activating the stack.

Here's the 11 lines of code to add :

// Detect activation...picks up cases where the user clicks on the
// (already active) tab
ctf.addListener(SWT.Activate, new org.eclipse.swt.widgets.Listener() {
	public void handleEvent(org.eclipse.swt.widgets.Event event) {
		if (event.detail == SWT.MouseDown){ 
			CTabFolder ctf = (CTabFolder) event.widget;
			MElementContainer<MUIElement> stack = (MElementContainer<MUIElement>) ctf.getData(OWNING_ME);
			activateStack(stack);
		}
	}
});
Comment 30 Eric Moffatt CLA 2013-04-05 11:25:43 EDT
http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?id=79af43ff4a53deab4d0568cea065d311993fac32

This is the StackRenderer part of the fix; SWT is adding code to set the 'detail' field of the event to SWT.MouseDown if the activate was because of a mouse event. This will help Car test the result...
Comment 31 Eric Moffatt CLA 2013-04-05 12:22:01 EDT
*** Bug 403313 has been marked as a duplicate of this bug. ***
Comment 32 Eric Moffatt CLA 2013-04-05 12:25:02 EDT
Car, note that this defect is marked as '4.2.2+', meaning that it should be backported into 4.2.2. This means that the SWT fix should also be backported so we'll have to coordinate on when we're going to do this...
Comment 34 Carolyn MacLeod CLA 2013-04-05 13:16:02 EDT
Eric, you can backport to 4.2 now.
(You do not need to backport to 3.8 ... I only did because we keep our streams consistent).