|
|
< Day Day Up > |
|
2.2 Keyboard Events and the Focus ControlKeyboard focus is the property that determines the target for keys that the user types. Normally, the control that has focus, called the focus control, receives all keyboard events until focus is assigned to another control. When a control has focus, it often draws in a different manner to give the user a visual cue. For example, a text widget might show a flashing I-beam caret; a list widget might draw a dotted rectangle; and so forth. On some platforms, focus follows the mouse as it moves around the desktop from control to control. Keys go to the control that is under the mouse. On other platforms, the user must explicitly click in (or otherwise select) a control to give it focus. This policy is governed by the window manager and is not something that SWT programs need to worry about. That is, unless you deliberately override the behavior in your application, it will follow whatever the default is for the platform. 2.2.1 Setting the Focus ControlFocus is assigned to a control using Control.setFocus().
You can find out which control has keyboard focus using Display.getFocusControl() (see Getting the Focus Control in the Display chapter).[1]
2.2.2 Forcing Focus to a ControlUnder rare circumstances, you may want to force the keyboard focus to go to a control that does not normally take it. You can do this by calling forceFocus().
One occasion where forceFocus() might be necessary occurs when implementing your own controls. Normally, focus is not assigned to a composite that has children. For example, when focus is in an OK button in a dialog, if the user unintentionally clicks on the parent of the button, focus remains in the button. However, some composites have children and need to take focus themselves. For example, a "notebook" (a control that provides a strip of selectable tabs that are used to switch between pages) might need to take focus when the user clicks on a tab. Notebooks normally have children, one per page. If you were to implement a notebook, instead of using the native control provided by SWT, you would need to force focus to the notebook when the mouse was pressed over a tab. 2.2.3 Focus EventsTable 2.1 shows the focus-related events that are provided by SWT.
The SWT.FocusIn (typed event FocusEvent) and SWT.FocusOut (typed event FocusEvent) events can be used to track focus within a program. Focus events contain meaningful values in only the display, widget, and type fields. Using SWT.FocusIn and SWT.FocusOut to Indicate FocusThe following example uses SWT.FocusIn and SWT.FocusOut to ensure that the class MyControl draws a focus indicator. The implementation of both events simply redraws the control. The SWT.Paint listener checks to see whether the MyControl has focus and draws a focus rectangle.[2] Figure 2.1 shows MyControl with focus in a Shell.
static class MyControl extends Canvas implements Listener {
String string = "";
public MyControl(Composite parent, int style) {
super(parent, style);
addListener(SWT.Paint, this);
addListener(SWT.FocusIn, this);
addListener(SWT.FocusOut, this);
addListener(SWT.KeyDown, this);
}
public void setText(String string) {
checkWidget();
this.string = string == null ? "" : string;
}
public void handleEvent(Event event) {
switch (event.type) {
case SWT.Paint:
GC gc = event.gc;
Rectangle rect = getClientArea();
Point extent = gc.textExtent(string);
int x = (rect.width - extent.x) / 2;
int y = (rect.height - extent.y) / 2;
gc.drawText(string, x, y);
if (isFocusControl()) {
x -= 2; y -=2;
extent.x +=3; extent.y +=3;
gc.drawFocus(x, y, extent.x, extent.y);
}
break;
case SWT.FocusIn:
case SWT.FocusOut:
redraw();
break;
case SWT.KeyDown:
if (event.character == ' ') {
notifyListeners(SWT.Selection, null);
}
break;
}
}
}
Figure 2.1. The CH1a_MyControl example.
2.2.4 Key EventsWhen a key is pressed or released, a key event is normally created and delivered to your application. However, depending on the platform, the locale, and the keystroke, there are circumstances when this does not happen. For example, if the key is an accent character, the operating system key classification engine may temporarily consume it. When a caret character (^) is typed in a German locale followed by an e, the result is the accented character ê. Similarly, key events are not created for the intermediate keystrokes consumed by the IME when preprocessing sequences of keys into single Japanese characters. The reason for this is that these kinds of low-level key events are highly platform-specific and generally not useful to most programs.[3] SWT hides the underlying operating system events and issues a single key event when the operating system has finished classifying the keystroke.[4]
Table 2.2 shows the key events that are provided by SWT.
The SWT.KeyDown (typed event KeyEvent) and SWT.KeyUp (typed event KeyEvent) events represent high-level key presses and key releases. They can be used to implement and intercept key processing. The relevant event fields during SWT.KeyDown and SWT.KeyUp are shown in Table 2.3.
2.2.5 Characters, Key Codes, and State MasksFor key events that represent characters found in the Unicode character set, the character field is set to the matching (Unicode) char value. For example, when the user presses the <a> key, an SWT.KeyDown event is issued. The character field in this event has the (char) value a. Despite the fact that SWT characters are just Java char values, convenience constants are provided for most common control characters, even those that have standard escape sequences (such as '\n' for linefeed). Programmers are free to use the constants (found in Table 2.4) or their equivalents.
The character field in a key event represents the final character value for the keystroke. Any modifier keys, such as <Shift> or <Ctrl>, that were held down when the key was pressed have been applied to the character. For example, when the user presses <Shift> and the <a> key, the character field contains A. Less obvious is the result of pressing <Ctrl> and the <a> key. This gives a Control+A character (with value '\u0001', known as SOH in the Unicode specification). Holding down <Ctrl> and pressing @, a to z, [, \, ], ^, or _ results in the corresponding Unicode control characters in the range '\u0000' to '\u001F'.
The keyCode field in the event is used to represent keystrokes that are not Unicode values. For example, pressing <F4> or <PageUp> causes the keyCode field to contain a corresponding key code value. All possible key code values are defined in the class SWT. For example, the key code value for the <PageUp> key is SWT.PAGE_UP. (There are simply too many constants to list here, see the Javadoc for class SWT for the complete list.) Although, strictly speaking, there are Unicode values to represent almost every kind of key,[5] the character field in the key event is not always assigned. Normally, a key such as <PageUp> is intended to cause an action, not insert a character. Instead of attempting to draw a character, programs use the fact that the character field is unassigned to classify the keystroke.
The keyCode field has one further purpose. If the character field is assigned, the keyCode field is used to represent the key code of the "unaffected" character. For example, the character field will contain the plus character (+) when the <Add> key is pressed. It will also contain the plus when the numeric keypad <Add> key is pressed. Most programs process either <Add> key in the same manner, using the character field. However, some programs might want to differentiate between the two. In this case, the keyCode field will contain SWT.KEYPAD_ADD when the plus character originated from the numeric keypad. The stateMask field is an integer bit-mask that captures that state of the keyboard and mouse immediately prior to the event.[6] This is an important point to understand. For example, at the time the <Shift> key is pressed, the <Shift> key is not down because you are in the process of pressing it. In this case, the stateMask field does not contain the SWT.SHIFT modifier. However, the stateMask will contain the SWT.SHIFT modifier when the next key is pressed because the <Shift> key is down at that time.
Table 2.5 shows the four[7] specific modifier masks supported by SWT.
Modifier masks are also used to represent keystrokes when the modifier keys themselves are pressed. For example, when the user presses the <Shift> key and nothing else, a key down event is generated with the character field set to '\u0000', the keyCode field set to SWT.SHIFT, and the stateMask field set to zero. If the user were now to press the <a> key, another key event would be generated. This new event would have the character field set to A and the stateMask field set to SWT.SHIFT. This can be a little bit confusing at first because the same constant (SWT.SHIFT) is used to serve two different purposes in the two fields. The specific modifier keys and state masks can be tricky to use portably. Most keyboards contain at least the <Shift>, <Ctrl>, and <Alt> keys but some platforms use more than just these three. To make things more complicated, platform-specific conventions exist that dictate which modifier keys should be used. For example, on the Macintosh, users expect to type Command+C to copy text to the clipboard. On Windows, the equivalent key combination is Control+C. Although it is possible to write code on a Macintosh that deliberately uses Control+C to copy text, any application that does this would be frustrating to use and would definitely not match the Macintosh user interface guidelines. To solve this problem, SWT defines the generic modifier masks shown in Table 2.6.
These generic modifier masks are initialized when SWT starts up on each platform. For example, SWT.MOD1 is set to SWT.CONTROL on Windows and to SWT.COMMAND on the Macintosh. It is important to note that expecting to process a modifier key on a platform where the modifier does not exist is futile. For example, the SWT.COMMAND key can never be pressed on Windows because it does not exist on the keyboard. The constant SWT.MODIFIER_MASK contains every valid modifier. It is generally used to test for an unmodified key. This constant ensures that when new modifier keys are added to SWT, code that tests for unmodified keys (or a key that is modified in any way) will continue to work. The following code fragment illustrates this point.
//WRONG – broken when new modifier masks are added
int bits = SWT.CONTROL | SWT.ALT | SWT.SHIFT | SWT.COMMAND;
if ((event.stateMask & bits) == 0) {
System.out.println("No modifiers are down");
}
//CORRECT – works when new modifier masks are added
if ((event.stateMask & SWT.MODIFIER_MASK) == 0) {
System.out.println("No modifiers are down");
}
2.2.6 Using SWT.KeyDown to Print Key EventsThe following program listens for key up and key down events and prints the stateMask, keyCode, and character values as keys are typed.
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
Listener listener = new Listener() {
public void handleEvent(Event event) {
String string =
event.type == SWT.KeyDown ? "DOWN": "UP ";
string += ": stateMask=0x"
+ Integer.toHexString(event.stateMask);
if ((event.stateMask & SWT.CTRL) != 0)
string += " CTRL";
if ((event.stateMask & SWT.ALT) != 0)
string += " ALT";
if ((event.stateMask & SWT.SHIFT) != 0)
string += " SHIFT";
if ((event.stateMask & SWT.COMMAND) != 0)
string += " COMMAND";
string += ", keyCode=0x"
+ Integer.toHexString(event.keyCode);
string += ", character=0x"
+ Integer.toHexString(event.character);
switch (event.character) {
case 0: string += " '\\0'"; break;
case SWT.BS: string += " '\\b'"; break;
case SWT.CR: string += " '\\r'"; break;
case SWT.DEL: string += " DEL"; break;
case SWT.ESC: string += " ESC"; break;
case SWT.LF: string += " '\\n'"; break;
case SWT.TAB: string += " '\\t'";
break;
default:
string += " '" + event.character + "'";
break;
}
System.out.println(string);
}
};
shell.addListener(SWT.KeyDown, listener);
shell.addListener(SWT.KeyUp, listener);
shell.setSize(200, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
Using SWT.KeyDown to Consume KeysOccasionally under rare circumstances, it is necessary to consume key events before they are processed by a control. Because SWT is implemented using native controls, most of the processing behind each keystroke occurs in the operating system. For example, when the user types in a text control, the code that inserts and draws the characters runs in the operating system after the SWT.KeyDown listeners return. Using the doit field, you can consume the keystroke and stop the operating system from processing the character. The following example prevents the user from entering characters in a native text control by setting the doit field to false for every SWT.KeyDown event.
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
Text text = new Text(shell, SWT.SINGLE | SWT.BORDER);
text.addListener(SWT.KeyDown, new Listener() {
public void handleEvent(Event event) {
event.doit = false;
}
});
text.pack();
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
Sometimes programmers mistakenly attempt to use this feature to implement input validation for text controls. This is unnecessary and prone to error.[9] Input validation is provided in a platform-independent and portable manner for text controls using the SWT.Verify event (see Class Text in the Basic Controls chapter).
Note that setting the doit field to false will not stop the processing of keystrokes when this happens outside of the operating system, for example, in another SWT.KeyDown listener on the same control. In this case, because nothing is done with the keystroke in the operating system, there is nothing to cancel (although it is not harmful to set doit to false). A further problem arises when your listener is added after the other SWT.KeyDown listeners for the control. It runs after the processing has already happened. To solve this problem and intercept and cancel all key processing, no matter where and how the actual work is done, event filters can be used (see Event Filters in the Display chapter). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
< Day Day Up > |
|