Handling Keyboard Events
Keyboard events are represented by the class wxKeyEvent. There are three different kinds of keyboard events in wxWidgets: key down, key up, and character. Key down and up events are untranslated events, whereas character events are translated, which we'll explain shortly. If the key is held down, you will typically get many down events but only one up event, so don't assume that one up event corresponds to each down event.To receive key events, your window needs to have the keyboard focus, which you can achieve by calling wxWindow::SetFocusfor example, when a mouse button is pressed.Table 6-2 lists the three keyboard event table macros.
EVT_KEY_DOWN(func) | Handles a wxEVT_KEY_DOWN event (untranslated key press). |
EVT_KEY_UP(func) | Handles a wxEVT_KEY_UP event (untranslated key release). |
EVT_CHAR(func) | Handles a wxEVT_CHAR event (translated key press). |
WXK_BACK | WXK_RIGHT |
WXK_TAB | WXK_DOWN |
WXK_RETURN | WXK_SELECT |
WXK_ESCAPE | WXK_PRINT |
WXK_SPACE | WXK_EXECUTE |
WXK_DELETE | WXK_SNAPSHOT |
WXK_INSERT | |
WXK_START | WXK_HELP |
WXK_LBUTTON | |
WXK_RBUTTON | WXK_NUMPAD0 |
WXK_CANCEL | WXK_NUMPAD1 |
WXK_MBUTTON | WXK_NUMPAD2 |
WXK_CLEAR | WXK_NUMPAD3 |
WXK_SHIFT | WXK_NUMPAD4 |
WXK_CONTROL | WXK_NUMPAD5 |
WXK_MENU | WXK_NUMPAD6 |
WXK_PAUSE | WXK_NUMPAD7 |
WXK_CAPITAL | WXK_NUMPAD8 |
WXK_PRIOR | WXK_NUMPAD9 |
WXK_NEXT | |
WXK_END | WXK_MULTIPLY |
WXK_HOME | WXK_ADD |
WXK_LEFT | WXK_SEPARATOR |
WXK_UP | WXK_SUBTRACT |
WXK_DECIMAL | WXK_PAGEDOWN |
WXK_DIVIDE | |
WXK_NUMPAD_SPACE | |
WXK_F1 | WXK_NUMPAD_TAB |
WXK_F2 | WXK_NUMPAD_ENTER |
WXK_F3 WXK_F4 | WXK_NUMPAD_F1 |
WXK_F5 | WXK_NUMPAD_F2 |
WXK_F6 | WXK_NUMPAD_F3 |
WXK_F7 | WXK_NUMPAD_F4 |
WXK_F8 | WXK_NUMPAD_HOME |
WXK_F9 | WXK_NUMPAD_LEFT |
WXK_F10 | WXK_NUMPAD_UP |
WXK_F11 | WXK_NUMPAD_RIGHT |
WXK_F12 | WXK_NUMPAD_DOWN |
WXK_F13 | WXK_NUMPAD_PRIOR |
WXK_F14 | WXK_NUMPAD_PAGEUP |
WXK_F15 | WXK_NUMPAD_NEXT |
WXK_F16 | WXK_NUMPAD_PAGEDOWN |
WXK_F17 | WXK_NUMPAD_END |
WXK_F18 | WXK_NUMPAD_BEGIN |
WXK_F19 | WXK_NUMPAD_INSERT |
WXK_F20 | WXK_NUMPAD_DELETE |
WXK_F21 | WXK_NUMPAD_EQUAL |
WXK_F22 | WXK_NUMPAD_MULTIPLY |
WXK_F23 | WXK_NUMPAD_ADD |
WXK_F24 | WXK_NUMPAD_SEPARATOR |
WXK_NUMPAD_SUBTRACT | |
WXK_NUMLOCK | WXK_NUMPAD_DECIMAL |
WXK_SCROLL | WXK_NUMPAD_DIVIDE |
WXK_PAGEUP |
An Example Character Event Handler
Here's the key handler from the wxThumbnailCtrl sample that you can find in examples/chap12/thumbnail on the CD-ROM:
For clarity, the navigation key handling is delegated to a separate function, Navigate. Pressing the Return or Enter key generates a higher-level command event that an application using the control can catch; for all other key presses, Skip is called to enable other parts of the application to process unused key events.
BEGIN_EVENT_TABLE( wxThumbnailCtrl, wxScrolledWindow )
EVT_CHAR(wxThumbnailCtrl::OnChar)
END_EVENT_TABLE()
void wxThumbnailCtrl::OnChar(wxKeyEvent& event)
{
int flags = 0;
if (event.ControlDown())
flags |= wxTHUMBNAIL_CTRL_DOWN;
if (event.ShiftDown())
flags |= wxTHUMBNAIL_SHIFT_DOWN;
if (event.AltDown())
flags |= wxTHUMBNAIL_ALT_DOWN;
if (event.GetKeyCode() == WXK_LEFT ||
event.GetKeyCode() == WXK_RIGHT ||
event.GetKeyCode() == WXK_UP ||
event.GetKeyCode() == WXK_DOWN ||
event.GetKeyCode() == WXK_HOME ||
event.GetKeyCode() == WXK_PAGEUP ||
event.GetKeyCode() == WXK_PAGEDOWN ||
event.GetKeyCode() == WXK_PRIOR ||
event.GetKeyCode() == WXK_NEXT ||
event.GetKeyCode() == WXK_END)
{
Navigate(event.GetKeyCode(), flags);
}
else if (event.GetKeyCode() == WXK_RETURN)
{
wxThumbnailEvent cmdEvent(
wxEVT_COMMAND_THUMBNAIL_RETURN,
GetId());
cmdEvent.SetEventObject(this);
cmdEvent.SetFlags(flags);
GetEventHandler()->ProcessEvent(cmdEvent);
}
else
event.Skip();
}
Key Code Translation
Key events provide untranslated key codes, whereas the character event provides a translated key code. The untranslated code for alphanumeric keys is always an uppercase value. For the other keys, it is one of the WXK_XXX values from the keycodes table. The translated key is, in general, the character the user expects to appear as the result of the key combination when typing text into a text entry field.Here are a few examples to clarify this. When the A key is pressed, the key down event key code is equal to ASCII "A" (65), but the character event key code is ASCII A (97). On the other hand, if you press both the Shift and A keys simultaneously, the key code in the key down event will still be A, while the character event key code will now be A as well.In this simple case, it is clear that the ASCII code could be found in the key down event handler by checking both the untranslated key code and the value returned by ShiftDown. But in general, if you want the ASCII key code, you should use the character event (with EVT_CHAR) because for non-alphanumeric keys, the translation is dependent on keyboard layout and can only be done properly by the system itself.Another kind of translation is done when the Control key is pressed: for example, for Ctrl+A, the key down event still passes the same key code A as usual, but the character event will have a key code of 1, which is the ASCII value of this key combination.You may discover how the other keys on your system behave interactively by running the keyboard sample (samples/keyboard) and pressing keys.
Modifier Key Variations
On Windows, there are Control and Alt modifier keys, and the special Windows key acts as the Meta key. On Unix, the key that acts as Meta is configurable (run xmodmap to see how your system is configured). The Numlock key is sometimes configured as a Meta key, and this is the reason HasModifiers does not return true if the Meta key is downthis allows key presses to be processed normally when Numlock is on.Control
Control | Control | Control | |||||||
Alt | Alt | Alt | Option | ![]() | Meta | Windows | (Configurable) | Command | ![]() |
Accelerators
An accelerator implements a keyboard shortcut for a menu command, enabling the user to execute that command quickly. These shortcuts take precedence over other keyboard processing, such as EVT_CHAR handlers. Standard shortcuts include Ctrl+O to open a file and Ctrl+V to paste data into the application. The easiest way to implement accelerators is to specify them in menu items. For example:
wxWidgets interprets the text after the "tab" character as an accelerator and adds it to the menu's accelerator table. In this example, when the user presses Ctrl+C the wxID_COPY command is sent, just as though the menu item was selected.You can use Ctrl, Alt, or Shift in various combinations, followed by a + or - and a character or function key. The following are all valid accelerator specifications: Ctrl+B, G, Shift-Alt-K, F9, Ctrl+F3, Esc, and Del. You can use the following special key names: Del, Back, Ins, Insert, Enter, Return, PgUp, PgDn, Left, Right, Up, Down, Home, End, Space, Tab, Esc, and Escape. Case is not significant when interpreting the names (any combination of uppercase and lowercase will work).Note that on Mac OS X, a shortcut specification involving Ctrl will actually use the Command key.Another way to provide accelerators is to populate an wxAccelerator Table with wxAcceleratorEntry objects and associate it with a window using wxWindow::SetAcceleratorTable. Each wxAcceleratorEntry is initialized with a bit-list of modifiers (one or more of wxACCEL_ALT, wxACCEL_CTRL, wxACCEL_SHIFT, and wxACCEL_NORMAL), a key code (see Table 6-3), and an identifier. For example:
menu->Append(wxID_COPY, wxT("Copy\tCtrl+C"));
You can use several accelerator tables in a window hierarchy, and you can combine menu string accelerator specifications with an explicit wxAcceleratorTable. This is useful if you have alternative accelerators for a single command, which you cannot entirely specify in the menu item label.
wxAcceleratorEntry entries[4];
entries[0].Set(wxACCEL_CTRL, (int) 'N', wxID_NEW);
entries[1].Set(wxACCEL_CTRL, (int) 'X', wxID_EXIT);
entries[2].Set(wxACCEL_SHIFT, (int) 'A', wxID_ABOUT);
entries[3].Set(wxACCEL_NORMAL, WXK_DELETE, wxID_CUT);
wxAcceleratorTable accel(4, entries);
frame->SetAcceleratorTable(accel);