Generate the same flags for modifier key events in wxGTK as in wxMSW.
[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 // Helper for ModKeyDown().
114 int GetModForKey(int keycode)
115 {
116 switch ( keycode )
117 {
118 case WXK_CONTROL: return wxMOD_CONTROL;
119 case WXK_SHIFT: return wxMOD_SHIFT;
120 case WXK_ALT: return wxMOD_ALT;
121 default:
122 wxFAIL_MSG( "Unknown modifier key" );
123 }
124
125 return wxMOD_NONE;
126 }
127
128 // Helper function to allow writing just ModKeyDown(WXK_CONTROL) instead of
129 // more verbose KeyDesc(WXK_CONTROL, wxMOD_CONTROL).
130 KeyDesc ModKeyDown(int keycode)
131 {
132 return KeyDesc(keycode, GetModForKey(keycode));
133 }
134
135 // Another helper provided for symmetry with ModKeyDown() only.
136 KeyDesc ModKeyUp(int keycode)
137 {
138 return KeyDesc(keycode);
139 }
140
141 // Verify that the event object corresponds to our idea of what it should be.
142 void TestEvent(int line, const wxKeyEvent& ev, const KeyDesc& desc)
143 {
144 // Construct the message we'll display if an assert fails.
145 std::string msg;
146 const wxEventType t = ev.GetEventType();
147 if ( t == wxEVT_KEY_DOWN )
148 msg = "key down";
149 else if ( t == wxEVT_CHAR )
150 msg = "char";
151 else if ( t == wxEVT_KEY_UP )
152 msg = "key up";
153 else
154 CPPUNIT_FAIL( "unknown event type" );
155
156 msg += " event at line ";
157 msg += wxString::Format("%d", line).mb_str();
158
159
160 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong key code in " + msg,
161 desc.m_keycode,
162 ev.GetKeyCode() );
163
164 #if wxUSE_UNICODE
165 if ( desc.m_keycode < WXK_START )
166 {
167 // For Latin-1 our key code is the same as Unicode character value.
168 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong Unicode key in " + msg,
169 (char)desc.m_keycode,
170 (char)ev.GetUnicodeKey() );
171 }
172 else // Special key
173 {
174 // Key codes above WXK_START don't correspond to printable characters.
175 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong non-zero Unicode key in " + msg,
176 0,
177 (int)ev.GetUnicodeKey() );
178 }
179 #endif // wxUSE_UNICODE
180
181 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong modifiers in " + msg,
182 desc.m_mods,
183 ev.GetModifiers() );
184 }
185
186 // Call TestEvent() passing it the line number from where it was called: this
187 // is useful for interpreting the assert failure messages.
188 #define ASSERT_KEY_EVENT_IS( ev, desc ) TestEvent(__LINE__, ev, desc)
189
190 } // anonymous namespace
191
192 // --------------------------------------------------------------------------
193 // test class
194 // --------------------------------------------------------------------------
195
196 class KeyboardEventTestCase : public CppUnit::TestCase
197 {
198 public:
199 KeyboardEventTestCase() {}
200
201 virtual void setUp();
202 virtual void tearDown();
203
204 private:
205 CPPUNIT_TEST_SUITE( KeyboardEventTestCase );
206 CPPUNIT_TEST( NormalLetter );
207 CPPUNIT_TEST( NormalSpecial );
208 CPPUNIT_TEST( CtrlLetter );
209 CPPUNIT_TEST( CtrlSpecial );
210 CPPUNIT_TEST( ShiftLetter );
211 CPPUNIT_TEST( ShiftSpecial );
212 CPPUNIT_TEST_SUITE_END();
213
214 void NormalLetter();
215 void NormalSpecial();
216 void CtrlLetter();
217 void CtrlSpecial();
218 void ShiftLetter();
219 void ShiftSpecial();
220
221 KeyboardTestWindow *m_win;
222
223 wxDECLARE_NO_COPY_CLASS(KeyboardEventTestCase);
224 };
225
226 wxREGISTER_UNIT_TEST(KeyboardEvent);
227
228 void KeyboardEventTestCase::setUp()
229 {
230 m_win = new KeyboardTestWindow(wxTheApp->GetTopWindow());
231 m_win->SetFocus();
232 wxYield(); // needed to show the new window
233
234 // The window might get some key up events when it's being shown if the key
235 // was pressed when the program was started and released after the window
236 // was shown, e.g. this does happen in practice when launching the test
237 // from command line. Simply discard all the spurious events so far.
238 m_win->ClearEvents();
239 }
240
241 void KeyboardEventTestCase::tearDown()
242 {
243 m_win->Destroy();
244 }
245
246 void KeyboardEventTestCase::NormalLetter()
247 {
248 wxUIActionSimulator sim;
249 sim.Char('a');
250 wxYield();
251
252 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyDownCount() );
253 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(), 'A' );
254
255 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
256 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), 'a' );
257
258 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyUpCount() );
259 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(), 'A' );
260 }
261
262 void KeyboardEventTestCase::NormalSpecial()
263 {
264 wxUIActionSimulator sim;
265 sim.Char(WXK_END);
266 wxYield();
267
268 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyDownCount() );
269 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(), WXK_END );
270
271 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
272 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), WXK_END );
273
274 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyUpCount() );
275 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(), WXK_END );
276 }
277
278 void KeyboardEventTestCase::CtrlLetter()
279 {
280 wxUIActionSimulator sim;
281 sim.Char('z', wxMOD_CONTROL);
282 wxYield();
283
284 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() );
285 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0),
286 ModKeyDown(WXK_CONTROL) );
287 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1),
288 KeyDesc('Z', wxMOD_CONTROL) );
289
290 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
291 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(),
292 KeyDesc('\x1a', wxMOD_CONTROL) );
293
294 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() );
295 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0),
296 KeyDesc('Z', wxMOD_CONTROL) );
297 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1),
298 ModKeyUp(WXK_CONTROL) );
299 }
300
301 void KeyboardEventTestCase::CtrlSpecial()
302 {
303 wxUIActionSimulator sim;
304 sim.Char(WXK_PAGEUP, wxMOD_CONTROL);
305 wxYield();
306
307 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() );
308 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0),
309 ModKeyDown(WXK_CONTROL) );
310 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1),
311 KeyDesc(WXK_PAGEUP, wxMOD_CONTROL) );
312
313 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
314 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(),
315 KeyDesc(WXK_PAGEUP, wxMOD_CONTROL) );
316
317 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() );
318 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0),
319 KeyDesc(WXK_PAGEUP, wxMOD_CONTROL) );
320 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1),
321 ModKeyUp(WXK_CONTROL) );
322 }
323
324 void KeyboardEventTestCase::ShiftLetter()
325 {
326 wxUIActionSimulator sim;
327 sim.Char('Q', wxMOD_SHIFT);
328 wxYield();
329
330 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() );
331 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0),
332 ModKeyDown(WXK_SHIFT) );
333 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1),
334 KeyDesc('Q', wxMOD_SHIFT) );
335
336 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
337 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(),
338 KeyDesc('Q', wxMOD_SHIFT) );
339
340 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() );
341 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0),
342 KeyDesc('Q', wxMOD_SHIFT) );
343 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1),
344 ModKeyUp(WXK_SHIFT) );
345 }
346
347 void KeyboardEventTestCase::ShiftSpecial()
348 {
349 wxUIActionSimulator sim;
350 sim.Char(WXK_TAB, wxMOD_SHIFT);
351 wxYield();
352
353 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() );
354 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0),
355 ModKeyDown(WXK_SHIFT) );
356 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1),
357 KeyDesc(WXK_TAB, wxMOD_SHIFT) );
358
359 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
360 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(),
361 KeyDesc(WXK_TAB, wxMOD_SHIFT) );
362
363 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() );
364 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0),
365 KeyDesc(WXK_TAB, wxMOD_SHIFT) );
366 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1),
367 ModKeyUp(WXK_SHIFT) );
368 }
369
370 #endif // wxUSE_UIACTIONSIMULATOR