1 Reply Latest reply on Feb 15, 2018 5:17 AM by Aere

    KeyPressed Events Cease When Key-Repeat Triggered On Mac OSX Java

    Aere

      I have a music Java Swing application that is played by sensing which keyboard key is pressed, and when it is released.  It depends on the KeyPressed and KeyReleased KeyEvents.  It uses Java 8. 

       

      It has been working for years, on Windows, Linux (using open java), and Mac OSX (using Oracle Java).

       

      On Mac OSX 10.12 (Sierra), a new problem appeared, and it continues to be a problem on Mac OSX 10.13 (High Sierra).  We have been able to work-around the problem by turning off key-repeat.

       

      In debugging the problem, I discovered that once key-repeat is triggered, KeyPressed events are no longer passed to the application.  There are no exceptions thrown.  KeyPressed events just stop coming, but KeyReleased events continue to be passed to the application.

       

      When the application is restarted, KeyEvents work as expected (both KeyPressed events, and KeyReleased events are passed to the application).  But again, if key-repeat gets triggered, KeyPressed events stop coming to the application.

       

      I wrote a small test program to demonstrate the problem:

       

      public class KeyEventsJDialog extends javax.swing.JDialog {

          private JPanel jPanelMain;

          private JLabel jLabelError;

          private JToggleButton jToggleButton1;

          private static final long serialVersionUID = 0 ;

          private int lastKeyCode = 0 ;

          private boolean isError = false ;

       

          /**

          * Auto-generated main method to display this JDialog

          */

          public static void main(String[] args)

          {

              SwingUtilities.invokeLater(new Runnable()

              {

                  public void run()

                  {

                      JFrame frame = new JFrame();

                      KeyEventsJDialog inst = new KeyEventsJDialog(frame);

                      inst.setVisible(true);

                      inst.jPanelMain.requestFocus() ;

                  }

              });

          }

         

          public KeyEventsJDialog(JFrame frame) {

              super(frame);

              initGUI();

          }

         

          private void initGUI() {

              try {

                  {

                      this.setTitle("Keyboard Events Test");

                      this.addComponentListener(new ComponentAdapter() {

                          public void componentHidden(ComponentEvent evt) {

                              thisComponentHidden(evt);

                          }

                      });

                      this.addWindowListener(new WindowAdapter() {

                          public void windowClosed(WindowEvent evt) {

                              thisWindowClosed(evt);

                          }

                      });

                      {

                          jPanelMain = new JPanel();

                          getContentPane().add(jPanelMain, BorderLayout.CENTER);

                          jPanelMain.addKeyListener(new KeyAdapter() {

                              public void keyTyped(KeyEvent evt) {

                                  jPanelMainKeyTyped(evt);

                              }

                              public void keyReleased(KeyEvent evt) {

                                  jPanelMainKeyReleased(evt);

                              }

                              public void keyPressed(KeyEvent evt) {

                                  jPanelMainKeyPressed(evt);

                              }

                          });

                          {

                              jToggleButton1 = new JToggleButton();

                              jPanelMain.add(jToggleButton1);

                              jToggleButton1.setText("(undefined)");

                          }

                          {

                              jLabelError = new JLabel();

                              jPanelMain.add(jLabelError);

                              jLabelError.setText(" ");

                              jLabelError.setPreferredSize(new java.awt.Dimension(206, 18));

                          }

                      }

                  }

                  setSize(400, 300);

              } catch (Exception e) {

                  e.printStackTrace();

              }

          }

         

          private void jPanelMainKeyPressed(KeyEvent evt)

          {

              System.out.println("jPanelMain.keyPressed, event="+evt);

              lastKeyCode = evt.getExtendedKeyCode() ;

              JToggleButton button = jToggleButton1 ;

              if (!button.isSelected())

              {

                  button.setText(" ") ;

                  button.setSelected(true) ;

              }

              isError = false ;

              jLabelError.setText(" ") ;

          }

         

          private void jPanelMainKeyReleased(KeyEvent evt)

          {

              System.out.println("jPanelMain.keyReleased, event="+evt);

              lastKeyCode = evt.getExtendedKeyCode() ;

              String typedString = "'" + evt.getKeyChar() + "' = " + lastKeyCode ;

              JToggleButton button = jToggleButton1 ;

              button.setText(new String(typedString)) ;

              if ((!button.isSelected()) || isError)

              {

                  isError = true ;

                  jLabelError.setText(KeyEvent.getKeyText(lastKeyCode) + " KeyPressed event missing") ;

              }

              else

              {

                  jLabelError.setText(KeyEvent.getKeyText(lastKeyCode)) ;

              }

              button.setSelected(false) ;

          }

         

          private void jPanelMainKeyTyped(KeyEvent evt)

          {

              System.out.println("jPanelMain.keyTyped, event="+evt);

              char typed = evt.getKeyChar() ;

              String typedString = "(undefined)" ;

              JToggleButton button = jToggleButton1 ;

              if (!button.isSelected())

              {

                  isError = true ;

                  jLabelError.setText("KeyPressed event missing") ;

                  button.setSelected(true) ;

              }

              typedString = "'" + typed + "' = " + lastKeyCode ;

              button.setText(new String(typedString)) ;

          }

         

          private void thisWindowClosed(WindowEvent evt)

          {

              System.out.println("this.windowClosed, event="+evt);

              System.exit(0) ;

          }

         

          private void thisComponentHidden(ComponentEvent evt)

          {

              System.out.println("this.componentHidden, event="+evt);

              System.exit(0) ;

          }

       

      }

       

      This program has a single toggle button, and when a key is pressed, the toggle button is selected.  When the key is released, the toggle button is un-selected.  It also monitors KeyTyped events, and indicates what key was used in the button text (and a label field to the right of it).

       

      All events are KeyEvents are traced using System.out.println().

       

      With this tool, you can experiment with the problem.

       

      In experimenting, I noticed a strange thing I also can't explain.

       

      When it gets into the state where KeyPressed events are no longer being sent, if I press and hold the "t" key (long enough to trigger key-repeat), after I let up on the "t" key, KeyPressed events are again passed to the application, until some other key (the "a" key most reliably causes it) is held long enough to trigger key-repeat, and then KeyPressed events stop.

       

      Does anyone have any idea why the KeyPressed events stop coming to the application?

       

      Thank you for responding to this.

        • 1. Re: KeyPressed Events Cease When Key-Repeat Triggered On Mac OSX Java
          Aere

          I did further testing on Mac OS X 10.11, 10.12, and 10.13, relative to the key-repeat problem.  In that testing, I identified the former behavior, and the new behavior. 

          In the information below, when I refer to 'freeze', I mean that KeyPressed events stop coming to the Java application. 

          There is a limited set of characters that will freeze input (if held long enough to trigger key-repeat) to the Java test program:

          z, c, n, a, s, e, y, u, i, o

          All of these characters have European special-character alternatives. 

          None of the other keyboard characters cause the Java test program to freeze on input, regardless how long they are held down. 

          I have listed the behavior for the "Notes" application, for the "Terminal" application, and for my Java test program, in the information below. 

          Mac OS X 10.11 El Capitan:

          Keyboard Preferences, key-repeat = on (fast).

          Notes application:

          When you type any of these characters: z, c, n, a, s, e, y, u, i, o, European alternatives are displayed, which you can choose from.  If key-repeat is turned-off, no European alternatives are shown for any of these characters.

          Terminal application:

          With key-repeat on, all keys repeat when held down, even the characters z, c, n, a, s, e, y, u, i, o, and no European alternatives are shown, whether key-repeat is 'on' or 'off'. 

          Java test program:

          All keys are passed to the program as KeyPressed, KeyTyped, and KeyReleased events, regardless whether key-repeat is turned on, or turned off, and regardless how long the keys are held down. 


          Mac OS X 10.12 Sierra:

          Notes application:

          With key-repeat on, when you type any of these characters: z, c, n, a, s, e, y, u, i, o, European alternatives are displayed, which you can choose from.  If key-repeat is turned-off, no European alternatives are shown for any of these characters.

          Terminal application:

          With key-repeat on, all keys repeat when held down, even the characters z, c, n, a, s, e, y, u, i, o, and no European alternatives are shown, whether key-repeat is 'on' or 'off'.  No keys repeat if key-repeat is off.

          Java test program:

          With key-repeat off, all keys are passed to the program as KeyPressed, KeyTyped, and KeyReleased events.  With key-repeat on, when any of the characters z, c, n, a, s, e, y, u, i, o, are pressed long enough to trigger key-repeat, no more KeyPressed or KeyTyped events are passed to the application, but KeyReleased events are still passed.  The test program runs successfully for all keys, if key-repeat is off. 


          Mac OS X 10.13 High Sierra:

          When the key-repeat slider is all the way to the left (the 'off' setting), it doesn't turn key-repeat off.  Instead, the prior setting for key-repeat is used.  Keys will repeat, even though key-repeat is off.  I observed this in many applications, most of which behaved the same as the TextEdit application, which was:

          The only key repeated is the "Delete" key, which repeats (if held down) at the last-specified rate. 

          I observed this behavior in the following applications: TextEdit, Messages, Safari (in the search info), Finder (renaming a folder), Contacts, Notes, and ScriptEditor. 

          The Calculator application performed key-repeat on all numbers, even with key-repeat off. 

          In the Terminal application, all keys were repeated, even with key-repeat off. 

          In the Notes application, any time the characters z, c, n, a, s, e, y, u, i, o, were typed, their European alternatives were displayed, regardless whether key-repeat was on or off.  In Mac OS X 10.12, the European alternatives were displayed only when key-repeat was turned on. 

          With the Java test program, all characters besides z, c, n, a, s, e, y, u, i, o, worked properly, regardless whether key-repeat was on, or off.  If any of the characters z, c, n, a, s, e, y, u, i, o, were pressed long enough to trigger key-repeat, KeyPressed and KeyTyped events were no longer passed to the program, regardless what keys were pressed, but KeyReleased events (for each subsequent key pressed) continued to be passed to the application. 

          In this 'frozen' state, if I pressed and held the 't' key long enough for key-repeat to trigger, KeyPressed and KeyTyped events started coming to the program again (along wih KeyReleased events) for whatever key was pressed. 

          It appears that the characters with European alternative characters (z, c, n, a, s, e, y, u, i, o), when held long enough to trigger key-repeat, will freeze input, regardless whether key-repeat is on, or off.  On 10.12, the key-repeat= off setting was adhered-to, allowing those characters to be typed and held (long enough to trigger key-repeat) with no ill-effects. 

          So it appears if the problem of the key-repeat=off being ignored, is fixed, the Java music application should work, as it does on Mac OS X 10.12.