JDK-4122687 : AltGr keys are not working in Components (Swing, JBCL, AWT)
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.1.5,1.1.6,1.1.7,1.2.0
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,windows_95,windows_nt
  • CPU: generic,x86
  • Submitted: 1998-03-25
  • Updated: 1999-07-20
  • Resolved: 1999-07-20
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.
Other Other
1.1.8 1.1.8Fixed 1.2.2Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
Name: clC74495			Date: 03/25/98

=20
Carlos.Lucasius@Canada (Mar 25, 1998)  -
Bug Report from Borland (primary licensee):

AltGr keys are not working in Components (Swing, JBCL, AWT).
However, running a simple app (AWT TextField) worked properly
under JDK 1.1.6i, and 1.2beta3 =20

STEPS:
0. Assumes installation of the U.S.- International keyboard driver
or some other driver supporting AltGr usage. (Drivers are installed
via: Control Panel | Keyboard; <Input Locales>; <Add>; Input Locale
=3D=3D "English (United States)"; <ok>; <Properties>; Keyboard Layout
=3D=3D "US-International")
1. File | New Project...
2. Activate the Int'l keyboard driver
3. <AltGr-s>          //for U.S.-Int'l driver, try whatever AltGr combinati=
on exists on your driver
//exp:  to see the German sharp-s, =DF, character
//act:  produces only a beep

(Review ID: 27096)
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.1.8 1.2.2 FIXED IN: 1.1.8 1.2.2 INTEGRATED IN: 1.1.8 1.2.2 VERIFIED IN: 1.1.8
14-06-2004

SUGGESTED FIX Name: vuC71690 Date: 02/03/99 ###@###.### 1999-02-03 The fix is to NOT call AwtComponent::GetJavaModifiers in AwtComponent::WmChar since Windows has already applied Ctrl/Shift modifiers to a key to translate it into a character. The Alt modifier is reported in the 29th bit of the lParam, which is the 13th bit of `flags' (which is a HIWORD(lParam)). If this is a WM_SYSCHAR message, then we pass the Alt mask to Java; if this is a WM_CHAR message, than Alt flag indicates that the character was typed using an AltGr (or, equivalently, to Ctrl+Alt), so in this case we do NOT pass the Alt mask to Java. This fix also backs out a part of a fix for 4098210 that affects WmChar processing. The backed out code is: // fix for bug #4098210 if (character == java_awt_event_KeyEvent_VK_DELETE) { if ((::GetKeyState(character) & 0x80) == 0) unicodeChar = java_awt_event_KeyEvent_VK_BACK_SPACE; } else ::MultiByteToWideChar(GetCodePage(), 0, (TCHAR*)&character, 1, &unicodeChar, 1); The reason for this is that translation of Ctrl+Backspace to DEL character is a windows feature. See for example in the VC4 online documentation: Visual C++ Books -> C/C++ -> C++ Language Reference -> Charts -> Key Codes -> Key Codes Chart 1 so for TYPED events we'd better leave it compatible with other windows apps. The fix also fixes the wrong shift count for "extended" bit in GetJavaModifiers. Since lParam is split into repeat count and flags, the extended bit (24th in lParam) is the 8th bit of flags. Because of the wrong shift count the condition was never true and META modifier was never seen. With the right shift count keys from extended block are reported with META modifier set, which Swing does not have a default keybindings for - so the diff fixes the count and ifdefs out the test to avoid problems with Swing. This issue probably deserves a separate bug report (if not already). Diffs for 1.1.8 reviewed by Robi Khan. *** awt_Component.cpp~ Wed Feb 3 20:39:05 1999 --- awt_Component.cpp Wed Feb 3 20:36:55 1999 *************** *** 1109,1117 **** { int modifiers = 0; ! if ((1<<24) & flags) { ! modifiers |= java_awt_event_InputEvent_META_MASK; ! } if (HIBYTE(::GetAsyncKeyState(VK_CONTROL)) || mouseButton == MIDDLE_BUTTON) { modifiers |= java_awt_event_InputEvent_CTRL_MASK; --- 1109,1124 ---- { int modifiers = 0; ! // FIXME: Commented out because Swing wouldn't recognize ! // arrows/keys from the extended block, since the following code ! // cause them to be reported with META modifier set. The test was ! // never true before because of the wrong shift count. ! #if 0 ! // Extended bit is 24th in lParam, so it's 8th in flags = HIWORD(lParam) ! if ((1<<8) & flags) { ! modifiers |= java_awt_event_InputEvent_META_MASK; ! } ! #endif if (HIBYTE(::GetAsyncKeyState(VK_CONTROL)) || mouseButton == MIDDLE_BUTTON) { modifiers |= java_awt_event_InputEvent_CTRL_MASK; *************** *** 1386,1424 **** MsgRouting AwtComponent::WmChar(UINT character, UINT repCnt, UINT flags, BOOL system) { - // Will only get WmChar messages with DBCS if we create them for an Edit class - // in the WmForwardChar method. These synthesized DBCS chars are ok to pass on - // directly to the default window procedure. They've already been filtered through - // the Java key event queue. We will never get the trail byte since the edit class - // will PeekMessage(&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE). - // I would like to be able to pass this character off via WM_AWT_FORWARD_BYTE, but - // the Edit classes don't seem to like that. // Begin pollution ! if (IsDBCSLeadByteEx(GetCodePage(), BYTE(character))) ! { return mrDoDefault; } // End pollution // We will simply create Java events here. WCHAR unicodeChar = L'\0'; - UINT message = 0; ! message = system?WM_SYSCHAR:WM_CHAR; ! //fix for bug #4098210 ! if (character == java_awt_event_KeyEvent_VK_DELETE) { ! if ((::GetKeyState(character) & 0x80) == 0) ! unicodeChar = java_awt_event_KeyEvent_VK_BACK_SPACE; ! } ! else ! ::MultiByteToWideChar(GetCodePage(), 0, (TCHAR*)&character, 1, &unicodeChar, 1); MSG* pMsg = CreateMessage(message, character, MAKELPARAM(repCnt, flags)); SendKeyEvent(java_awt_event_KeyEvent_KEY_TYPED, nowMillis(), java_awt_event_KeyEvent_VK_UNDEFINED, unicodeChar, ! GetJavaModifiers(flags, 0), pMsg); return mrConsume; } --- 1393,1437 ---- MsgRouting AwtComponent::WmChar(UINT character, UINT repCnt, UINT flags, BOOL system) { + // Will only get WmChar messages with DBCS if we create them for + // an Edit class in the WmForwardChar method. These synthesized + // DBCS chars are ok to pass on directly to the default window + // procedure. They've already been filtered through the Java key + // event queue. We will never get the trail byte since the edit + // class will PeekMessage(&msg, hwnd, WM_CHAR, WM_CHAR, + // PM_REMOVE). I would like to be able to pass this character off + // via WM_AWT_FORWARD_BYTE, but the Edit classes don't seem to + // like that. // Begin pollution ! if (IsDBCSLeadByteEx(GetCodePage(), BYTE(character))) { return mrDoDefault; } // End pollution // We will simply create Java events here. + UINT message = system ? WM_SYSCHAR : WM_CHAR; WCHAR unicodeChar = L'\0'; ! // Do NOT call GetJavaModifiers since Windows has already applied ! // Ctrl/Shift modifiers to a key to translate it into a character. ! // The Alt modifier is reported in the 29th bit of the lParam, ! // which is the 13th bit of `flags' (which is a HIWORD(lParam)). ! // If this is a WM_SYSCHAR message, then we pass the Alt mask to ! // Java; if this is a WM_CHAR message, than Alt flag indicates ! // that the character was typed using an AltGr (== Ctrl+Alt), so ! // in this case we do NOT pass the Alt mask to Java (4122687). ! long modifiers = 0; ! if (system && (flags & (1<<13))) ! modifiers |= java_awt_Event_ALT_MASK; ! ::MultiByteToWideChar(GetCodePage(), 0, (TCHAR*)&character, 1, ! &unicodeChar, 1); MSG* pMsg = CreateMessage(message, character, MAKELPARAM(repCnt, flags)); SendKeyEvent(java_awt_event_KeyEvent_KEY_TYPED, nowMillis(), java_awt_event_KeyEvent_VK_UNDEFINED, unicodeChar, ! modifiers, pMsg); return mrConsume; } As several people already mentioned, the Swing problem with AltGr characters went away in 1.2 "K". However the fix is ported to 1.2.2 as well for the sake of consistency. Diffs for 1.2.2, reviewed by Eric Hawkes. *** awt_Component.cpp~ Wed Feb 3 20:04:21 1999 --- awt_Component.cpp Tue Feb 2 21:16:00 1999 *************** *** 1412,1420 **** { int modifiers = 0; ! if ((1<<24) & flags) { modifiers |= java_awt_event_InputEvent_META_MASK; ! } if (HIBYTE(::GetAsyncKeyState(VK_CONTROL)) || mouseButton == MIDDLE_BUTTON) { modifiers |= java_awt_event_InputEvent_CTRL_MASK; --- 1412,1427 ---- { int modifiers = 0; ! // FIXME: Commented out because Swing wouldn't recognize ! // arrows/keys from the extended block, since the following code ! // cause them to be reported with META modifier set. The test was ! // never true before because of the wrong shift count. ! #if 0 ! // "Extended" bit is 24th in lParam, so it's 8th in flags = HIWORD(lParam) ! if ((1<<8) & flags) { modifiers |= java_awt_event_InputEvent_META_MASK; ! } ! #endif if (HIBYTE(::GetAsyncKeyState(VK_CONTROL)) || mouseButton == MIDDLE_BUTTON) { modifiers |= java_awt_event_InputEvent_CTRL_MASK; *************** *** 1886,1928 **** MsgRouting AwtComponent::WmChar(UINT character, UINT repCnt, UINT flags, BOOL system) { - // Will only get WmChar messages with DBCS if we create them for an Edit class - // in the WmForwardChar method. These synthesized DBCS chars are ok to pass on - // directly to the default window procedure. They've already been filtered through - // the Java key event queue. We will never get the trail byte since the edit class - // will PeekMessage(&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE). - // I would like to be able to pass this character off via WM_AWT_FORWARD_BYTE, but - // the Edit classes don't seem to like that. // Begin pollution ! if (IsDBCSLeadByteEx(GetCodePage(), BYTE(character))) ! { return mrDoDefault; } // End pollution // We will simply create Java events here. WCHAR unicodeChar = L'\0'; ! UINT message = 0; - message = system?WM_SYSCHAR:WM_CHAR; - //fix for bug #4098210 - if (character == java_awt_event_KeyEvent_VK_DELETE) { - if ((::GetKeyState(character) & 0x80) == 0) - unicodeChar = java_awt_event_KeyEvent_VK_BACK_SPACE; - } - else - ::MultiByteToWideChar(GetCodePage(), 0, (TCHAR*)&character, 1, &unicodeChar, 1); MSG* pMsg = CreateMessage(message, character, MAKELPARAM(repCnt, flags)); ! // If InputMethod is disabled or character is control code, KeyTyped Event is generated. ! // Otherwise, InputMethod Event is generated. ! if ( m_useNativeCompWindow || unicodeChar<=0x001F) { // Enter key generates \r in windows, but \n is required in java ! if(unicodeChar==VK_RETURN) unicodeChar = java_awt_event_KeyEvent_VK_ENTER; SendKeyEvent(java_awt_event_KeyEvent_KEY_TYPED, nowMillis(), ! java_awt_event_KeyEvent_VK_UNDEFINED, unicodeChar, ! GetJavaModifiers(flags, 0), pMsg); } else { jstring jstr = ((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2))->NewString(&unicodeChar,1); SendInputMethodEvent(java_awt_event_InputMethodEvent_INPUT_METHOD_TEXT_CHANGED, jstr, --- 1893,1945 ---- MsgRouting AwtComponent::WmChar(UINT character, UINT repCnt, UINT flags, BOOL system) { + // Will only get WmChar messages with DBCS if we create them for + // an Edit class in the WmForwardChar method. These synthesized + // DBCS chars are ok to pass on directly to the default window + // procedure. They've already been filtered through the Java key + // event queue. We will never get the trail byte since the edit + // class will PeekMessage(&msg, hwnd, WM_CHAR, WM_CHAR, + // PM_REMOVE). I would like to be able to pass this character off + // via WM_AWT_FORWARD_BYTE, but the Edit classes don't seem to + // like that. // Begin pollution ! if (IsDBCSLeadByteEx(GetCodePage(), BYTE(character))) { return mrDoDefault; } // End pollution // We will simply create Java events here. + UINT message = system ? WM_SYSCHAR : WM_CHAR; + + // Do NOT call GetJavaModifiers since Windows has already applied + // Ctrl/Shift modifiers to a key to translate it into a character. + // The Alt modifier is reported in the 29th bit of the lParam, + // which is the 13th bit of `flags' (which is a HIWORD(lParam)). + // If this is a WM_SYSCHAR message, then we pass the Alt mask to + // Java; if this is a WM_CHAR message, than Alt flag indicates + // that the character was typed using an AltGr (== Ctrl+Alt), so + // in this case we do NOT pass the Alt mask to Java. + long modifiers = 0; + if (system && (flags & (1<<13))) + modifiers |= java_awt_Event_ALT_MASK; + WCHAR unicodeChar = L'\0'; ! ::MultiByteToWideChar(GetCodePage(), 0, (TCHAR*)&character, 1, ! &unicodeChar, 1); MSG* pMsg = CreateMessage(message, character, MAKELPARAM(repCnt, flags)); ! // If InputMethod is disabled or character is control code, ! // KeyTyped Event is generated. Otherwise, InputMethod Event is ! // generated. ! if (m_useNativeCompWindow || unicodeChar <= 0x001F) { // Enter key generates \r in windows, but \n is required in java ! if (unicodeChar == VK_RETURN) ! unicodeChar = java_awt_event_KeyEvent_VK_ENTER; SendKeyEvent(java_awt_event_KeyEvent_KEY_TYPED, nowMillis(), ! java_awt_event_KeyEvent_VK_UNDEFINED, unicodeChar, ! modifiers, pMsg); } else { jstring jstr = ((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2))->NewString(&unicodeChar,1); SendInputMethodEvent(java_awt_event_InputMethodEvent_INPUT_METHOD_TEXT_CHANGED, jstr, ======================================================================
11-06-2004

EVALUATION hans.muller@Eng 1998-03-30 This looks like an AWT problem - the native keyboard event code probably doesn't pass these key events along. The fact that AWT text fields do support the special keys just means that the platforms native components do. We should too. norbert.lindenberg@Eng 1998-03-30 Can't repro with peered TextComponent or lightweight text component on JDK1.1.6K on Win95 or WinNT US with German keyboard layout. The characters produced by AltGr-2, AltGr-3, AltGr-Q show up nicely in either component. Couldn't figure out how to run SwingSet on JDK 1.1.6 on the Win95 box, so there's still a slight possibility that this problem persists in Swing. ======= This problem only happens with lightweight Components. Nevertheless, it is most likely still an AWT, not a Swing, problem. david.mendenhall@eng 1998-09-17 ---------------------------------------------------------------------------- This is a problem at the native level with the generation of the "typed" key events. There is not enough time to fix this for 1.2, but we have a java-level patch that has been sent to licensees which follows. The root of the problem is the fact that the native level is generating key typed events for situations that don't generate a unicode character, and we are trying to filter that at the java level. import java.awt.event.*; import javax.swing.text.*; /** * Patch to work around the problem where currently * the AltGr doesn't work with swing text because * of the way it filters key typed events. At some * point the native AWT support will be fixed and the * filtering behavior can be removed, but until then * this patch should help (it's a slightly improved * filter). This will only work on win32 which is * currently setting modifiers on the key typed * events. * <p> * This can be installed by calling * <pre><code> * &nbsp; new AltGrPatch(); * </code></pre> * prior to using a swing text component. The creation * of an instance of this class does not itself do anything * but causes the class to be loaded and the static * initialization to take place. The static * initializer will change the default keymaps handling * of the key typed events when this class is loaded. * This patch assumes that the the handling of key * typed events hasn't been changed by the application * (i.e. by calling Keymap.setDefaultAction on a keymap). * If the application is already modifying the keymap, * the applications action for this should be modified * to include the behavior contained in the nested class * AltGrPatch.DefaultKeyTypedAction. * */ class AltGrPatch { /** * The action that is executed by default if * a <em>key typed event</em> is received and there * is no keymap entry. There is a variation across * different VM's in what gets sent as a <em>key typed</em> * event, and this action tries to filter out the undesired * events. This filters the control characters and those * with the ALT modifier. * <p> * If the event doesn't get filtered, it will try to insert * content into the text editor. The content is fetched * from the command string of the ActionEvent. The text * entry is done through the <code>replaceSelection</code> * method on the target text component. This is the * action that will be fired for most text entry tasks. * * @see DefaultEditorKit#defaultKeyTypedAction * @see DefaultEditorKit#getActions * @see Keymap#setDefaultAction * @see Keymap#getDefaultAction */ static class DefaultKeyTypedAction extends TextAction { /** * Creates this object with the appropriate identifier. */ public DefaultKeyTypedAction() { super(DefaultEditorKit.defaultKeyTypedAction); } /** * The operation to perform when this action is triggered. * * @param e the action event */ public void actionPerformed(ActionEvent e) { JTextComponent target = getTextComponent(e); if ((target != null) && (e != null)) { String content = e.getActionCommand(); int mod = e.getModifiers(); if ((content != null) && (content.length() > 0) && (((mod & ActionEvent.ALT_MASK) == 0) || ((mod & ActionEvent.CTRL_MASK) != 0))) { char c = content.charAt(0); if ((c >= 0x20) && (c != 0x7F)) { target.replaceSelection(content); } } } } } static { Keymap map = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP); if (map != null) { map.setDefaultAction(new DefaultKeyTypedAction()); System.err.println("AltGr patch applied"); } else { System.err.println("Default keymap doesn't exist, patch not applied"); } } } timothy.prinzing@eng 1998-09-20 Name: vuC71690 Date: 02/03/99 ###@###.### 1999-02-03 On Windows AltGr == Ctrl+Alt. Since we report modifiers that were used to type a character in the KEY_TYPED event, Swing is confused since it see Ctrl+Alt+<char> for chars typed with AltGr. ====================================================================== This bug was verified as fixed via manual testing using jdk118h. al.smith@eng 1999-02-26
26-02-1999