Generic soft key detection in J2ME

As many of you will be aware, the soft key buttons on mobile phones are general purpose whose purpose change with regard to context. Most popular handsets have two of these directly beneath the screen (one to the left, and one to the right).

In my project I needed to be able to detect when the left and right soft keys are being pressed but unfortunately J2ME does not define a standard key code. Instead it is up to the developer to specify different codes for all of the different phones in their target audience.

Two solutions came to mind:

  1. Compile the application for each target handset.

  2. Get the user to specify which button is which (even if they do not realize this!).

I decided to go with option #2 so that my application would work for the majority of handsets without making the project too difficult to maintain. Instead of directly asking the user to configure the keys, I created a welcome screen.

In addition to a pleasant greeting, the welcome screen has the text “Continue” in the bottom left corner. The user will instinctively press the soft key button that is nearest that text and so the key code is known for the life of the application. I decided to filter out all known keys so that the user does not press the “FIRE” button, etc.

Welcome Screen for J2ME

Once the key code of the left soft key is known, we can assume that any other non-standard button that is pressed is probably the second soft-key.

Note - This means that other unknown buttons will also behave as the 2nd soft key.

Here is a simplified version of the welcome screen that I created:

public class WelcomeCanvas extends Canvas {

    public WelcomeCanvas() {
        setFullScreenMode(true);
    }

    protected void paint(Graphics g) {
        g.setColor(0x336699);
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(0xFFFFFF);
        g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_LARGE));
        g.drawString("Welcome!", getWidth() / 2, getHeight() / 2, Graphics.HCENTER | Graphics.TOP);

        // The all important continue text!
        g.setFont(Font.getDefaultFont());
        g.drawString("Continue", 2, getHeight() - 2, Graphics.BOTTOM | Graphics.LEFT);
    }

    protected void keyPressed(int keyCode) {
        if (!SoftCommandCanvas.isKnownKey(this, keyCode)) {
            SoftCommandCanvas.KEY_SOFT_LEFT = keyCode;
            continuePressed();
        }
    }

    protected void continuePressed() {
        // Do something!
    }

}

Here is an example of how you can then detect which soft key is being pressed in another canvas:

public class SoftCommandCanvas extends Canvas {

    // Assigned by `WelcomeCanvas` upon selecting 'Continue'.
    // The default value here works for Nokia handsets.
    public static int KEY_SOFT_LEFT = -6;

    public SoftCommandCanvas() {
        setFullScreenMode(true);
    }

    public static boolean isKnownKey(Canvas canvas, int keyCode) {
        return (keyCode >= KEY_NUM0 && keyCode <= KEY_NUM9) ||
            keyCode == KEY_POUND || keyCode == KEY_STAR ||
            canvas.getGameAction(keyCode) != 0;
    }

    protected void keyPressed(int keyCode) {
        if (!isKnownKey(this, keyCode)) {
            if (keyCode == KEY_SOFT_LEFT) {
                fireLeftSoftCommand();
            }
            else {
                fireRightSoftCommand();
            }
        }
        else {
            super.keyPressed(keyCode);
        }
    }

    protected void fireLeftSoftCommand() {
        // Do something!
    }

    protected void fireRightSoftCommand() {
        // Do something!
    }

}