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
< WXK_START
)
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() );
200 // Key codes above WXK_START don't correspond to printable characters.
201 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong non-zero Unicode key in " + msg
,
203 (int)ev
.GetUnicodeKey() );
205 #endif // wxUSE_UNICODE
207 CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong modifiers in " + msg
,
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)
216 } // anonymous namespace
218 // --------------------------------------------------------------------------
220 // --------------------------------------------------------------------------
222 class KeyboardEventTestCase
: public CppUnit
::TestCase
225 KeyboardEventTestCase() {}
227 virtual void setUp();
228 virtual void tearDown();
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();
241 void NormalSpecial();
247 KeyboardTestWindow
*m_win
;
249 wxDECLARE_NO_COPY_CLASS(KeyboardEventTestCase
);
252 wxREGISTER_UNIT_TEST(KeyboardEvent
);
254 void KeyboardEventTestCase
::setUp()
256 m_win
= new KeyboardTestWindow(wxTheApp
->GetTopWindow());
258 wxYield(); // needed to show the new window
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();
267 void KeyboardEventTestCase
::tearDown()
272 void KeyboardEventTestCase
::NormalLetter()
274 wxUIActionSimulator sim
;
278 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetKeyDownCount() );
279 ASSERT_KEY_EVENT_IS( m_win
->GetKeyDownEvent(), 'A' );
281 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetCharCount() );
282 ASSERT_KEY_EVENT_IS( m_win
->GetCharEvent(), 'a' );
284 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetKeyUpCount() );
285 ASSERT_KEY_EVENT_IS( m_win
->GetKeyUpEvent(), 'A' );
288 void KeyboardEventTestCase
::NormalSpecial()
290 wxUIActionSimulator sim
;
294 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetKeyDownCount() );
295 ASSERT_KEY_EVENT_IS( m_win
->GetKeyDownEvent(), WXK_END
);
297 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetCharCount() );
298 ASSERT_KEY_EVENT_IS( m_win
->GetCharEvent(), WXK_END
);
300 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetKeyUpCount() );
301 ASSERT_KEY_EVENT_IS( m_win
->GetKeyUpEvent(), WXK_END
);
304 void KeyboardEventTestCase
::CtrlLetter()
306 wxUIActionSimulator sim
;
307 sim
.Char('z', wxMOD_CONTROL
);
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
) );
316 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetCharCount() );
317 ASSERT_KEY_EVENT_IS( m_win
->GetCharEvent(),
318 KeyDesc('\x1a', wxMOD_CONTROL
) );
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
) );
327 void KeyboardEventTestCase
::CtrlSpecial()
329 wxUIActionSimulator sim
;
330 sim
.Char(WXK_PAGEUP
, wxMOD_CONTROL
);
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
) );
339 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetCharCount() );
340 ASSERT_KEY_EVENT_IS( m_win
->GetCharEvent(),
341 KeyDesc(WXK_PAGEUP
, wxMOD_CONTROL
) );
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
) );
350 void KeyboardEventTestCase
::ShiftLetter()
352 wxUIActionSimulator sim
;
353 sim
.Char('Q', wxMOD_SHIFT
);
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
) );
362 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetCharCount() );
363 ASSERT_KEY_EVENT_IS( m_win
->GetCharEvent(),
364 KeyDesc('Q', wxMOD_SHIFT
) );
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
) );
373 void KeyboardEventTestCase
::ShiftSpecial()
375 wxUIActionSimulator sim
;
376 sim
.Char(WXK_TAB
, wxMOD_SHIFT
);
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
) );
385 CPPUNIT_ASSERT_EQUAL( 1, m_win
->GetCharCount() );
386 ASSERT_KEY_EVENT_IS( m_win
->GetCharEvent(),
387 KeyDesc(WXK_TAB
, wxMOD_SHIFT
) );
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
) );
396 #endif // wxUSE_UIACTIONSIMULATOR