1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/events/keyboard.cpp
3 // Purpose: Test keyboard events
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2010 Vadim Zeitlin <vadim@wxwidgets.org>
8 ///////////////////////////////////////////////////////////////////////////////
10 // ----------------------------------------------------------------------------
12 // ----------------------------------------------------------------------------
20 #if wxUSE_UIACTIONSIMULATOR
25 #include "wx/window.h"
28 #include "wx/uiaction.h"
29 #include "wx/vector.h"
34 // ----------------------------------------------------------------------------
35 // test window verifying the event generation
36 // ----------------------------------------------------------------------------
38 class KeyboardTestWindow
: public wxWindow
41 KeyboardTestWindow(wxWindow
*parent
)
42 : wxWindow(parent
, wxID_ANY
)
44 Connect(wxEVT_KEY_DOWN
, wxKeyEventHandler(KeyboardTestWindow
::OnKeyDown
));
45 Connect(wxEVT_CHAR
, wxKeyEventHandler(KeyboardTestWindow
::OnChar
));
46 Connect(wxEVT_KEY_UP
, wxKeyEventHandler(KeyboardTestWindow
::OnKeyUp
));
49 unsigned GetKeyDownCount() const { return m_keyDownEvents
.size(); }
50 unsigned GetCharCount() const { return m_charEvents
.size(); }
51 unsigned GetKeyUpCount() const { return m_keyUpEvents
.size(); }
53 const wxKeyEvent
& GetKeyDownEvent(unsigned n
= 0) const
55 return m_keyDownEvents
[n
];
57 const wxKeyEvent
& GetCharEvent(unsigned n
= 0) const
59 return m_charEvents
[n
];
61 const wxKeyEvent
& GetKeyUpEvent(unsigned n
= 0) const
63 return m_keyUpEvents
[n
];
70 m_keyUpEvents
= wxVector
<wxKeyEvent
>();
74 void OnKeyDown(wxKeyEvent
& event
)
76 m_keyDownEvents
.push_back(event
);
80 void OnChar(wxKeyEvent
& event
)
82 m_charEvents
.push_back(event
);
86 void OnKeyUp(wxKeyEvent
& event
)
88 m_keyUpEvents
.push_back(event
);
92 wxVector
<wxKeyEvent
> m_keyDownEvents
,
97 wxDECLARE_NO_COPY_CLASS(KeyboardTestWindow
);
100 // Object describing the (main fields of) keyboard event.
103 KeyDesc(int keycode
, int mods
= 0)
104 : m_keycode(keycode
),
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.
120 int GetModForKey(int keycode
)
124 case WXK_CONTROL
: return wxMOD_CONTROL
;
125 case WXK_SHIFT
: return wxMOD_SHIFT
;
126 case WXK_ALT
: return wxMOD_ALT
;
128 wxFAIL_MSG( "Unknown modifier key" );
136 KeyDesc
ModKeyDown(int keycode
)
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.
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
));
148 KeyDesc
ModKeyUp(int keycode
)
150 return KeyDesc(keycode
, GetModForKey(keycode
));
153 #else // Assume MSW-like behaviour for all the other platforms.
155 KeyDesc
ModKeyDown(int keycode
)
157 return KeyDesc(keycode
, GetModForKey(keycode
));
160 KeyDesc
ModKeyUp(int keycode
)
162 return KeyDesc(keycode
);
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
)
170 // Construct the message we'll display if an assert fails.
172 const wxEventType t
= ev
.GetEventType();
173 if ( t
== wxEVT_KEY_DOWN
)
175 else if ( t
== wxEVT_CHAR
)
177 else if ( t
== wxEVT_KEY_UP
)
180 CPPUNIT_FAIL( "unknown event type" );
182 msg
+= " event at line ";
183 msg
+= wxString
::Format("%d", line
).mb_str();
186 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong key code in " + msg
,
191 if ( desc
.m_keycode
< 0x80 )
193 // FIXME: Currently wxMSW generates 'A' key code for key down/up events
194 // for the 'a' physical key while wxGTK and wxOSX/Cocoa generate them
195 // with 'a' and it's not clear which behaviour is more correct so don't
196 // test this for those events, only test it for EVT_CHAR where the
197 // correct behaviour is clear.
199 if ( t
== wxEVT_CHAR
)
201 // For 7-bit ASCII Unicode keys are the same as normal key codes.
202 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong Unicode key in " + msg
,
203 (char)desc
.m_keycode
,
204 (char)ev
.GetUnicodeKey() );
209 // In this test we don't use any really Unicode characters so far so
210 // anything above 0x80 must be special keys (e.g. WXK_CONTROL &c) which
211 // don't have any Unicode equivalent.
212 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong non-zero Unicode key in " + msg
,
214 (int)ev
.GetUnicodeKey() );
216 #endif // wxUSE_UNICODE
218 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong modifiers in " + msg
,
223 // Call TestEvent() passing it the line number from where it was called: this
224 // is useful for interpreting the assert failure messages.
225 #define ASSERT_KEY_EVENT_IS( ev, desc ) TestEvent(__LINE__, ev, desc)
227 } // anonymous namespace
229 // --------------------------------------------------------------------------
231 // --------------------------------------------------------------------------
233 class KeyboardEventTestCase
: public CppUnit
::TestCase
236 KeyboardEventTestCase() {}
238 virtual void setUp();
239 virtual void tearDown();
242 CPPUNIT_TEST_SUITE( KeyboardEventTestCase
);
243 CPPUNIT_TEST( NormalLetter
);
244 CPPUNIT_TEST( NormalSpecial
);
245 CPPUNIT_TEST( CtrlLetter
);
246 CPPUNIT_TEST( CtrlSpecial
);
247 CPPUNIT_TEST( ShiftLetter
);
248 CPPUNIT_TEST( ShiftSpecial
);
249 CPPUNIT_TEST_SUITE_END();
252 void NormalSpecial();
258 KeyboardTestWindow
*m_win
;
260 wxDECLARE_NO_COPY_CLASS(KeyboardEventTestCase
);
263 wxREGISTER_UNIT_TEST(KeyboardEvent
);
265 void KeyboardEventTestCase
::setUp()
267 m_win
= new KeyboardTestWindow(wxTheApp
->GetTopWindow());
269 wxYield(); // needed to show the new window
271 // The window might get some key up events when it's being shown if the key
272 // was pressed when the program was started and released after the window
273 // was shown, e.g. this does happen in practice when launching the test
274 // from command line. Simply discard all the spurious events so far.
275 m_win
->ClearEvents();
278 void KeyboardEventTestCase
::tearDown()
283 void KeyboardEventTestCase
::NormalLetter()
285 wxUIActionSimulator sim
;
289 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetKeyDownCount() );
290 ASSERT_KEY_EVENT_IS( m_win
->GetKeyDownEvent(), 'A' );
292 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetCharCount() );
293 ASSERT_KEY_EVENT_IS( m_win
->GetCharEvent(), 'a' );
295 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetKeyUpCount() );
296 ASSERT_KEY_EVENT_IS( m_win
->GetKeyUpEvent(), 'A' );
299 void KeyboardEventTestCase
::NormalSpecial()
301 wxUIActionSimulator sim
;
305 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetKeyDownCount() );
306 ASSERT_KEY_EVENT_IS( m_win
->GetKeyDownEvent(), WXK_END
);
308 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetCharCount() );
309 ASSERT_KEY_EVENT_IS( m_win
->GetCharEvent(), WXK_END
);
311 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetKeyUpCount() );
312 ASSERT_KEY_EVENT_IS( m_win
->GetKeyUpEvent(), WXK_END
);
315 void KeyboardEventTestCase
::CtrlLetter()
317 wxUIActionSimulator sim
;
318 sim
.Char('z', wxMOD_CONTROL
);
321 CPPUNIT_ASSERT_EQUAL( 2, m_win
->GetKeyDownCount() );
322 ASSERT_KEY_EVENT_IS( m_win
->GetKeyDownEvent(0),
323 ModKeyDown(WXK_CONTROL
) );
324 ASSERT_KEY_EVENT_IS( m_win
->GetKeyDownEvent(1),
325 KeyDesc('Z', wxMOD_CONTROL
) );
327 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetCharCount() );
328 ASSERT_KEY_EVENT_IS( m_win
->GetCharEvent(),
329 KeyDesc('\x1a', wxMOD_CONTROL
) );
331 CPPUNIT_ASSERT_EQUAL( 2, m_win
->GetKeyUpCount() );
332 ASSERT_KEY_EVENT_IS( m_win
->GetKeyUpEvent(0),
333 KeyDesc('Z', wxMOD_CONTROL
) );
334 ASSERT_KEY_EVENT_IS( m_win
->GetKeyUpEvent(1),
335 ModKeyUp(WXK_CONTROL
) );
338 void KeyboardEventTestCase
::CtrlSpecial()
340 wxUIActionSimulator sim
;
341 sim
.Char(WXK_PAGEUP
, wxMOD_CONTROL
);
344 CPPUNIT_ASSERT_EQUAL( 2, m_win
->GetKeyDownCount() );
345 ASSERT_KEY_EVENT_IS( m_win
->GetKeyDownEvent(0),
346 ModKeyDown(WXK_CONTROL
) );
347 ASSERT_KEY_EVENT_IS( m_win
->GetKeyDownEvent(1),
348 KeyDesc(WXK_PAGEUP
, wxMOD_CONTROL
) );
350 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetCharCount() );
351 ASSERT_KEY_EVENT_IS( m_win
->GetCharEvent(),
352 KeyDesc(WXK_PAGEUP
, wxMOD_CONTROL
) );
354 CPPUNIT_ASSERT_EQUAL( 2, m_win
->GetKeyUpCount() );
355 ASSERT_KEY_EVENT_IS( m_win
->GetKeyUpEvent(0),
356 KeyDesc(WXK_PAGEUP
, wxMOD_CONTROL
) );
357 ASSERT_KEY_EVENT_IS( m_win
->GetKeyUpEvent(1),
358 ModKeyUp(WXK_CONTROL
) );
361 void KeyboardEventTestCase
::ShiftLetter()
363 wxUIActionSimulator sim
;
364 sim
.Char('Q', wxMOD_SHIFT
);
367 CPPUNIT_ASSERT_EQUAL( 2, m_win
->GetKeyDownCount() );
368 ASSERT_KEY_EVENT_IS( m_win
->GetKeyDownEvent(0),
369 ModKeyDown(WXK_SHIFT
) );
370 ASSERT_KEY_EVENT_IS( m_win
->GetKeyDownEvent(1),
371 KeyDesc('Q', wxMOD_SHIFT
) );
373 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetCharCount() );
374 ASSERT_KEY_EVENT_IS( m_win
->GetCharEvent(),
375 KeyDesc('Q', wxMOD_SHIFT
) );
377 CPPUNIT_ASSERT_EQUAL( 2, m_win
->GetKeyUpCount() );
378 ASSERT_KEY_EVENT_IS( m_win
->GetKeyUpEvent(0),
379 KeyDesc('Q', wxMOD_SHIFT
) );
380 ASSERT_KEY_EVENT_IS( m_win
->GetKeyUpEvent(1),
381 ModKeyUp(WXK_SHIFT
) );
384 void KeyboardEventTestCase
::ShiftSpecial()
386 wxUIActionSimulator sim
;
387 sim
.Char(WXK_TAB
, wxMOD_SHIFT
);
390 CPPUNIT_ASSERT_EQUAL( 2, m_win
->GetKeyDownCount() );
391 ASSERT_KEY_EVENT_IS( m_win
->GetKeyDownEvent(0),
392 ModKeyDown(WXK_SHIFT
) );
393 ASSERT_KEY_EVENT_IS( m_win
->GetKeyDownEvent(1),
394 KeyDesc(WXK_TAB
, wxMOD_SHIFT
) );
396 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetCharCount() );
397 ASSERT_KEY_EVENT_IS( m_win
->GetCharEvent(),
398 KeyDesc(WXK_TAB
, wxMOD_SHIFT
) );
400 CPPUNIT_ASSERT_EQUAL( 2, m_win
->GetKeyUpCount() );
401 ASSERT_KEY_EVENT_IS( m_win
->GetKeyUpEvent(0),
402 KeyDesc(WXK_TAB
, wxMOD_SHIFT
) );
403 ASSERT_KEY_EVENT_IS( m_win
->GetKeyUpEvent(1),
404 ModKeyUp(WXK_SHIFT
) );
407 #endif // wxUSE_UIACTIONSIMULATOR