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

KeyCharacterCombinations for punctuation and symbols fail on non-US keyboards

XMLWordPrintable

    • b18
    • generic
    • windows

      ADDITIONAL SYSTEM INFORMATION :
      Windows 10
      JavaFX 17
      OpenJDK 11.0.11

      A DESCRIPTION OF THE PROBLEM :
      KeyCharacterCombinations for symbols like '+', '\' and '-' can fail on non-US keyboards. The Windows implementation of the Toolkit call getKeyCodeForChar uses a fixed table which is only valid for US QWERTY. This causes a mismatch between the way getKeyCodeForChar works and the way key codes are assigned when a KeyEvent is generated.

      The test application constructs a KeyCharacterCombination for each KeyTyped event and verifies that the combination matches the KeyPressed event that generated the character.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile and run the attached test.
      Switch to a German keyboard layout.
      Press the German '+' key (where right bracket is on a US keyboard).
      Press the German '#' key (where back slash is on a US keyboard).

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The log area should show these messages:
      Passed: key code Plus matched +
      Passed: key code Number Sign matched #
      ACTUAL -
      The log area shows these messages:
      * Failed: key code Plus did not match +
      * Failed: key code Number Sign did not match #


      ---------- BEGIN SOURCE ----------
      import javafx.application.Application;
      import javafx.application.Platform;
      import javafx.scene.control.TextArea;
      import javafx.scene.input.KeyCode;
      import javafx.scene.input.KeyCombination;
      import javafx.scene.input.KeyCharacterCombination;
      import javafx.scene.input.KeyEvent;
      import javafx.scene.Scene;
      import javafx.stage.Stage;

      public class CharComboTest extends Application {
          private final TextArea typingArea = new TextArea("");
          private KeyEvent lastPressed = null;

          public static void main(String[] args) {
              Application.launch(args);
          }

          @Override
          public void start(Stage stage) {
              typingArea.setEditable(false);
              typingArea.appendText("Shifted punctuation keys are most likely to fail.\nKeys that don't generate text will be ignored.\n\n");

              typingArea.addEventFilter(KeyEvent.KEY_PRESSED, this::pressedEvent);
              typingArea.addEventFilter(KeyEvent.KEY_RELEASED, this::releasedEvent);
              typingArea.addEventFilter(KeyEvent.KEY_TYPED, this::typedEvent);

              Scene scene = new Scene(typingArea, 640, 640);
              stage.setScene(scene);
              stage.setTitle("Key Character Combinations");
              stage.show();

              Platform.runLater(typingArea::requestFocus);
          }

          // Helper Methods for Event Handling
          private void passed(String str) {
              typingArea.appendText("Passed: " + str + "\n");
          }

          private void failed(String str) {
              typingArea.appendText("* Failed: " + str + "\n");
          }

          private void ignored(String str) {
              typingArea.appendText("Ignored: " + str + "\n");
          }

          private void pressedEvent(KeyEvent e) {
              lastPressed = e;
          }

          private void releasedEvent(KeyEvent e) {
              lastPressed = null;
          }

          private KeyCombination.ModifierValue boolToModifier(boolean down)
          {
              if (down)
                  return KeyCombination.ModifierValue.DOWN;
              return KeyCombination.ModifierValue.UP;
          }

          private void typedEvent(KeyEvent e) {
              if (lastPressed == null)
                  return;
              if (e.getCharacter().isEmpty())
                  return;
              
              // Keys that only generate characters with diacritics are not assigned key codes.
              if (lastPressed.getCode() == KeyCode.UNDEFINED)
              {
                  ignored("undefined key code for " + e.getCharacter());
                  return;
              }

              // Keys on the numeric keypad will not match.
              if (lastPressed.getCode().isKeypadKey()) {
                  ignored("keypad code " + lastPressed.getCode().getName() + " generated " + e.getCharacter());
                  return;
              }

              KeyCombination.ModifierValue shiftModifier = boolToModifier(lastPressed.isShiftDown());
              KeyCombination.ModifierValue controlModifier = boolToModifier(lastPressed.isControlDown());
              KeyCombination.ModifierValue altModifier = boolToModifier(lastPressed.isAltDown());
              KeyCombination.ModifierValue metaModifier = boolToModifier(lastPressed.isMetaDown());
              KeyCombination.ModifierValue shortcutModifier = boolToModifier(lastPressed.isShortcutDown());

              KeyCharacterCombination combination = new KeyCharacterCombination(e.getCharacter(),
                  shiftModifier, controlModifier, altModifier, metaModifier, shortcutModifier);

              String combinationDescription = combination.getDisplayText();
              if (lastPressed.getCode().isWhitespaceKey())
              {
                  if (!combinationDescription.isEmpty())
                      combinationDescription = combinationDescription.substring(0, combinationDescription.length() - 1);
                  combinationDescription += lastPressed.getCode().getName();
              }
              
              if (combination.match(lastPressed))
                  passed("key code " + lastPressed.getCode().getName() + " matched " + combinationDescription);
              else
                  failed("key code " + lastPressed.getCode().getName() + " did not match " + combinationDescription);
          }
      }

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

      FREQUENCY : always


            mfox Martin Fox
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: