Google+ Badge

Thursday, September 6, 2012

Convert Numeric keypad [ENTER] to [TAB] in java

Our data entry staff does a lot of numeric entry. Java uses the [TAB] key to move between entry fields. I was asked if we could have the NumPad [ENTER] key act like the [TAB] key greatly speeding up data entry. I was able to pull it off with a little bit of code.


import java.awt.AWTEvent;
import java.awt.AWTException;
import java.awt.EventQueue;
import java.awt.Robot;
import java.awt.event.KeyEvent;

/**
 * Special event queue to convert NUMPAD + ENTER into TAB
 *
 * @author kevin.peck
 * @date Sep 4, 2012
 */
public class CustomEventQueue extends EventQueue {
    private Robot robot;
    private boolean swapKeys;

    /**
     * Constructor
     *
     * Get robot running so we can fake key events
     */
    public CustomEventQueue() {
        super();
        try {
            robot = new Robot();
        } catch (AWTException e) {
            System.out.println("Unable to get robot running " + e);
        }
    }

    /**
     * @param swapKeys  true to force key swap processing
     */
    public void setSwapKeys(boolean swapKeys) {
        this.swapKeys = swapKeys;
    }

    /**
     * @return  true if we are doing key swap processing
     */
    public boolean areKeysSwapped() {
        return swapKeys;
    }

    /**
     * Watch for keyevents and convert NUMPAD ENTER key into TAB key
     */
    @Override
    protected void dispatchEvent(AWTEvent event) {
        if (swapKeys && event instanceof KeyEvent) {
            KeyEvent keyEvent = (KeyEvent)event;
            if (keyEvent.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD && keyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
                if (keyEvent.getID() == KeyEvent.KEY_PRESSED) {
                    robot.keyPress(KeyEvent.VK_TAB);
                    robot.keyRelease(KeyEvent.VK_TAB);
                }
                return;
            }
        }
        super.dispatchEvent(event);
    }
}

Add this to your main code (class derived from JFrame)
    private CustomEventQueue eventQueue = new CustomEventQueue();

Add this to the constructor or initialization routine of the class derived from JFrame
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                EventQueue ev = Toolkit.getDefaultToolkit().getSystemEventQueue();
                eventQueue.setSwapKeys(true);
                ev.push(eventQueue);
            }
        });

Why is there a setSwapKeys() method? So you can turn off this functionality. I set enabled the sample above but in my code it is actually reading a Preference setting. You can enable / disable the [ENTER] = [TAB] at any time in your code by invoking the swap keys method.

If swap keys is enabled I eat the VK_ENTER from the numeric keypad for both PRESSED and RELEASED events. I use the Robot object to send out a VK_TAB press and release on the PRESSED event. Nothing is sent on the VK_ENTER RELEASED event. 

Why am I installing the queue invokeLater? I was not doing that an it ran just fine on Java 1.7 but on Java 1.6 I would get an exception. Putting it on the EDT solved that issue.

So far it seems to be working like a champ. With minimal modifications you can watch for any event you need to perform special actions. Don't go crazy but have fun.