From a908b7b0d922f7b76574cb34bb9bd8892a91c8ca Mon Sep 17 00:00:00 2001 From: Joe Wegner Date: Fri, 23 Aug 2019 10:26:24 -0400 Subject: [PATCH 1/2] A way to make the scrolling menu on Tools | Boards menu more accessible friendly - but it's ugly --- .../processing/app/tools/MenuScroller.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/app/src/processing/app/tools/MenuScroller.java b/app/src/processing/app/tools/MenuScroller.java index 3523ec7ceca..17502292744 100644 --- a/app/src/processing/app/tools/MenuScroller.java +++ b/app/src/processing/app/tools/MenuScroller.java @@ -3,6 +3,8 @@ */ package processing.app.tools; +import processing.app.PreferencesData; + import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -278,6 +280,9 @@ public MenuScroller(JPopupMenu menu, int scrollCount, int interval, scrollCount = autoSizeScrollCount; } +// if (PreferencesData.getBoolean("ide.accessible")) { +// interval = 1000; +// } if (scrollCount <= 0 || interval <= 0) { throw new IllegalArgumentException("scrollCount and interval must be greater than 0"); } @@ -567,6 +572,29 @@ public MenuScrollTimer(final int increment, int interval) { public void actionPerformed(ActionEvent e) { firstIndex += increment * accelerator; refreshMenu(); + if (PreferencesData.getBoolean("ide.accessible")) { + String itemClassName; + int keyEvent; + if (increment > 0) { + itemClassName = menuItems[firstIndex + scrollCount - 1].getClass().getName(); + keyEvent = KeyEvent.VK_UP; + } + else { + itemClassName = menuItems[firstIndex].getClass().getName(); + keyEvent = KeyEvent.VK_DOWN; + } + + // if next item is a separator just go on like normal, otherwise move the cursor back to that item is read + // by a screen reader and the user can continue to use their arrow keys to navigate the list + if (!itemClassName.equals(JSeparator.class.getName()) ) { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + Component comp = manager.getFocusOwner(); + KeyEvent event = new KeyEvent(comp, + KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0, + keyEvent, KeyEvent.CHAR_UNDEFINED); + comp.dispatchEvent(event); + } + } } }); } From 2a53cba1397e0ea4331efce02dec1c564c6600c8 Mon Sep 17 00:00:00 2001 From: Joe Wegner Date: Fri, 23 Aug 2019 12:28:11 -0400 Subject: [PATCH 2/2] Clean up code --- .../processing/app/tools/MenuScroller.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/app/src/processing/app/tools/MenuScroller.java b/app/src/processing/app/tools/MenuScroller.java index 17502292744..9e9aacbcafd 100644 --- a/app/src/processing/app/tools/MenuScroller.java +++ b/app/src/processing/app/tools/MenuScroller.java @@ -280,9 +280,6 @@ public MenuScroller(JPopupMenu menu, int scrollCount, int interval, scrollCount = autoSizeScrollCount; } -// if (PreferencesData.getBoolean("ide.accessible")) { -// interval = 1000; -// } if (scrollCount <= 0 || interval <= 0) { throw new IllegalArgumentException("scrollCount and interval must be greater than 0"); } @@ -573,8 +570,21 @@ public void actionPerformed(ActionEvent e) { firstIndex += increment * accelerator; refreshMenu(); if (PreferencesData.getBoolean("ide.accessible")) { + // If the user has chosen to use accessibility features, it means that they are using a screen reader + // to assist them in development of their project. This scroller is very unfriendly toward screen readers + // because it does not tell the user that it is scrolling through the board options, and it does not read + // the name of the boards as they scroll by. It is possible that the desired board will never become + // accessible. + // Because this scroller is quite nice for the sighted user, the idea here is to continue to use the + // scroller, but to fool it into scrolling one item at a time for accessible features users so that the + // screen readers work well, too. + // It's not the prettiest of code, but it works. String itemClassName; int keyEvent; + + // The blind user likely used an arrow key to get to the scroller. Determine which arrow key + // so we can send an event for the opposite arrow key. This fools the scroller into scrolling + // a single item. Get the class name of the new item while we're here if (increment > 0) { itemClassName = menuItems[firstIndex + scrollCount - 1].getClass().getName(); keyEvent = KeyEvent.VK_UP; @@ -584,8 +594,9 @@ public void actionPerformed(ActionEvent e) { keyEvent = KeyEvent.VK_DOWN; } - // if next item is a separator just go on like normal, otherwise move the cursor back to that item is read - // by a screen reader and the user can continue to use their arrow keys to navigate the list + // Use the class name to check if the next item is a separator. If it is, just let it scroll on like + // normal, otherwise move the cursor back with the opposite key event to the new item so that item is read + // by a screen reader and the user can use their arrow keys to navigate the list one item at a time if (!itemClassName.equals(JSeparator.class.getName()) ) { KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); Component comp = manager.getFocusOwner();