JDK-8123632 : KeyCodes do not reflect the keys that are actually pressed on German keyboard
  • Type: Bug
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: 7u25,8
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2013-08-13
  • Updated: 2024-09-30
  • Resolved: 2013-12-23
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8u20Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
see RT-20144 which was closed as "not an issue"

this actually *is* an issue, and an inherently broken issue!

consider a german keyboard layout (it looks like this: http://www.onepoyle.net/german/support/KB_Germany.png, notice that the EQUALS "=" and PLUS "+" are different physical keys!)

also consider following application that displays KeyCodes as they are delivered in Swing:

=== KeyEventTest.java ====

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Locale;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;

public class KeyEventTest {
  public static void main( String[] args ) {
    EventQueue.invokeLater(new Runnable() {
      public void run() {
        Locale.setDefault(Locale.GERMANY);
        (new KeyEventTest()).start();
      }
    });
  }

  private void start() {
    final JTextArea jta = new JTextArea();
    jta.addKeyListener(new KeyListener() {
      public void keyTyped( final KeyEvent e ) {
      }

      public void keyPressed( final KeyEvent e ) {
      }

      public void keyReleased( final KeyEvent e ) {
        System.out.println(KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiersEx()));
      }
    });
    final JScrollPane jsp = new JScrollPane(jta);
    jsp.setPreferredSize(new Dimension(640, 480));

    final JPanel contentPane = new JPanel(new BorderLayout());
    contentPane.add(jsp);

    final JFrame frame = new JFrame(KeyEventTest.class.getName());
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(contentPane);
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}

pressing the numpad + and the + left of return outputs the following:

pressed ADD
pressed PLUS

now consider the following equivalent javafx program:

=== KeyCodeTest.java ===

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.Locale;


public class KeyCodeTest extends Application {

  public static void main(String[] args) {
    Locale.setDefault(Locale.GERMANY);
    launch(args);
  }

  @Override
  public void start(Stage primaryStage) {
    StackPane pane = new StackPane();

    final Label label = new Label("");

    pane.getChildren().add(label);

    pane.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
      @Override
      public void handle(KeyEvent keyEvent) {
        label.setText(label.getText()+keyEvent.getText());
        System.out.println("pressed \""+keyEvent.getCode()+"\"");
      }
    });

    Scene scene = new Scene(pane, 500, 500);
    primaryStage.setScene(scene);
    primaryStage.show();
    pane.requestFocus();
  }
}

same input as above results:

pressed "ADD"
pressed "EQUALS"

note that the keycode indicates a key that actually has *nothing to do* with the key that was physically pressed!

the workaround that was suggested by Pavel Safrata on the issue that i linked above is incorrect, since there is no way to distinguish between the numpad "+" and the other "+" left of return.
Comments
Please file a new JIRA rather than adding comments to this one (they will just get lost). You can refer to this JIRA in the comments and we will link the two bugs.
05-01-2015

When pressing A on a French MacBook keyboard gives me KeyCode.Q, Z gives me KeyCode.W, Q gives me KeyCode.A, W gives me KeyCode.Z, E, R, T, Y are ok. So I guess the layout is the QWERTY. Running JDK8u25
02-01-2015

@Christian: all the keys that you've listed have been tested by me. E.g. the ä key is the "' key in the English keyboard layout (see my previous comment which lists all the OEM keys as they appear on the English US keyboard.)
10-01-2014

As to the first question, there are no EA builds of 8u20 yet. I would hope that builds will start soon, but I don't have a concrete date. Someone else will need to answer your second question.
02-01-2014

Is there a binary JDK 8 preview (which includes the fix) to download and install? Did you also consider äöüß keys?
02-01-2014

Testing: install a German keyboard layout and use the FX app from the Description of this issue to verify the fix. Specifically, try pressing the ;: + , - . /? `~ [{ \| }] '" keys and see what characters/key codes they generate. Note that the current fix resolves the issue on the MS Windows platform only.
23-12-2013

+1
20-12-2013

Webrev: http://cr.openjdk.java.net/~anthony/g-23-8u-keyCodes-RT-32300.0/ Reviewers: Steve, Felipe
20-12-2013

On Mac the issue is even worse: there's a problem with dead keys. The keyDown: event is sent with an empty characters string when a dead key is pressed, so it's just impossible to detect that it is a dead key (its keyCode is a regular keyCode for the physical key, e.g. PLUS for the DEAD_ACUTE on German layout). However, the corresponding keyUp: event provides a non-empty characters: property that contains a symbol representing this dead key. Another complication is that the keyCodes for Z and Y are not switched. Given that the JDK is also affected, I've filed a separate bug to resolve this issue on the Mac: RT-35074. I've also filed a separate bug for Gtk: RT-35077.
20-12-2013

Note that AWT/Swing on Mac has the same bug as described here: the Swing test app reports key codes for the US English layout even after switching to the German layout.
20-12-2013

Here's a fix for MS WIndows platform: http://cr.openjdk.java.net/~anthony/g-23-8u-keyCodes-RT-32300.0/
19-12-2013

I have implemented mapping of normal keys and tested it with the German layout. Now I need to implement the translation of dead keys, and then the fix will be complete for the MS Windows platform.
18-12-2013

I confirm that I can reproduce this issue when switching to the German keyboard layout. Felipe's guess is correct: the table was hard-coded because at that time we only considered the US English kbd layout. I'm investigating how to map the key codes dynamically.
17-12-2013

Assign to Anthony for FX 9 (it will be deferred out of FX 8 given Felipe's analysis).
21-11-2013

Okay, I went over this code again. In JavaFX the translation of a Windows Virtual Key (nVirtKey) to a KeyCode is based only on that table hardcoded in /graphics/src/main/native-glass/win/KeyTable.cpp I don't know the history here but I would guess that table was written observing the output of an US keyboard. Swing works because the table is build dynamically based on the current keyboard layout. See src/windows/native/sun/windows/awt_Component.cpp AwtComponent::BuildDynamicKeyMapTable() (Note, I can be wrong here as I am not familiar with Swing code base, I just grep'ed the source. Anyway, I see how this approach would work for this case). SWT also works, it has a similar approach to Swing (but instead of building translation tables it just maps each key in VM_KEYDOWN). Bottom line: I don't see how to fix this without fundamentally changing the way JavaFX handles native key translation. As far as I'm concerned this is out of scope for 8 given the time we have left. Please defer to 9.
21-11-2013

Is this a regression? This is important to know.
21-11-2013

@Felipe: look at the picture of the german keyboard. pressing "0": WM_KEYDOWN nVirtKey:'0' cRepeat:1 ScanCode:0B fExtended:0 fAltDown:0 fRepeat:0 fUp:0 WM_CHAR chCharCode:'0030' (48) cRepeat:1 ScanCode:0B fExtended:0 fAltDown:0 fRepeat:0 fUp:0 WM_KEYUP nVirtKey:'0' cRepeat:1 ScanCode:0B fExtended:0 fAltDown:0 fRepeat:1 fUp:1 pressing "+": WM_KEYDOWN nVirtKey:VK_OEM_PLUS cRepeat:1 ScanCode:1B fExtended:0 fAltDown:0 fRepeat:0 fUp:0 WM_CHAR chCharCode:'002B' (43) cRepeat:1 ScanCode:1B fExtended:0 fAltDown:0 fRepeat:0 fUp:0 WM_KEYUP nVirtKey:VK_OEM_PLUS cRepeat:1 ScanCode:1B fExtended:0 fAltDown:0 fRepeat:1 fUp:1
19-11-2013

Any update on this issue?
15-11-2013

I do not have a physical German keyboard. I was only able to test this by changing my (physical en_US) keyboard layout to German. Pressing the '=' key on my keyboard (the key to the left of backspace) win32 reports VK_OEM_PLUS, which is defined in WinUser.h as: #define VK_OEM_PLUS 0xBB // '+' any country In /graphics/src/main/native-glass/win/KeyTable.cpp VK_OEM_PLUS is translate to com_sun_glass_events_KeyEvent_VK_EQUALS (0x3D) In KeyCodeMap.java 0x3D gets translate to KeyCode.EQUALS(0x3D, "Equals") It all works fine for English. I'm not familiar with Swing to know how they deal with this situation. As a matter of fact, in my case (US keyboard), KeyCode.EQUALS is right answer for keyCode as it really is the physical key I pressed. Are you using a physical German keyboard ? If so, are you familiar with MS Spy++ (part of Visual Studio) ? Could you inspect the WM_KEYDOWN event and see what virtual key is reported my the OS when the problematic keys are pressed ?
30-10-2013

Felipe: can you take a look at this?
30-10-2013

Here are the other key codes which are returned on my (german) keyboard: ^ => BACK_SLASH (should be DEAD_CIRCUMFLEX) ´ => CLOSE_BRACKET´(should be DEAD_ACUTE) + => EQUALS (should be PLUS) # => SLASH (should be NUMBER_SIGN) The following probably should have KeyCode.UNDEFINED? ß => OPEN_BRACKET ü => SEMICOLON ö => BACK_QUOTE ä => QUOTE
13-08-2013

The EQUALS reported for a key with "+" and "*" on it really is a bug.
13-08-2013

I can reproduce the issue with a german keyboard. Many other keys are also wrong. # results in "SLASH" ^ results in "BACK_SLASH" üöäß keys in german keyboards result in unexpected keycodes. Suprisingly z and y are correct although they are switched on german keyboards. If I switch my keyboard layout to English (US), everything seems to be correct (the text matches with the code).
13-08-2013