9.4. Shortcut Keys

Shortcut keys can be defined as actions using the ShortcutAction class. To handle key presses, you need to define an action handler by implementing the Handler interface. The interface has two methods that you need to implement: getActions() and handleAction().

The getActions() interface method must return an array of Action objects for the component specified with the second parameter for the method, the sender of an action. For a keyboard shortcut, you use a ShortcutAction. The implementation of the method should look somewhat as follows:

    public Action[] getActions(Object target, Object sender) {
        Action[] actions = new Action[1];

        // Set the action for the requested component 
        if (sender == ok) {
            // Bind the unmodified Enter key to the Ok button. 
            actions[0] = new ShortcutAction("Default key",
                                            ShortcutAction.KeyCode.ENTER, null);
        } else if (sender == cancel) {
            // Bind "C" key modified with Alt to the Cancel button.
            actions[0] = new ShortcutAction("Alt+C",
                                            ShortcutAction.KeyCode.C, new int[] {
                                                   ShortcutAction.ModifierKey.ALT});
        } else
            return null;
        return actions;
    }

The method takes a symbolic caption for the action; this is largely irrelevant for shortcut actions. The second parameter is the keycode, as defined in ShortcutAction.KeyCode interface. Currently, the following keycodes are allowed:

Keys A to Z
Normal letter keys
F1 to F12

Function keys

BACKSPACE, DELETE, ENTER, ESCAPE, INSERT, TAB

Control keys

NUM0 to NUM9

Number pad keys

ARROW_DOWN, ARROW_UP, ARROW_LEFT, ARROW_RIGHT

Arrow keys

HOME, END, PAGE_UP, PAGE_DOWN

Other movement keys

The third parameter is an array of modifier keys, as defined in the ShortcutAction.ModifierKey interface. The following modifier keys are allowed: ALT, CTRL, and SHIFT. The modifier keys can be combined; for example, the following defines shortcut key combination Ctrl-Shift-S:

ShortcutAction("Ctrl+Shift+S",
               ShortcutAction.KeyCode.S, new int[] {
                      ShortcutAction.ModifierKey.CTRL,
                      ShortcutAction.ModifierKey.SHIFT});

The following example demonstrates the definition of a default button for a user interface, as well as a normal shortcut key, Alt-C for clicking the Cancel button.

import com.itmill.toolkit.event.Action;
import com.itmill.toolkit.event.ShortcutAction;
import com.itmill.toolkit.event.Action.Handler;
import com.itmill.toolkit.ui.*;

public class DefaultButtonExample extends CustomComponent implements Handler {
    // Define and create user interface components
    Panel            panel      = new Panel("Login");
    VerticalLayout   formlayout = new VerticalLayout();
    TextField        username   = new TextField("Username");
    TextField        password   = new TextField("Password");
    HorizontalLayout buttons    = new HorizontalLayout();
    
    // Create buttons and define their listener methods. Here we use parameterless
    // methods so that we can use same methods for both click events and keyboard
    // actions.
    Button        ok         = new Button("OK", this, "okHandler");
    Button        cancel     = new Button("Cancel", this, "cancelHandler");

    public DefaultButtonExample() {
        // Set up the user interface
        setCompositionRoot(panel);
        panel.addComponent(formlayout);
        formlayout.addComponent(username);
        formlayout.addComponent(password);
        formlayout.setStyle("form");
        formlayout.addComponent(buttons);
        buttons.addComponent(ok);
        buttons.addComponent(cancel);
        
        // Set focus to username
        username.focus();
        
        // Set this object as the action handler for actions related to the Ok
        // and Cancel buttons.
        ok.addActionHandler(this);
        cancel.addActionHandler(this);
    }

    /**
     * Retrieve actions for a specific component. This method will be called for each
     * object that has a handler; in this example the Ok and Cancel buttons.
     **/
    public Action[] getActions(Object target, Object sender) {
        Action[] actions = new Action[1];

        // Set the action for the requested component 
        if (sender == ok) {
            // Bind the unmodified Enter key to the Ok button. 
            actions[0] = new ShortcutAction("Default key",
                                            ShortcutAction.KeyCode.ENTER, null);
        } else if (sender == cancel) {
            // Bind "C" key modified with Alt to the Cancel button.
            actions[0] = new ShortcutAction("Alt+C",
                                            ShortcutAction.KeyCode.C, new int[] {
                                                   ShortcutAction.ModifierKey.ALT});
        } else
            return null;
        return actions;
    }

    /**
     * Handle actions received from keyboard. This simply directs the actions to
     * the same listener methods that are called with ButtonClick events.
     **/
    public void handleAction(Action action, Object sender, Object target) {
        if (target == ok)
            this.okHandler();
        if (target == cancel)
            this.cancelHandler();
    }

    public void okHandler() {
        // Do something: report the click
        formlayout.addComponent(new Label("OK clicked"));
    }

    public void cancelHandler() {
        // Do something: report the click
        formlayout.addComponent(new Label("Cancel clicked"));
    }
}

Notice that the keyboard actions are handled from the entire page. This can cause problems if you have components that require a certain key. For example, multi-line TextField requires the Enter key. There is currently no way to filter the shortcut actions out while the focus is inside some specific component, so you need to avoid such conflicts.