![]() ![]() |
![]() |
![]() ![]() ![]() ![]() |
![]() |
Swing's support for keyboard UI is designed with the following goals in mind:
The initial Swing release provides some features to reach the first and second goals listed listed under the three first-level bullets above. The goal listed under the third main bullet (advanced automatic focus navigation) will be met in the JDK 1.2 release because it cannot be met without modifying the focus manager.
This document describes a proposal for the two first goals and will be extended in the future to document features covering the goal of advanced automatic focus navigation.
Version 0.4. Last modified 09/04/97.
keyboard support:
The best way to make any Swing-based application usable without a mouse is to make sure that no additional work is required from the application developer to make the application support keyboard UI. This really means that widgets developed in Swing should be able by themselves to negotiate with the system, declaring their favorite keyboard equivalencies and when these keyboard equivalencies are available. For some widgets, such as menus, the application developer will have to define the accelerators that make sense. For widgets such as buttons, the application developer will have to specify which button is the default button. These features are really widget properties and will be easy to handle inside an application builder.
From a widget developer's point of view, it should be very easy to support keyboard input. For a given feature, the code should be the same whether the input device that has triggered the feature is a keyboard or a mouse. This means that the input device that has triggered the feature is hidden from the code that actually implements the feature. One way to do this in Swing is to encapsulate the feature inside a JAction object. JAction objects can also answer the needs of another requirement: It is useful for a keyboard UI system to be able to discover whether a widget can perform an action. If the widget cannot perform the action, perhaps another widget that supports the same combination of keys should perform its action.
Assuming that any feature accessible from the keyboard has been factored into a set of JAction, the last piece of code that should be implemented to drive a widget from the keyboard is the code that actually maps a combination of keys to an action. Since it is possible for a widget to perform an action even if it does not have the focus (think about a keyboard mnemonic or a menu), and because it is desirable to avoid requiring every single widget to provide the same kind of code to check the key event to trigger the right action, a solution is to have a registry system that handles the mapping (keys / components / focused component) -> action.
JComponent provides a set of methods that allows ComponentUI implementers to register and unregister an action for a set of keys. Also JComponent contains the implementation of the keyboard action registry.
The keyboard action registry's responsibility is to know about all the keys that can be handled by a tree of component and to invoke the right action when a set of keys is pressed. When a ComponentUI instance installs its UI, it registers its actions and keys. When the ComponentUI instance removes its UI, it removes its actions. Actual bindings are stored into the JComponent's properties.
Registering an action into the registry looks like this:
registerKeyboardAction(JAction anAction, JKeyStroke aKeyStroke, int aCondition)
The anAction parameter is the action that should be invoked when the proper keys are pressed and aCondition is verified. The aKeyStroke parameter describes the key(s) that will trigger the action. JKeyStroke can store whether keys should be pressed or released for the action to be invoked. The aCondition parameter is an int value that describes when the action should be invoked. Its value can be:
Version 0.4. Last modified 09/04/97.
When an action is invoked, the keyboard registry determines what component should carry out the action by examining components that could handle the action in the following order:
The following pseudo-code illustrates how this sequence of actions takes place:
Input: a KeyEvent KE
If the focused component has some registered actions and one of these registered action A has been registered with (charKey,modifiers) that matches KE, do if A is enabled, invoke A and stop done else for all components C on the path from the focused component's parent to the root of the component tree (both included) do if C has registered an action A with a (charKey,modifiers) that matches KE and a condition equals to WHEN_IN_FOCUSED_WINDOW or ALWAYS do if A is enabled, invoke A and stop done done for all components C in the focused component tree excluding the focused component do if C has registered an action A with a (charCode,modifiers) that matches KE and a condition equals to WHEN_IN_FOCUSED_WINDOW or ALWAYS, do if A is enabled invoke A and stop done done
Finally, if an action A has been registered with a (charCode,modifiers) that matches
KE and a condition equals to ALWAYS if A is enabled invoke A.
The basic idea is that JComponent overloads processKeyEvent() in the following way:
public void processKeyEvent(KeyEvent anEvent) { super.processKeyEvent(anEvent); if(anEvent.isConsumed()) return; /*** Give the keyboard UI registry system a chance to process the key event ***/ if(anEvent.getID() == KeyEvent.KEY_PRESSED) { processKeyBindings(anEvent); } }
It is the responsibility of all ComponentUI objects to mark the event consumed if the event has been consumed.
This is the proposed API for the keyboard registry:
public class JComponent { .... /** Register a new keyboard action. * anAction will be invoked if a key event matching aKeyStroke * occurs and aCondition is verified. aCondition can currently be: * <UL> * <LI> WHEN_FOCUSED: the action will be invoked only when the receiving * JComponent has the focus. * <LI> WHEN_IN_FOCUSED_WINDOW: the action will be invoked when the * receiving JComponent has the focus or is in the window that contains the focused container. * </UL> * If an action has already been registered for the receiving container, with the same key stroke, * anAction will replace the action. */ public void registerKeyboardAction(JAction anAction,JKeyStroke aKeyStroke,int aCondition); /** Unregister a keyboard action given a JKeyStroke **/ public void unregisterKeyboardAction(JKeyStroke aKeyStroke); /** Return the registered key strokes **/ public JKeyStroke[] getRegisteredKeyStrokes(); /** Return the condition that has been registered with a key stroke **/ public int getConditionForKeyStroke(JKeyStroke aKeyStroke); /** Return the action that has been registered with a key stroke **/ public JAction getActionForKeyStroke(JKeyStroke aKeyStroke); /** Unregister all keyboard actions **/ public void resetKeyboardActions(); .... }
The following examples illustrate two ways in which you might use Swing's
keyboard UI:
The first example shows how arrow keys could be used to move the selection in a list box up and down. In the list box's ComponentUI:
void intallUI(JComponent c) { /** Install sub-components **/ ... /** Install event listeners **/ ... /** Install key bindings scrollDownAction and scrollUpAction are defined actions **/ c.registerKeyboardAction(scrollDownAction, JKeyStroke.getKeyStroke(KeyEvent.DOWN, 0), WHEN_FOCUSED); c.registerKeyboardAction(scrollUpAction, JKeyStroke.getKeyStroke(KeyEvent.UP,0), WHEN_FOCUSED); } void deinstallUI(JComponent c) { /** Remove sub-components and event listeners **/ ... /** Remove key bindings **/ c.resetKeyboardActions(); }
In this example, a label needs to know when Control + A is pressed so its associated JTextField can get the focus. In The label's ComponentUI:
void intallUI(JComponent c) { /** Install sub-components **/ ... /** Install event listeners **/ ... /** Install key bindings setFocus is a defined action that causes the associated container to be focused **/ c.registerKeyboarAction(setFocus, JKeyStroke.getKeyStroke('a',InputEvent.CTRL_MASK), WHEN_IN_FOCUSED_WINDOW); } void deinstallUI(JComponent c) { /** Remove sub-components and event listeners **/ ... /** Remove key bindings **/ c.resetKeyboardActions(); }
In the current stage of development, Swing's focus navigation is not implemented or designed . It will require some modifications to the awt package. This feature will be implemented in
Version 0.4. Last modified 09/04/97. Other goals for Keyboard UI development include the following additional
features for the public focus manager:
Version 0.4. Last modified 09/04/97.
Copyright © 1995-97 Sun
Microsystems, Inc. All Rights Reserved.