Tablet input indistinguishable from setText changes

This applet illustrates problems with input from Tablets (Tablet PC or external tablet) to Java TextFields. 

This demonstration applet attempts to modify the input to the TextField to correct errors.  In this example, any input to the TextField other than a positive number or zero is flagged as an error by changing the text to report the error.  The applet acts in different ways on different platforms, and there seems to be no good way to write the program for the Sun and Macintosh JVMs.  Consider what happens when inserting the incorrect input "x" using the Tablet:

Microsoft JVM (using Microsoft Windows XP 2005 Tablet Input Panel):

The TextField shows: "Error", the desired display.  The following appears in the Java Console:

keyPressed:
textValueChanged: x
keyTyped: x
textValueChanged: Error
keyReleased: Error

All 4 Key and Text events (keyPressed, textValueChanged, keyTyped and keyReleased) fire from the input and textValueChanged fires again from setText.  The program listens for keyTyped to distinguish between Tablet input and setText changes.  (Note that keyPressed could not be used since it does not have current information reflecting the input "x"). 

Sun JVM (using Microsoft Windows XP 2005 Tablet Input Panel):

The TextField shows "xError", not the desired display.  The following appears in the Java Console:

keyTyped:
textValueChanged: xError
textValueChanged: xError

Only keyTyped and textValueChanged are fired but keyTyped does not have current information reflecting the input "x" so it still reports the TextField as blank.  Despite keyTyped not having current information one might imagine using it to set some flag to distinguish Tablet events from setText events, but this is a can of worms in a threaded environment (note that different trials of longer inputs give different content of events).  Another problem is that such an approach would not work on the Macintosh because keyTyped does not fire (see below).  Moving the fixText method in the code below into textValueChanged would lead to endless recursion.

Macintosh JVM: (using Macintosh OS X, Java 1.4.2 and a Wacom Graphire2 tablet):

The TextField shows "x", not the desired display.  The following appears in the Java Console:

textValueChanged:
textValueChanged: x

Only textValueChanged is fired, allowing no simple way to distinguish Tablet events from setText events.  One might imagine using flags to distinguish Tablet events from setText events, but this is a can of worms in a threaded environment.  Moving the fixText method in the code below into textValueChanged would lead to endless recursion.

Summary of events in different platforms:

Event from Tablet   Microsoft JVM (3810)   Sun JVM (1.5 RC)   Mac JVM (1.4.x)
    Fired   Current   Fired   Current   Fired   Current
                         
keyPressed   Yes   --   No   --   No   --
keyReleased   Yes   Yes   No   --   No   --
keyTyped   Yes   Yes   Yes   No   No   --
textValueChanged   Yes   Yes   Yes   Yes   Yes   Yes

Before the advent of Tablet input there was no input device that triggered only textValueChanged events, so distinguishing external input from internal use of setText was not a practical problem.  This has changed and Java programmers must be careful about using Key events in programs.  As shown in the example above, using setText is problematic since it fires textValueChanged.

Is there some way to get some other event from Tablets to allow one to distinguish Tablet input from setText changes?  Is there some flag/counter approach that will work? Or is it necessary to give up using TextField.setText when textValueChanged is used and use alternate approaches such as giving TextField feedback by color and nearby Labels.

If you have any insights, workarounds or comments about this test page please contact Mickey Segal.  A listing of  many Java resources is at this link.

Source code:

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

public class tablet_events3 extends Applet implements ActionListener, KeyListener, TextListener {

TextField textField;

public void init()
{
    setBackground(new Color(225,225, 255));
    textField = new TextField(20);
    textField.addActionListener(this);
    textField.addKeyListener(this);
    textField.addTextListener(this);
    add(textField);
    textField.requestFocus();
}

void fixText()
{
    if (getDoubleFromString(textField.getText()) < -0.01) textField.setText("Error");
}

public void actionPerformed(ActionEvent ae)
{
    System.out.println("actionPerformed: " + textField.getText());
}

public void keyPressed(KeyEvent ke)
{
    System.out.println("keyPressed: " + textField.getText());
}

public void keyReleased(KeyEvent ke)
{
    System.out.println("keyReleased: " + textField.getText());
}

public void keyTyped(KeyEvent ke)
{
    System.out.println("keyTyped: " + textField.getText());
    fixText();
}

public void textValueChanged(TextEvent te)
{
    System.out.println("textValueChanged: " + textField.getText());
}

double getDoubleFromString(String s)
{
    s = s.trim();
    if (s.equals("") || s == null) return (-1.0);
    try
    {
        return (Double.valueOf(s).doubleValue());
    }
    catch (Exception e)
    {
        return(-1.0);
    }
}
} // END OF Class tablet_events3