]> git.saurik.com Git - wxWidgets.git/blob - tests/events/keyboard.cpp
Fix crashes after using "wildcard" wxEvtHandler::Disconnect().
[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 // FIXME: As all the other tests involving wxUIActionSimulator, this one is
21 // broken under OS X, the test window siply never gets any events.
22 #if wxUSE_UIACTIONSIMULATOR && !defined(__WXOSX__)
23
24 #ifndef WX_PRECOMP
25 #include "wx/app.h"
26 #include "wx/event.h"
27 #include "wx/window.h"
28 #endif // WX_PRECOMP
29
30 #include "wx/uiaction.h"
31 #include "wx/vector.h"
32
33 namespace
34 {
35
36 // ----------------------------------------------------------------------------
37 // test window verifying the event generation
38 // ----------------------------------------------------------------------------
39
40 class KeyboardTestWindow : public wxWindow
41 {
42 public:
43 KeyboardTestWindow(wxWindow *parent)
44 : wxWindow(parent, wxID_ANY, wxPoint(0, 0), parent->GetClientSize())
45 {
46 Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(KeyboardTestWindow::OnKeyDown));
47 Connect(wxEVT_CHAR, wxKeyEventHandler(KeyboardTestWindow::OnChar));
48 Connect(wxEVT_KEY_UP, wxKeyEventHandler(KeyboardTestWindow::OnKeyUp));
49 }
50
51 unsigned GetKeyDownCount() const { return m_keyDownEvents.size(); }
52 unsigned GetCharCount() const { return m_charEvents.size(); }
53 unsigned GetKeyUpCount() const { return m_keyUpEvents.size(); }
54
55 const wxKeyEvent& GetKeyDownEvent(unsigned n = 0) const
56 {
57 return m_keyDownEvents[n];
58 }
59 const wxKeyEvent& GetCharEvent(unsigned n = 0) const
60 {
61 return m_charEvents[n];
62 }
63 const wxKeyEvent& GetKeyUpEvent(unsigned n = 0) const
64 {
65 return m_keyUpEvents[n];
66 }
67
68 void ClearEvents()
69 {
70 m_keyDownEvents =
71 m_charEvents =
72 m_keyUpEvents = wxVector<wxKeyEvent>();
73 }
74
75 private:
76 void OnKeyDown(wxKeyEvent& event)
77 {
78 m_keyDownEvents.push_back(event);
79 event.Skip();
80 }
81
82 void OnChar(wxKeyEvent& event)
83 {
84 m_charEvents.push_back(event);
85 event.Skip();
86 }
87
88 void OnKeyUp(wxKeyEvent& event)
89 {
90 m_keyUpEvents.push_back(event);
91 event.Skip();
92 }
93
94 wxVector<wxKeyEvent> m_keyDownEvents,
95 m_charEvents,
96 m_keyUpEvents;
97
98
99 wxDECLARE_NO_COPY_CLASS(KeyboardTestWindow);
100 };
101
102 // Object describing the (main fields of) keyboard event.
103 struct KeyDesc
104 {
105 KeyDesc(int keycode, int mods = 0)
106 : m_keycode(keycode),
107 m_mods(mods)
108 {
109 }
110
111 int m_keycode;
112 int m_mods;
113 };
114
115 // Helper for ModKeyDown().
116 int GetModForKey(int keycode)
117 {
118 switch ( keycode )
119 {
120 case WXK_CONTROL: return wxMOD_CONTROL;
121 case WXK_SHIFT: return wxMOD_SHIFT;
122 case WXK_ALT: return wxMOD_ALT;
123 default:
124 wxFAIL_MSG( "Unknown modifier key" );
125 }
126
127 return wxMOD_NONE;
128 }
129
130 // Helper function to allow writing just ModKeyDown(WXK_CONTROL) instead of
131 // more verbose KeyDesc(WXK_CONTROL, wxMOD_CONTROL).
132 KeyDesc ModKeyDown(int keycode)
133 {
134 return KeyDesc(keycode, GetModForKey(keycode));
135 }
136
137 // Another helper provided for symmetry with ModKeyDown() only.
138 KeyDesc ModKeyUp(int keycode)
139 {
140 return KeyDesc(keycode);
141 }
142
143 // Verify that the event object corresponds to our idea of what it should be.
144 void TestEvent(int line, const wxKeyEvent& ev, const KeyDesc& desc)
145 {
146 // Construct the message we'll display if an assert fails.
147 std::string msg;
148 const wxEventType t = ev.GetEventType();
149 if ( t == wxEVT_KEY_DOWN )
150 msg = "key down";
151 else if ( t == wxEVT_CHAR )
152 msg = "char";
153 else if ( t == wxEVT_KEY_UP )
154 msg = "key up";
155 else
156 CPPUNIT_FAIL( "unknown event type" );
157
158 msg += " event at line ";
159 msg += wxString::Format("%d", line).mb_str();
160
161
162 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong key code in " + msg,
163 desc.m_keycode,
164 ev.GetKeyCode() );
165
166 #if wxUSE_UNICODE
167 if ( desc.m_keycode < WXK_START )
168 {
169 // For Latin-1 our key code is the same as Unicode character value.
170 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong Unicode key in " + msg,
171 (char)desc.m_keycode,
172 (char)ev.GetUnicodeKey() );
173 }
174 else // Special key
175 {
176 // Key codes above WXK_START don't correspond to printable characters.
177 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong non-zero Unicode key in " + msg,
178 0,
179 (int)ev.GetUnicodeKey() );
180 }
181 #endif // wxUSE_UNICODE
182
183 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong modifiers in " + msg,
184 desc.m_mods,
185 ev.GetModifiers() );
186 }
187
188 // Call TestEvent() passing it the line number from where it was called: this
189 // is useful for interpreting the assert failure messages.
190 #define ASSERT_KEY_EVENT_IS( ev, desc ) TestEvent(__LINE__, ev, desc)
191
192 } // anonymous namespace
193
194 // --------------------------------------------------------------------------
195 // test class
196 // --------------------------------------------------------------------------
197
198 class KeyboardEventTestCase : public CppUnit::TestCase
199 {
200 public:
201 KeyboardEventTestCase() {}
202
203 virtual void setUp();
204 virtual void tearDown();
205
206 private:
207 CPPUNIT_TEST_SUITE( KeyboardEventTestCase );
208 CPPUNIT_TEST( NormalLetter );
209 CPPUNIT_TEST( NormalSpecial );
210 CPPUNIT_TEST( CtrlLetter );
211 CPPUNIT_TEST( CtrlSpecial );
212 CPPUNIT_TEST( ShiftLetter );
213 CPPUNIT_TEST( ShiftSpecial );
214 CPPUNIT_TEST_SUITE_END();
215
216 void NormalLetter();
217 void NormalSpecial();
218 void CtrlLetter();
219 void CtrlSpecial();
220 void ShiftLetter();
221 void ShiftSpecial();
222
223 KeyboardTestWindow *m_win;
224
225 wxDECLARE_NO_COPY_CLASS(KeyboardEventTestCase);
226 };
227
228 wxREGISTER_UNIT_TEST(KeyboardEvent);
229
230 void KeyboardEventTestCase::setUp()
231 {
232 m_win = new KeyboardTestWindow(wxTheApp->GetTopWindow());
233 m_win->SetFocus();
234 wxYield(); // needed to show the new window
235
236 // The window might get some key up events when it's being shown if the key
237 // was pressed when the program was started and released after the window
238 // was shown, e.g. this does happen in practice when launching the test
239 // from command line. Simply discard all the spurious events so far.
240 m_win->ClearEvents();
241 }
242
243 void KeyboardEventTestCase::tearDown()
244 {
245 m_win->Destroy();
246 }
247
248 void KeyboardEventTestCase::NormalLetter()
249 {
250 wxUIActionSimulator sim;
251 sim.Char('a');
252 wxYield();
253
254 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyDownCount() );
255 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(), 'A' );
256
257 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
258 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), 'a' );
259
260 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyUpCount() );
261 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(), 'A' );
262 }
263
264 void KeyboardEventTestCase::NormalSpecial()
265 {
266 wxUIActionSimulator sim;
267 sim.Char(WXK_END);
268 wxYield();
269
270 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyDownCount() );
271 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(), WXK_END );
272
273 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
274 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), WXK_END );
275
276 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyUpCount() );
277 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(), WXK_END );
278 }
279
280 void KeyboardEventTestCase::CtrlLetter()
281 {
282 wxUIActionSimulator sim;
283 sim.Char('z', wxMOD_CONTROL);
284 wxYield();
285
286 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() );
287 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0),
288 ModKeyDown(WXK_CONTROL) );
289 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1),
290 KeyDesc('Z', wxMOD_CONTROL) );
291
292 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
293 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(),
294 KeyDesc('\x1a', wxMOD_CONTROL) );
295
296 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() );
297 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0),
298 KeyDesc('Z', wxMOD_CONTROL) );
299 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1),
300 ModKeyUp(WXK_CONTROL) );
301 }
302
303 void KeyboardEventTestCase::CtrlSpecial()
304 {
305 wxUIActionSimulator sim;
306 sim.Char(WXK_PAGEUP, wxMOD_CONTROL);
307 wxYield();
308
309 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() );
310 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0),
311 ModKeyDown(WXK_CONTROL) );
312 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1),
313 KeyDesc(WXK_PAGEUP, wxMOD_CONTROL) );
314
315 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
316 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(),
317 KeyDesc(WXK_PAGEUP, wxMOD_CONTROL) );
318
319 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() );
320 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0),
321 KeyDesc(WXK_PAGEUP, wxMOD_CONTROL) );
322 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1),
323 ModKeyUp(WXK_CONTROL) );
324 }
325
326 void KeyboardEventTestCase::ShiftLetter()
327 {
328 wxUIActionSimulator sim;
329 sim.Char('Q', wxMOD_SHIFT);
330 wxYield();
331
332 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() );
333 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0),
334 ModKeyDown(WXK_SHIFT) );
335 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1),
336 KeyDesc('Q', wxMOD_SHIFT) );
337
338 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
339 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(),
340 KeyDesc('Q', wxMOD_SHIFT) );
341
342 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() );
343 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0),
344 KeyDesc('Q', wxMOD_SHIFT) );
345 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1),
346 ModKeyUp(WXK_SHIFT) );
347 }
348
349 void KeyboardEventTestCase::ShiftSpecial()
350 {
351 wxUIActionSimulator sim;
352 sim.Char(WXK_F3, wxMOD_SHIFT);
353 wxYield();
354
355 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() );
356 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0),
357 ModKeyDown(WXK_SHIFT) );
358 ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1),
359 KeyDesc(WXK_F3, wxMOD_SHIFT) );
360
361 CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() );
362 ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(),
363 KeyDesc(WXK_F3, wxMOD_SHIFT) );
364
365 CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() );
366 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0),
367 KeyDesc(WXK_F3, wxMOD_SHIFT) );
368 ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1),
369 ModKeyUp(WXK_SHIFT) );
370 }
371
372 #endif // wxUSE_UIACTIONSIMULATOR