Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8311922

[macOS] right-Option key fails to generate release event

XMLWordPrintable

    • b01
    • 20
    • b17
    • x86_64
    • os_x

      ADDITIONAL SYSTEM INFORMATION :
      Also replicates in pre-release Java 22.

      A DESCRIPTION OF THE PROBLEM :
      The right-option key on a Mac keyboard does not behave consistent with the left-option key and other paired modifier keys. It fails to generate a keyReleased event (instead it seems to generate a second keyPressed event when the key is released). Also, getKeyLocation() reports as KeyEvent.KEY_LOCATION_STANDARD rather than KeyEvent.KEY_LOCATION_RIGHT.

      This is observed in recent versions of Java. Running the same test under Java 14 produces a different result. The keyReleased event and key location are reported correctly. However, the keycodes for the right-Option key are completely different from the left-Option key, which is not the same for other modifier keys.

      REGRESSION : Last worked in version 14

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the test case program (see source below) on a MacOS machine. Press and Release the right-option key and other modifier keys, left and right.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Key Pressed and Released events should be generated as appropriate. Key location should be "left" and "right" depending on which modifier key is pressed.

      ACTUAL -
      Pressing & releasing left-option and other modifier keys, such as left or right-shift, reports "Pressed" & "Released". Pressing right-option reports "Pressed" but releasing it does not report "Released", status remains as Pressed.

       Also notice that the Location of the right-option key is reported as "Standard" but all other paired modifier keys report as "left" or "right".

      ---------- BEGIN SOURCE ----------
      package events;

      /*
       * KeyEventDemo
       */

      import java.awt.BorderLayout;
      import java.awt.Container;
      import java.awt.Dimension;
      import java.awt.event.*;
      import javax.swing.*;

      class KeyEventDemo extends JFrame
              implements KeyListener,
              ActionListener
      {
          JTextArea displayArea;
          JTextField typingArea;
          static final String newline = System.getProperty("line.separator");

          public static void main(String[] args) {
              /* Use an appropriate Look and Feel */
              try {
                  //UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
                  //UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
                  UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
              } catch (UnsupportedLookAndFeelException ex) {
                  ex.printStackTrace();
              } catch (IllegalAccessException ex) {
                  ex.printStackTrace();
              } catch (InstantiationException ex) {
                  ex.printStackTrace();
              } catch (ClassNotFoundException ex) {
                  ex.printStackTrace();
              }
              /* Turn off metal's use of bold fonts */
              UIManager.put("swing.boldMetal", Boolean.FALSE);

              //Schedule a job for event dispatch thread:
              //creating and showing this application's GUI.
              javax.swing.SwingUtilities.invokeLater(new Runnable() {
                  public void run() {
                      createAndShowGUI();
                  }
              });
          }

          /**
           * Create the GUI and show it. For thread safety,
           * this method should be invoked from the
           * event-dispatching thread.
           */
          private static void createAndShowGUI() {
              //Create and set up the window.
              KeyEventDemo frame = new KeyEventDemo("KeyEventDemo (Java " + System.getProperty("java.version") + ")");
              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

              //Set up the content pane.
              frame.addComponentsToPane();


              //Display the window.
              frame.pack();
              frame.setVisible(true);
          }

          private void addComponentsToPane() {

              JButton button = new JButton("Clear");
              button.addActionListener(this);

              typingArea = new JTextField(20);
              typingArea.addKeyListener(this);

              //Uncomment this if you wish to turn off focus
              //traversal. The focus subsystem consumes
              //focus traversal keys, such as Tab and Shift Tab.
              //If you uncomment the following line of code, this
              //disables focus traversal and the Tab events will
              //become available to the key event listener.
              //typingArea.setFocusTraversalKeysEnabled(false);

              displayArea = new JTextArea();
              displayArea.setEditable(false);
              JScrollPane scrollPane = new JScrollPane(displayArea);
              scrollPane.setPreferredSize(new Dimension(375, 125));

              getContentPane().add(typingArea, BorderLayout.PAGE_START);
              getContentPane().add(scrollPane, BorderLayout.CENTER);
              getContentPane().add(button, BorderLayout.PAGE_END);
          }

          public KeyEventDemo(String name) {
              super(name);
          }


          /** Handle the key typed event from the text field. */
          public void keyTyped(KeyEvent e) {
              displayInfo(e, "KEY TYPED: ");
          }

          /** Handle the key pressed event from the text field. */
          public void keyPressed(KeyEvent e) {
              displayInfo(e, "KEY PRESSED: ");
          }

          /** Handle the key released event from the text field. */
          public void keyReleased(KeyEvent e) {
              displayInfo(e, "KEY RELEASED: ");
          }

          /** Handle the button click. */
          public void actionPerformed(ActionEvent e) {
              //Clear the text components.
              displayArea.setText("");
              typingArea.setText("");

              //Return the focus to the typing area.
              typingArea.requestFocusInWindow();
          }

          /*
           * We have to jump through some hoops to avoid
           * trying to print non-printing characters
           * such as Shift. (Not only do they not print,
           * but if you put them in a String, the characters
           * afterward won't show up in the text area.)
           */
          private void displayInfo(KeyEvent e, String keyStatus){

              //You should only rely on the key char if the event
              //is a key typed event.
              int id = e.getID();
              String keyString;
              if (id == KeyEvent.KEY_TYPED) {
                  char c = e.getKeyChar();
                  keyString = "key character = '" + c + "'";
              } else {
                  int keyCode = e.getKeyCode();
                  keyString = "key code = " + keyCode
                          + " ("
                          + KeyEvent.getKeyText(keyCode)
                          + ")";
              }

              int modifiersEx = e.getModifiersEx();
              String modString = "extended modifiers = " + modifiersEx;
              String tmpString = KeyEvent.getModifiersExText(modifiersEx);
              if (tmpString.length() > 0) {
                  modString += " (" + tmpString + ")";
              } else {
                  modString += " (no extended modifiers)";
              }

              String actionString = "action key? ";
              if (e.isActionKey()) {
                  actionString += "YES";
              } else {
                  actionString += "NO";
              }

              String locationString = "key location: ";
              int location = e.getKeyLocation();
              if (location == KeyEvent.KEY_LOCATION_STANDARD) {
                  locationString += "standard";
              } else if (location == KeyEvent.KEY_LOCATION_LEFT) {
                  locationString += "left";
              } else if (location == KeyEvent.KEY_LOCATION_RIGHT) {
                  locationString += "right";
              } else if (location == KeyEvent.KEY_LOCATION_NUMPAD) {
                  locationString += "numpad";
              } else { // (location == KeyEvent.KEY_LOCATION_UNKNOWN)
                  locationString += "unknown";
              }

              displayArea.append(keyStatus + newline
                      + " " + keyString + newline
                      + " " + modString + newline
                      + " " + actionString + newline
                      + " " + locationString + newline);
              displayArea.setCaretPosition(displayArea.getDocument().getLength());
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Not known.

      FREQUENCY : always


            dnguyen Damon Nguyen
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: