Generate unshifted Unicode key codes in wxEVT_KEY_XXX events in wxGTK.
[wxWidgets.git] / tests / events / keyboard.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/events/keyboard.cpp
3 // Purpose: Test keyboard events
4 // Author: Vadim Zeitlin
5 // Created: 2010-09-05
6 // RCS-ID: $Id$
7 // Copyright: (c) 2010 Vadim Zeitlin <vadim@wxwidgets.org>
8 ///////////////////////////////////////////////////////////////////////////////
9
10 // ----------------------------------------------------------------------------
11 // headers
12 // ----------------------------------------------------------------------------
13
14 #include "testprec.h"
15
16 #ifdef __BORLANDC__
17 #pragma hdrstop
18 #endif
19
20 #if wxUSE_UIACTIONSIMULATOR
21
22 #ifndef WX_PRECOMP
23 #include "wx/app.h"
24 #include "wx/event.h"
25 #include "wx/window.h"
26 #endif // WX_PRECOMP
27
28 #include "wx/uiaction.h"
29 #include "wx/vector.h"
30
31 namespace
32 {
33
34 // ----------------------------------------------------------------------------
35 // test window verifying the event generation
36 // ----------------------------------------------------------------------------
37
38 class KeyboardTestWindow : public wxWindow
39 {
40 public:
41 KeyboardTestWindow(wxWindow *parent)
42 : wxWindow(parent, wxID_ANY)
43 {
44 Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(KeyboardTestWindow::OnKeyDown));
45 Connect(wxEVT_CHAR, wxKeyEventHandler(KeyboardTestWindow::OnChar));
46 Connect(wxEVT_KEY_UP, wxKeyEventHandler(KeyboardTestWindow::OnKeyUp));
47 }
48
49 unsigned GetKeyDownCount() const { return m_keyDownEvents.size(); }
50 unsigned GetCharCount() const { return m_charEvents.size(); }
51 unsigned GetKeyUpCount() const { return m_keyUpEvents.size(); }
52
53 const wxKeyEvent& GetKeyDownEvent(unsigned n = 0) const
54 {
55 return m_keyDownEvents[n];
56 }
57 const wxKeyEvent& GetCharEvent(unsigned n = 0) const
58 {
59 return m_charEvents[n];
60 }
61 const wxKeyEvent& GetKeyUpEvent(unsigned n = 0) const
62 {
63 return m_keyUpEvents[n];
64 }
65
66 void ClearEvents()
67 {
68 m_keyDownEvents =
69 m_charEvents =
70 m_keyUpEvents = wxVector<wxKeyEvent>();
71 }
72
73 private:
74 void OnKeyDown(wxKeyEvent& event)
75 {
76 m_keyDownEvents.push_back(event);
77 event.Skip();
78 }
79
80 void OnChar(wxKeyEvent& event)
81 {
82 m_charEvents.push_back(event);
83 event.Skip();
84 }
85
86 void OnKeyUp(wxKeyEvent& event)
87 {
88 m_keyUpEvents.push_back(event);
89 event.Skip();
90 }
91
92 wxVector<wxKeyEvent> m_keyDownEvents,
93 m_charEvents,
94 m_keyUpEvents;
95
96
97 wxDECLARE_NO_COPY_CLASS(KeyboardTestWindow);
98 };
99
100 // Object describing the (main fields of) keyboard event.
101 struct KeyDesc
102 {
103 KeyDesc(int keycode, int mods = 0)
104 : m_keycode(keycode),
105 m_mods(mods)
106 {
107 }
108
109 int m_keycode;
110 int m_mods;
111 };
112
113 // These functions are only needed because of wx bug: currently, modifiers key
114 // events are inconsistent between platforms and wxMSW generates key down event
115 // for e.g. WXK_CONTROL with wxMOD_CONTROL set and key up event with it unset
116 // while wxGTK does exactly vice versa. So we provide these helpers to make it
117 // possible to make the tests pass under all platforms for now but ideally they
118 // should all be made to behave the same and this should become unnecessary.
119
120 int GetModForKey(int keycode)
121 {
122 switch ( keycode )
123 {
124 case WXK_CONTROL: return wxMOD_CONTROL;
125 case WXK_SHIFT: return wxMOD_SHIFT;
126 case WXK_ALT: return wxMOD_ALT;
127 default:
128 wxFAIL_MSG( "Unknown modifier key" );
129 }
130
131 return wxMOD_NONE;
132 }
133
134 #ifdef __WXGTK__
135
136 KeyDesc ModKeyDown(int keycode)
137 {
138 // Second level bug: currently wxUIActionSimulator produces different
139 // modifiers than actually pressing the key. So while the above comment is
140 // true for keys pressed by user, when simulating them we do get the
141 // corresponding bit set for the modifier press events.
142 //
143 // Again, this is a bug and wxUIActionSimulator should be fixed to behave
144 // as the real events do but until this happens just work around this here.
145 return KeyDesc(keycode, GetModForKey(keycode));
146 }
147
148 KeyDesc ModKeyUp(int keycode)
149 {
150 return KeyDesc(keycode, GetModForKey(keycode));
151 }
152
153 #else // Assume MSW-like behaviour for all the other platforms.
154
155 KeyDesc ModKeyDown(int keycode)
156 {
157 return KeyDesc(keycode, GetModForKey(keycode));
158 }
159
160 KeyDesc ModKeyUp(int keycode)
161 {
162 return KeyDesc(keycode);
163 }
164
165 #endif // Platforms.
166
167 // Verify that the event object corresponds to our idea of what it should be.
168 void TestEvent(int line, const wxKeyEvent& ev, const KeyDesc& desc)
169 {
170 // Construct the message we'll display if an assert fails.
171 std::string msg;
172 const wxEventType t = ev.GetEventType();
173 if ( t == wxEVT_KEY_DOWN )
174 msg = "key down";
175 else if ( t == wxEVT_CHAR )
176 msg = "char";
177 else if ( t == wxEVT_KEY_UP )
178 msg = "key up";
179 else
180 CPPUNIT_FAIL( "unknown event type" );
181
182 msg += " event at line ";
183 msg += wxString::Format("%d", line).mb_str();
184
185
186 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong key code in " + msg,
187 desc.m_keycode,
188 ev.GetKeyCode() );
189
190 #if wxUSE_UNICODE
191 if ( desc.m_keycode < WXK_START )
192 {
193 // For Latin-1 our key code is the same as Unicode character value.
194 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong Unicode key in " + msg,
195 (char)desc.m_keycode,
196 (char)ev.GetUnicodeKey() );
197 }
198 else // Special key
199 {
200 // Key codes above WXK_START don't correspond to printable characters.
201 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong non-zero Unicode key in " + msg,
202 0,
203 (int)ev.GetUnicodeKey() );
204 }
205 #endif // wxUSE_UNICODE
206
207 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong modifiers in " + msg,
208 desc.m_mods,
209 ev.GetModifiers() );
210 }
211
212 // Call TestEvent() passing it the line number from where it was called: this
213 // is useful for interpreting the assert failure messages.
214 #define ASSERT_KEY_EVENT_IS( ev, desc ) TestEvent(__LINE__, ev, desc)
215
216 } // anonymous namespace
217
218 // --------------------------------------------------------------------------
219 // test class
220 // --------------------------------------------------------------------------
221
222 class KeyboardEventTestCase : public CppUnit::TestCase
223 {
224 public:
225 KeyboardEventTestCase() {}
226
227 virtual void setUp();
228 virtual void tearDown();
229
230 private:
231 CPPUNIT_TEST_SUITE( KeyboardEventTestCase );
232 CPPUNIT_TEST( NormalLetter );
233 CPPUNIT_TEST( NormalSpecial );
234 CPPUNIT_TEST( CtrlLetter );
235 CPPUNIT_TEST( CtrlSpecial );
236 CPPUNIT_TEST( ShiftLetter );
237 CPPUNIT_TEST( ShiftSpecial );
238 CPPUNIT_TEST_SUITE_END();
239
240 void NormalLetter();
241 void NormalSpecial();
242 void CtrlLetter();
243 void CtrlSpecial();
244 void ShiftLetter();
245 void ShiftSpecial();
246
247 KeyboardTestWindow *m_win;
248
249 wxDECLARE_NO_COPY_CLASS(KeyboardEventTestCase);
250 };
251
252 wxREGISTER_UNIT_TEST(KeyboardEvent);
253
254 void KeyboardEventTestCase::setUp()
255 {
256 m_win = new KeyboardTestWindow(wxTheApp->GetTopWindow());
257 m_win->SetFocus();
258 wxYield(); // needed to show the new window
259
260 // The window might get some key up events when it's being shown if the key
261 // was pressed when the program was started and released after the window
262 // was shown, e.g. this does happen in practice when launching the test
263 // from command line. Simply discard all the spurious events so far.
264 m_win->ClearEvents();
265 }
266
267 void KeyboardEventTestCase::tearDown()
268 {
269 m_win->Destroy();
270 }
271
272 void KeyboardEventTestCase::NormalLetter()
273 {
274 wxUIActionSimulator sim;
275 sim.Char('a');
276 wxYield();
277
278 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyDownCount() );
279 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(), 'A' );
280
281 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
282 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), 'a' );
283
284 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyUpCount() );
285 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(), 'A' );
286 }
287
288 void KeyboardEventTestCase::NormalSpecial()
289 {
290 wxUIActionSimulator sim;
291 sim.Char(WXK_END);
292 wxYield();
293
294 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyDownCount() );
295 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(), WXK_END );
296
297 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
298 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), WXK_END );
299
300 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyUpCount() );
301 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(), WXK_END );
302 }
303
304 void KeyboardEventTestCase::CtrlLetter()
305 {
306 wxUIActionSimulator sim;
307 sim.Char('z', wxMOD_CONTROL);
308 wxYield();
309
310 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() );
311 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0),
312 ModKeyDown(WXK_CONTROL) );
313 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1),
314 KeyDesc('Z', wxMOD_CONTROL) );
315
316 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
317 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(),
318 KeyDesc('\x1a', wxMOD_CONTROL) );
319
320 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() );
321 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0),
322 KeyDesc('Z', wxMOD_CONTROL) );
323 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1),
324 ModKeyUp(WXK_CONTROL) );
325 }
326
327 void KeyboardEventTestCase::CtrlSpecial()
328 {
329 wxUIActionSimulator sim;
330 sim.Char(WXK_PAGEUP, wxMOD_CONTROL);
331 wxYield();
332
333 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() );
334 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0),
335 ModKeyDown(WXK_CONTROL) );
336 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1),
337 KeyDesc(WXK_PAGEUP, wxMOD_CONTROL) );
338
339 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
340 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(),
341 KeyDesc(WXK_PAGEUP, wxMOD_CONTROL) );
342
343 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() );
344 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0),
345 KeyDesc(WXK_PAGEUP, wxMOD_CONTROL) );
346 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1),
347 ModKeyUp(WXK_CONTROL) );
348 }
349
350 void KeyboardEventTestCase::ShiftLetter()
351 {
352 wxUIActionSimulator sim;
353 sim.Char('Q', wxMOD_SHIFT);
354 wxYield();
355
356 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() );
357 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0),
358 ModKeyDown(WXK_SHIFT) );
359 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1),
360 KeyDesc('Q', wxMOD_SHIFT) );
361
362 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
363 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(),
364 KeyDesc('Q', wxMOD_SHIFT) );
365
366 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() );
367 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0),
368 KeyDesc('Q', wxMOD_SHIFT) );
369 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1),
370 ModKeyUp(WXK_SHIFT) );
371 }
372
373 void KeyboardEventTestCase::ShiftSpecial()
374 {
375 wxUIActionSimulator sim;
376 sim.Char(WXK_TAB, wxMOD_SHIFT);
377 wxYield();
378
379 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() );
380 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0),
381 ModKeyDown(WXK_SHIFT) );
382 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1),
383 KeyDesc(WXK_TAB, wxMOD_SHIFT) );
384
385 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
386 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(),
387 KeyDesc(WXK_TAB, wxMOD_SHIFT) );
388
389 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() );
390 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0),
391 KeyDesc(WXK_TAB, wxMOD_SHIFT) );
392 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1),
393 ModKeyUp(WXK_SHIFT) );
394 }
395
396 #endif // wxUSE_UIACTIONSIMULATOR