Pen Events in Mac OS X

(version #3 with KeyListener and TextListener; documents Macintosh bug report ID#: 3093653)

A Java applet should appear below as a purple box.  

Inkwell generates only TextEvent when inserting text into a Java TextField

* SUMMARY
Jaguar's Inkwell handwriting recognition software generates only TextEvents when inserting text into Java TextField.  This is a problem since many programs written for keyboard and mouse will fail to work properly unless rewritten extensively.  The approach used on the Microsoft JVM, where KeyEvents and TextEvents are generated for each character in the inserted string, appears to be superior for compatibility with keyboard/mouse based programs.

* STEPS TO REPRODUCE
1. Connect a graphics tablet such as a Wacom Graphire2 to an OS 10.2+ computer and install the tablet. 
2. In Inkwell, choose the "Allow me to write anywhere" option and turn "Handwriting recognition" on. 
3. Run the applet shown here.
4. In the applet, activate the TextField, and using the stylus write more than one letter into the yellow text writing area that pops up. Allow this to be inserted into the TextField.

* RESULTS
1. Looking in the Java Console (or the system Console as appropriate) the events received from the text writing are logged. TextEvents are generated, but no ActionEvents or KeyEvents are generated. This is a problem because many existing programs are written to process KeyEvents in keyReleased and ActionEvents in actionPerformed but do not have code for TextEvents.  Although one could rewrite programs to put code for TextEvents into textValueChanged methods, that would require non-trivial modifications in many programs, since for example, code in keyReleased often uses  KeyEvent.getKeyCode() for which there is no equivalent for TextEvents.  Such code changes are non-trivial since any code written for TextEvents would also be executed after any KeyEvent since KeyEvents cause TextEvents.

This problem could be solved by adding ActionEvents for each act of inputting from Inkwell to a TextField, but some programmers think pressing a Return key should not be implied. 

One solution is to adopt the hack used by Windows XP Tablet Edition of generating KeyEvents as well as the TextEvents for pen input.  This solution offers great compatibility with the OS that most will use to test Ink input.  Another workaround is to urge users to add a "Return" gesture in their Inkwell writings (this gesture is confusingly labeled "vertical space" in OS 10.2.1).  

These issues would become very important if Apple uses the inkwell functionality for a tablet computer.

2. In version 1.3, many of the characters written do not make it into the TextField. For 26 characters written the first 13 make it. For 2 characters written, the first one character makes it. For one character written, an Exception is generated. 

Testing on Sun Java 1.5 on Windows XP Tablet 2005 reveals that Sun has taken a similar approach of not providing KeyEvents, so programmers will need to re-write their code for this environment.  However, some problems arise even when trying to rewrite code to use textValueChanged.

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


The source code is shown below and can be downloaded from the link: PenTablet.java

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

public class PenTablet extends Applet implements ActionListener, KeyListener, ItemListener, 
TextListener {

TextField textField;
Choice choice;
Label textFieldLabel, choiceLabel;

public void init() 
{
    setBackground(new Color(225,225, 255));
    textField = new TextField("Initial"); 
    textField.addActionListener(this);
    textField.addKeyListener(this);
    textField.addTextListener(this);
    add(textField);
    textFieldLabel = new Label("Initial");
    add(textFieldLabel);
    choice = new Choice();
    choice.addItem("First ");
    choice.addItem("Second ");
    choice.addItem("Third ");
    choice.addItemListener(this);
    add(choice);
    choiceLabel = new Label("First ");
    add(choiceLabel);
}

void refreshTextFieldLabel()
{
    textFieldLabel.setText(textField.getText());
    textFieldLabel.invalidate();
    invalidate();
    validate();
}

public void actionPerformed(ActionEvent ae)
{
    System.out.println("Action");
    if (ae.getSource() == textField) refreshTextFieldLabel();
}

public void keyPressed(KeyEvent ke){}

public void keyReleased(KeyEvent ke)
{
    System.out.println("Key");
    refreshTextFieldLabel();
}

public void textValueChanged(TextEvent te)
{
    System.out.println("Text");
    refreshTextFieldLabel();
}

public void keyTyped(KeyEvent ke){}

public void itemStateChanged(ItemEvent ie)
{
    System.out.println("Item");
    if (ie.getSource() == choice)
    {
        choiceLabel.setText(choice.getItem(choice.getSelectedIndex()));
        choiceLabel.invalidate();
        invalidate();
        validate();
    }
}
} // END OF Class PenTablet