-
Bug
-
Resolution: Unresolved
-
P3
-
11, 17, 21, 23, 24
-
generic
-
windows
Note: This bug occurs with e.g. Java VM 17 and 21 running on Windows, it does not occur on macOS.
Issue: If a JMenuItem contains a shortcut like “Ctrl + Comma”, the private method getKeyChar of the AccessBridge class cuts the “Comma” text to the first character and hence transfers “C” (instead of “Comma”) via the AccessBridge API. For a shortcut “Ctrl + Comma” in a menu item, screen readers announce “Ctrl + C” instead of “Ctrl + Comma” as shortcut, and the user may use a wrong shortcut for this menu action.
For a shortcut like “Ctrl + Period” this method cuts the “Period” to “P”, the AccessBridge API sends “P” as char and hence a screen reader announces “Ctrl + P” as shortcut.
For a shortcut like “Ctrl + Enter” this method cuts the “Enter” to “E”, the AccessBridge API sends “E” as char and hence a screen reader announces “Ctrl + E” as shortcut.
You can use the simple class Test_JMenuItem_KeyStrokes below for testing the java application on Windows with a screen reader, or with the jaccessinspector.
Following code in the method getKeyChar of the AccessBridge (starting with line 3970) is the cause for this issue:
String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode());
debugString("[INFO]: Shortcut is: " + keyText);
if (keyText != null || keyText.length() > 0) {
CharSequence seq = keyText.subSequence(0, 1);
if (seq != null || seq.length() > 0) {
return seq.charAt(0);
}
}
When keyText is for example “Comma”, seq.charAt(0) = C, and then method will return “C” instead of Comma.
public class Test_JMenuItem_KeyStrokes
{
public static void main(String[] args)
{
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu with Keystrokes");
menu.setMnemonic(KeyEvent.VK_M);
menuBar.add(menu);
KeyStroke keyStroke1 = KeyStroke.getKeyStroke(KeyEvent.VK_COMMA, InputEvent.CTRL_DOWN_MASK);
KeyStroke keyStroke2 = KeyStroke.getKeyStroke(KeyEvent.VK_COMMA, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
KeyStroke keyStroke3 = KeyStroke.getKeyStroke(KeyEvent.VK_COMMA, InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK);
KeyStroke keyStroke4 = KeyStroke.getKeyStroke(KeyEvent.VK_PERIOD, InputEvent.CTRL_DOWN_MASK);
KeyStroke keyStroke5 = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
JCheckBoxMenuItem menuItem1 = new JCheckBoxMenuItem("First Menu Item");
menuItem1.setAccelerator(keyStroke1);
JCheckBoxMenuItem menuItem2 = new JCheckBoxMenuItem("Second Menu Item");
menuItem2.setAccelerator(keyStroke2);
JCheckBoxMenuItem menuItem3 = new JCheckBoxMenuItem("Third Menu Item");
menuItem3.setAccelerator(keyStroke3);
JCheckBoxMenuItem menuItem4 = new JCheckBoxMenuItem("Fourth Menu Item");
menuItem4.setAccelerator(keyStroke4);
JCheckBoxMenuItem menuItem5 = new JCheckBoxMenuItem("Fifth Menu Item");
menuItem5.setAccelerator(keyStroke5);
menu.add(menuItem1);
menu.add(menuItem2);
menu.add(menuItem3);
menu.add(menuItem4);
menu.add(menuItem5);
JFrame frame = new JFrame("A Frame with Menu");
frame.add(new JCheckBox("A checkbox"));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar(menuBar);
frame.setSize(300, 200);
frame.setVisible(true);
}
}
Issue: If a JMenuItem contains a shortcut like “Ctrl + Comma”, the private method getKeyChar of the AccessBridge class cuts the “Comma” text to the first character and hence transfers “C” (instead of “Comma”) via the AccessBridge API. For a shortcut “Ctrl + Comma” in a menu item, screen readers announce “Ctrl + C” instead of “Ctrl + Comma” as shortcut, and the user may use a wrong shortcut for this menu action.
For a shortcut like “Ctrl + Period” this method cuts the “Period” to “P”, the AccessBridge API sends “P” as char and hence a screen reader announces “Ctrl + P” as shortcut.
For a shortcut like “Ctrl + Enter” this method cuts the “Enter” to “E”, the AccessBridge API sends “E” as char and hence a screen reader announces “Ctrl + E” as shortcut.
You can use the simple class Test_JMenuItem_KeyStrokes below for testing the java application on Windows with a screen reader, or with the jaccessinspector.
Following code in the method getKeyChar of the AccessBridge (starting with line 3970) is the cause for this issue:
String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode());
debugString("[INFO]: Shortcut is: " + keyText);
if (keyText != null || keyText.length() > 0) {
CharSequence seq = keyText.subSequence(0, 1);
if (seq != null || seq.length() > 0) {
return seq.charAt(0);
}
}
When keyText is for example “Comma”, seq.charAt(0) = C, and then method will return “C” instead of Comma.
public class Test_JMenuItem_KeyStrokes
{
public static void main(String[] args)
{
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu with Keystrokes");
menu.setMnemonic(KeyEvent.VK_M);
menuBar.add(menu);
KeyStroke keyStroke1 = KeyStroke.getKeyStroke(KeyEvent.VK_COMMA, InputEvent.CTRL_DOWN_MASK);
KeyStroke keyStroke2 = KeyStroke.getKeyStroke(KeyEvent.VK_COMMA, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
KeyStroke keyStroke3 = KeyStroke.getKeyStroke(KeyEvent.VK_COMMA, InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK);
KeyStroke keyStroke4 = KeyStroke.getKeyStroke(KeyEvent.VK_PERIOD, InputEvent.CTRL_DOWN_MASK);
KeyStroke keyStroke5 = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
JCheckBoxMenuItem menuItem1 = new JCheckBoxMenuItem("First Menu Item");
menuItem1.setAccelerator(keyStroke1);
JCheckBoxMenuItem menuItem2 = new JCheckBoxMenuItem("Second Menu Item");
menuItem2.setAccelerator(keyStroke2);
JCheckBoxMenuItem menuItem3 = new JCheckBoxMenuItem("Third Menu Item");
menuItem3.setAccelerator(keyStroke3);
JCheckBoxMenuItem menuItem4 = new JCheckBoxMenuItem("Fourth Menu Item");
menuItem4.setAccelerator(keyStroke4);
JCheckBoxMenuItem menuItem5 = new JCheckBoxMenuItem("Fifth Menu Item");
menuItem5.setAccelerator(keyStroke5);
menu.add(menuItem1);
menu.add(menuItem2);
menu.add(menuItem3);
menu.add(menuItem4);
menu.add(menuItem5);
JFrame frame = new JFrame("A Frame with Menu");
frame.add(new JCheckBox("A checkbox"));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar(menuBar);
frame.setSize(300, 200);
frame.setVisible(true);
}
}