JDK-4156752 : Java AWT: Input Method not de-installed because no focus out event delivered
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt:i18n
  • Affected Version: 1.1.7
  • Priority: P2
  • Status: Closed
  • Resolution: Duplicate
  • OS: solaris_2.6
  • CPU: sparc
  • Submitted: 1998-07-13
  • Updated: 1998-08-21
  • Resolved: 1998-08-21
Related Reports
Duplicate :  
Description
JDK 1.1.6 added input method support to support entry of multi-byte
characters on all AWT components which install a key listener.
The input method installs and deinstalls on the component in response
to focus events.
The bug is that the input method may not get de-installed from a component
when it loses focus, with the consequence that keyboard input is
misdirected and lost.

This bug appears on Solaris only, with JDK 1.1.6 and later which is
where the input method code was added.
I am not sure why it doesn't appear on NT, or JDK 1.2. It may be just
good fortune. I'll look into that later.

There is a scenario in which the focus out does not get delivered
to the component, meaning that the input method is still active even though
the component on which it is installed is no longer the active focus component.

This manifests itself in the application as non-entry of modified characters
when typing into the new text component with the input focus.

In the case which showed up this problem, a large and complex application
installed key listeners on all components, in part I believe so that it
could handle tab ordering and validation of all data entered.

One of these components was a button whose function was to bring
up a new Frame in which the user is to complete a task before returning
to the original frame. To prevent the user from manipulating the original
frame, whilst the 2nd frame was showing, it was disabled. So it acted like a
modal dialog.

Disabling the frame also disabled the button the user was pressing.
This translated (on Solaris) into a call to XtSetSensitive(false).
This prevents the underlying X libraries from delivering most events,
including focus events, on that Xt widget, up to the AWT Motif layer.

Thus the AWT never receives a focus out, and leaves the inout
method installed. So when new key events come in, the input method
code is called first from handleKeyEvent() in /src/solaris/sun/canvas.c

The test case below shows that modified (shifted keys, or when caps lock
is in effect) are passed through this route and not delivered to the
component with focus, but instead to the disabled button.

// EchoUpper.java

/* Bring up the app. Press caps lock, Type into the text field, note
 * that alpha characters echo properly. 
 * Press the "Disable Me" button, try typing into the text field again.
 * Note that characters no longer echo and that the event trace shows
 * KEY_TYPED events being delivered to the button.
 */

import java.awt.*;
import java.awt.event.*;

public class EchoUpper extends Frame
                       implements KeyListener, ActionListener, FocusListener {
     Button disable ;

     public static void main(String args[]) {
        new EchoUpper();
     }

     public EchoUpper() {
        disable = new Button("Disable Me");
        disable.addActionListener(this);
        disable.addKeyListener(this);
        disable.addFocusListener(this);
        add("North", disable);
        pack();
        setVisible(true);

        Frame frame2 = new Frame("Second Window");
        TextField text = new TextField(20);
        text.addActionListener(this);
        text.addKeyListener(this);
        text.addFocusListener(this);
        frame2.add("Center", text);
        frame2.pack();
        frame2.setVisible(true);
        frame2.setLocation(0,80);
    }

    public void actionPerformed(ActionEvent event) {
        disable.setEnabled(false);
    }

    public void keyTyped(KeyEvent e) {
       System.out.println("Key Typed: "+e);
    }

    public void keyPressed(KeyEvent e) {
       System.out.println("Key Pressed: "+e);
    }

    public void keyReleased(KeyEvent e) {
       System.out.println("Key Released: "+e);
    }

    public void focusGained(FocusEvent e) {
            System.out.println("Focus Gained: "+e);
    }

    public void focusLost(FocusEvent e) {
            System.out.println("Focus Lost: "+e);
    }
}

Comments
WORK AROUND None that works for the customer application. In theory you call transferFocus() on the button with focus to relinquish focus before disabling the button. Thereby triggering the deinstallation of the input method. But this only works where focus is transferred to a component which does not have a key listener, or is not then disabled too. In the app against which this bug was uncovered, most components have key listeners installed, the enire frame is disabled, so all you have done is leave the input method installed on a different component.
11-06-2004

SUGGESTED FIX Two ideas 1) In the input method code, add a check that this component has the keyboard focus, and bail out if it doesn't. 2) When a component with focus is disabled you could send it a FocusOut event. The reasoning is a disabled component can't accept focus, so it shouldn't keep focus either.
11-06-2004

EVALUATION I tried the suggested fixes, which did not help. I am now sending mail to the people who worked on X11InputMethod.java for their analysis. I isolated the regression to the following delta by senthils: D 1.91.1.4 97/11/13 10:40:06 senthils 116 115 00024/00010/01635 Bugfix 4040458- Europian locale fix & missing XFilterEvent is added sccs sccsdiff -r1.91.1.3 -r1.91.1.4 canvas.c 609,610c609,620 < /* Get keysym without taking modifiers into account first to map < * to AWT keyCode table. --- > /* > * If Window is connected to IME awt_X11inputmethod_LookupString extracts > * composed character or committed string and sends KeyTyped(1.1.6) and > * InputEvent (1.2) event to application.It also returns keysyms. > * The keysyms are sent as KeyPress events to application. > > * If user press character 'a' in C locale awt_X11inputmethod_LookupString > * sends KeyTyped Event with keyChar='a' and returns keysym=XK_a. > * keysymtoAWTKeyCode translates XK_a to VK_A and sends keyPress event. > > * If Window is not connected to IME, keycode is converted into keysym > * and keyPress and keyTyped events are sent to application 620,622c630,640 < } < } else { < /* Get keysym without taking modifiers into account first to map --- > } > keysymToAWTKeyCode(keysym, &keycode, &printable); > if (keycode > 0) > awt_post_java_key_event(client_data, keyEventId, > (passEvent==TRUE) ? (long)awt_copyXEvent(event) : (long)0, > int2ll(event->xkey.time), keycode, > (unicode)keysym, modifiers); > > return; > > } /* Get keysym without taking modifiers into account first to map 625,627c643 < keysym = XKeycodeToKeysym(event->xkey.display, event->xkey.keycode, 0); < } < --- > keysym = XKeycodeToKeysym(event->xkey.display, event->xkey.keycode, 0); 642d657 < #if 0 675d689 < #endif mike.bronson@eng 1998-08-06 Confirmed that this bug has been fixed in 1.1.7J. masayoshi.okutsu@Eng 1998-08-20
06-08-1998