Don't eagerly set wxKeyEvent position fields.
[wxWidgets.git] / samples / keyboard / keyboard.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: keyboard.cpp
3 // Purpose: Keyboard wxWidgets sample
4 // Author: Vadim Zeitlin
5 // Modified by: Marcin Wojdyr
6 // Created: 07.04.02
7 // RCS-ID: $Id$
8 // Copyright: (c) 2002 Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17 #ifndef WX_PRECOMP
18 #include "wx/wx.h"
19 #endif
20
21 #ifndef wxHAS_IMAGES_IN_RESOURCES
22 #include "../sample.xpm"
23 #endif
24
25 // Define a new frame type: this is going to be our main frame
26 class MyFrame : public wxFrame
27 {
28 public:
29 MyFrame(const wxString& title);
30
31 private:
32 // event handlers
33 void OnQuit(wxCommandEvent& WXUNUSED(event)) { Close(true); }
34 void OnAbout(wxCommandEvent& event);
35
36 void OnTestAccelA(wxCommandEvent& WXUNUSED(event))
37 { m_logText->AppendText("Test accelerator \"A\" used.\n"); }
38 void OnTestAccelCtrlA(wxCommandEvent& WXUNUSED(event))
39 { m_logText->AppendText("Test accelerator \"Ctrl-A\" used.\n"); }
40 void OnTestAccelEsc(wxCommandEvent& WXUNUSED(event))
41 { m_logText->AppendText("Test accelerator \"Esc\" used.\n"); }
42
43 void OnClear(wxCommandEvent& WXUNUSED(event)) { m_logText->Clear(); }
44 void OnSkipDown(wxCommandEvent& event) { m_skipDown = event.IsChecked(); }
45 void OnSkipHook(wxCommandEvent& event) { m_skipHook = event.IsChecked(); }
46
47 void OnKeyDown(wxKeyEvent& event)
48 {
49 LogEvent("KeyDown", event);
50 if ( m_skipDown )
51 event.Skip();
52 }
53 void OnKeyUp(wxKeyEvent& event) { LogEvent("KeyUp", event); }
54 void OnChar(wxKeyEvent& event) { LogEvent("Char", event); }
55 void OnCharHook(wxKeyEvent& event)
56 {
57 LogEvent("Hook", event);
58 if ( m_skipHook )
59 event.Skip();
60 }
61
62 void OnPaintInputWin(wxPaintEvent& event);
63
64 void LogEvent(const wxString& name, wxKeyEvent& event);
65
66 wxTextCtrl *m_logText;
67 wxWindow *m_inputWin;
68 bool m_skipHook,
69 m_skipDown;
70 };
71
72
73 // Define a new application type, each program should derive a class from wxApp
74 class MyApp : public wxApp
75 {
76 public:
77 // 'Main program' equivalent: the program execution "starts" here
78 virtual bool OnInit()
79 {
80 // create the main application window
81 new MyFrame("Keyboard wxWidgets App");
82
83 // If we returned false here, the application would exit immediately.
84 return true;
85 }
86 };
87
88 // Create a new application object: this macro will allow wxWidgets to create
89 // the application object during program execution (it's better than using a
90 // static object for many reasons) and also declares the accessor function
91 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
92 // not wxApp)
93 IMPLEMENT_APP(MyApp)
94
95
96 // ============================================================================
97 // implementation
98 // ============================================================================
99
100 // frame constructor
101 MyFrame::MyFrame(const wxString& title)
102 : wxFrame(NULL, wxID_ANY, title),
103 m_inputWin(NULL),
104 m_skipHook(true),
105 m_skipDown(true)
106 {
107 SetIcon(wxICON(sample));
108
109 // IDs for menu items
110 enum
111 {
112 QuitID = wxID_EXIT,
113 ClearID = wxID_CLEAR,
114 SkipHook = 100,
115 SkipDown,
116 TestAccelA,
117 TestAccelCtrlA,
118 TestAccelEsc
119 };
120
121 // create a menu bar
122 wxMenu *menuFile = new wxMenu;
123
124 menuFile->Append(ClearID, "&Clear log\tCtrl-L");
125 menuFile->AppendSeparator();
126
127 menuFile->Append(TestAccelA, "Test accelerator &1\tA");
128 menuFile->Append(TestAccelCtrlA, "Test accelerator &2\tCtrl-A");
129 menuFile->Append(TestAccelEsc, "Test accelerator &3\tEsc");
130 menuFile->AppendSeparator();
131
132 menuFile->AppendCheckItem(SkipHook, "Skip CHAR_HOOK event",
133 "Not skipping this event disables both KEY_DOWN and CHAR events"
134 );
135 menuFile->Check(SkipHook, true);
136 menuFile->AppendCheckItem(SkipDown, "Skip KEY_DOWN event",
137 "Not skipping this event disables CHAR event generation"
138 );
139 menuFile->Check(SkipDown, true);
140 menuFile->AppendSeparator();
141
142 menuFile->Append(QuitID, "E&xit\tAlt-X", "Quit this program");
143
144 // the "About" item should be in the help menu
145 wxMenu *menuHelp = new wxMenu;
146 menuHelp->Append(wxID_ABOUT, "&About\tF1", "Show about dialog");
147
148 // now append the freshly created menu to the menu bar...
149 wxMenuBar *menuBar = new wxMenuBar();
150 menuBar->Append(menuFile, "&File");
151 menuBar->Append(menuHelp, "&Help");
152
153 // ... and attach this menu bar to the frame
154 SetMenuBar(menuBar);
155
156 m_inputWin = new wxWindow(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 50),
157 wxRAISED_BORDER);
158 m_inputWin->SetBackgroundColour(*wxBLUE);
159
160 wxTextCtrl *headerText = new wxTextCtrl(this, wxID_ANY, "",
161 wxDefaultPosition, wxDefaultSize,
162 wxTE_READONLY);
163 headerText->SetValue(
164 " event key KeyCode mod UnicodeKey "
165 " RawKeyCode RawKeyFlags Position");
166
167
168 m_logText = new wxTextCtrl(this, wxID_ANY, "",
169 wxDefaultPosition, wxDefaultSize,
170 wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL);
171
172 // set monospace font to have output in nice columns
173 wxFont font(10, wxFONTFAMILY_TELETYPE,
174 wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
175 headerText->SetFont(font);
176 m_logText->SetFont(font);
177
178 // layout
179 wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
180 sizer->Add(m_inputWin, wxSizerFlags().Expand());
181 sizer->Add(headerText, wxSizerFlags().Expand());
182 sizer->Add(m_logText, wxSizerFlags(1).Expand());
183 SetSizerAndFit(sizer);
184
185 // set size and position on screen
186 SetSize(700, 340);
187 CentreOnScreen();
188
189 // connect menu event handlers
190
191 Connect(QuitID, wxEVT_COMMAND_MENU_SELECTED,
192 wxCommandEventHandler(MyFrame::OnQuit));
193
194 Connect(wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED,
195 wxCommandEventHandler(MyFrame::OnAbout));
196
197 Connect(ClearID, wxEVT_COMMAND_MENU_SELECTED,
198 wxCommandEventHandler(MyFrame::OnClear));
199
200 Connect(SkipHook, wxEVT_COMMAND_MENU_SELECTED,
201 wxCommandEventHandler(MyFrame::OnSkipHook));
202 Connect(SkipDown, wxEVT_COMMAND_MENU_SELECTED,
203 wxCommandEventHandler(MyFrame::OnSkipDown));
204
205 Connect(TestAccelA, wxEVT_COMMAND_MENU_SELECTED,
206 wxCommandEventHandler(MyFrame::OnTestAccelA));
207
208 Connect(TestAccelCtrlA, wxEVT_COMMAND_MENU_SELECTED,
209 wxCommandEventHandler(MyFrame::OnTestAccelCtrlA));
210
211 Connect(TestAccelEsc, wxEVT_COMMAND_MENU_SELECTED,
212 wxCommandEventHandler(MyFrame::OnTestAccelEsc));
213
214 // connect event handlers for the blue input window
215 m_inputWin->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MyFrame::OnKeyDown),
216 NULL, this);
217 m_inputWin->Connect(wxEVT_KEY_UP, wxKeyEventHandler(MyFrame::OnKeyUp),
218 NULL, this);
219 m_inputWin->Connect(wxEVT_CHAR, wxKeyEventHandler(MyFrame::OnChar),
220 NULL, this);
221 m_inputWin->Connect(wxEVT_PAINT,
222 wxPaintEventHandler(MyFrame::OnPaintInputWin),
223 NULL, this);
224
225 // notice that we don't connect OnCharHook() to the input window, unlike
226 // the usual key events this one is propagated upwards
227 Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(MyFrame::OnCharHook));
228
229 // status bar is useful for showing the menu items help strings
230 CreateStatusBar();
231
232 // and show itself (the frames, unlike simple controls, are not shown when
233 // created initially)
234 Show(true);
235 }
236
237 // event handlers
238
239 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
240 {
241 wxMessageBox("Demonstrates keyboard event processing in wxWidgets\n"
242 "(c) 2002 Vadim Zeitlin\n"
243 "(c) 2008 Marcin Wojdyr",
244 "About wxWidgets Keyboard Sample",
245 wxOK | wxICON_INFORMATION, this);
246 }
247
248 void MyFrame::OnPaintInputWin(wxPaintEvent& WXUNUSED(event))
249 {
250 wxPaintDC dc(m_inputWin);
251 dc.SetTextForeground(*wxWHITE);
252 wxFont font(*wxSWISS_FONT);
253 font.SetWeight(wxFONTWEIGHT_BOLD);
254 font.SetPointSize(font.GetPointSize() + 2);
255 dc.SetFont(font);
256
257 dc.DrawLabel("Press keys here",
258 m_inputWin->GetClientRect(), wxALIGN_CENTER);
259 }
260
261
262 // helper function that returns textual description of wx virtual keycode
263 const char* GetVirtualKeyCodeName(int keycode)
264 {
265 switch ( keycode )
266 {
267 #define WXK_(x) \
268 case WXK_##x: return #x;
269
270 WXK_(BACK)
271 WXK_(TAB)
272 WXK_(RETURN)
273 WXK_(ESCAPE)
274 WXK_(SPACE)
275 WXK_(DELETE)
276 WXK_(START)
277 WXK_(LBUTTON)
278 WXK_(RBUTTON)
279 WXK_(CANCEL)
280 WXK_(MBUTTON)
281 WXK_(CLEAR)
282 WXK_(SHIFT)
283 WXK_(ALT)
284 WXK_(CONTROL)
285 WXK_(MENU)
286 WXK_(PAUSE)
287 WXK_(CAPITAL)
288 WXK_(END)
289 WXK_(HOME)
290 WXK_(LEFT)
291 WXK_(UP)
292 WXK_(RIGHT)
293 WXK_(DOWN)
294 WXK_(SELECT)
295 WXK_(PRINT)
296 WXK_(EXECUTE)
297 WXK_(SNAPSHOT)
298 WXK_(INSERT)
299 WXK_(HELP)
300 WXK_(NUMPAD0)
301 WXK_(NUMPAD1)
302 WXK_(NUMPAD2)
303 WXK_(NUMPAD3)
304 WXK_(NUMPAD4)
305 WXK_(NUMPAD5)
306 WXK_(NUMPAD6)
307 WXK_(NUMPAD7)
308 WXK_(NUMPAD8)
309 WXK_(NUMPAD9)
310 WXK_(MULTIPLY)
311 WXK_(ADD)
312 WXK_(SEPARATOR)
313 WXK_(SUBTRACT)
314 WXK_(DECIMAL)
315 WXK_(DIVIDE)
316 WXK_(F1)
317 WXK_(F2)
318 WXK_(F3)
319 WXK_(F4)
320 WXK_(F5)
321 WXK_(F6)
322 WXK_(F7)
323 WXK_(F8)
324 WXK_(F9)
325 WXK_(F10)
326 WXK_(F11)
327 WXK_(F12)
328 WXK_(F13)
329 WXK_(F14)
330 WXK_(F15)
331 WXK_(F16)
332 WXK_(F17)
333 WXK_(F18)
334 WXK_(F19)
335 WXK_(F20)
336 WXK_(F21)
337 WXK_(F22)
338 WXK_(F23)
339 WXK_(F24)
340 WXK_(NUMLOCK)
341 WXK_(SCROLL)
342 WXK_(PAGEUP)
343 WXK_(PAGEDOWN)
344 WXK_(NUMPAD_SPACE)
345 WXK_(NUMPAD_TAB)
346 WXK_(NUMPAD_ENTER)
347 WXK_(NUMPAD_F1)
348 WXK_(NUMPAD_F2)
349 WXK_(NUMPAD_F3)
350 WXK_(NUMPAD_F4)
351 WXK_(NUMPAD_HOME)
352 WXK_(NUMPAD_LEFT)
353 WXK_(NUMPAD_UP)
354 WXK_(NUMPAD_RIGHT)
355 WXK_(NUMPAD_DOWN)
356 WXK_(NUMPAD_PAGEUP)
357 WXK_(NUMPAD_PAGEDOWN)
358 WXK_(NUMPAD_END)
359 WXK_(NUMPAD_BEGIN)
360 WXK_(NUMPAD_INSERT)
361 WXK_(NUMPAD_DELETE)
362 WXK_(NUMPAD_EQUAL)
363 WXK_(NUMPAD_MULTIPLY)
364 WXK_(NUMPAD_ADD)
365 WXK_(NUMPAD_SEPARATOR)
366 WXK_(NUMPAD_SUBTRACT)
367 WXK_(NUMPAD_DECIMAL)
368 WXK_(NUMPAD_DIVIDE)
369
370 WXK_(WINDOWS_LEFT)
371 WXK_(WINDOWS_RIGHT)
372 #ifdef __WXOSX__
373 WXK_(RAW_CONTROL)
374 #endif
375 #undef WXK_
376
377 default:
378 return NULL;
379 }
380 }
381
382 // helper function that returns textual description of key in the event
383 wxString GetKeyName(const wxKeyEvent &event)
384 {
385 int keycode = event.GetKeyCode();
386 const char* virt = GetVirtualKeyCodeName(keycode);
387 if ( virt )
388 return virt;
389 if ( keycode > 0 && keycode < 32 )
390 return wxString::Format("Ctrl-%c", (unsigned char)('A' + keycode - 1));
391 if ( keycode >= 32 && keycode < 128 )
392 return wxString::Format("'%c'", (unsigned char)keycode);
393
394 #if wxUSE_UNICODE
395 int uc = event.GetUnicodeKey();
396 if ( uc != WXK_NONE )
397 return wxString::Format("'%c'", uc);
398 #endif
399
400 return "unknown";
401 }
402
403
404 void MyFrame::LogEvent(const wxString& name, wxKeyEvent& event)
405 {
406 wxString msg;
407 // event key_name KeyCode modifiers Unicode raw_code raw_flags pos
408 msg.Printf("%7s %15s %5d %c%c%c%c"
409 #if wxUSE_UNICODE
410 "%5d (U+%04x)"
411 #else
412 " none "
413 #endif
414 #ifdef wxHAS_RAW_KEY_CODES
415 " %7lu 0x%08lx"
416 #else
417 " not-set not-set"
418 #endif
419 " (%5d,%5d)"
420 "\n",
421 name,
422 GetKeyName(event),
423 event.GetKeyCode(),
424 event.ControlDown() ? 'C' : '-',
425 event.AltDown() ? 'A' : '-',
426 event.ShiftDown() ? 'S' : '-',
427 event.MetaDown() ? 'M' : '-'
428 #if wxUSE_UNICODE
429 , event.GetUnicodeKey()
430 , event.GetUnicodeKey()
431 #endif
432 #ifdef wxHAS_RAW_KEY_CODES
433 , (unsigned long) event.GetRawKeyCode()
434 , (unsigned long) event.GetRawKeyFlags()
435 #endif
436 , event.GetX()
437 , event.GetY()
438 );
439
440 m_logText->AppendText(msg);
441 }
442
443