/////////////////////////////////////////////////////////////////////////////// // Name: tests/events/keyboard.cpp // Purpose: Test keyboard events // Author: Vadim Zeitlin // Created: 2010-09-05 // Copyright: (c) 2010 Vadim Zeitlin /////////////////////////////////////////////////////////////////////////////// // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- #include "testprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif // FIXME: As all the other tests involving wxUIActionSimulator, this one is // broken under OS X, the test window siply never gets any events. #if wxUSE_UIACTIONSIMULATOR && !defined(__WXOSX__) #ifndef WX_PRECOMP #include "wx/app.h" #include "wx/event.h" #include "wx/window.h" #endif // WX_PRECOMP #include "wx/uiaction.h" #include "wx/vector.h" namespace { // ---------------------------------------------------------------------------- // test window verifying the event generation // ---------------------------------------------------------------------------- class KeyboardTestWindow : public wxWindow { public: KeyboardTestWindow(wxWindow *parent) : wxWindow(parent, wxID_ANY, wxPoint(0, 0), parent->GetClientSize()) { Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(KeyboardTestWindow::OnKeyDown)); Connect(wxEVT_CHAR, wxKeyEventHandler(KeyboardTestWindow::OnChar)); Connect(wxEVT_KEY_UP, wxKeyEventHandler(KeyboardTestWindow::OnKeyUp)); } unsigned GetKeyDownCount() const { return m_keyDownEvents.size(); } unsigned GetCharCount() const { return m_charEvents.size(); } unsigned GetKeyUpCount() const { return m_keyUpEvents.size(); } const wxKeyEvent& GetKeyDownEvent(unsigned n = 0) const { return m_keyDownEvents[n]; } const wxKeyEvent& GetCharEvent(unsigned n = 0) const { return m_charEvents[n]; } const wxKeyEvent& GetKeyUpEvent(unsigned n = 0) const { return m_keyUpEvents[n]; } void ClearEvents() { m_keyDownEvents = m_charEvents = m_keyUpEvents = wxVector(); } private: void OnKeyDown(wxKeyEvent& event) { m_keyDownEvents.push_back(event); event.Skip(); } void OnChar(wxKeyEvent& event) { m_charEvents.push_back(event); event.Skip(); } void OnKeyUp(wxKeyEvent& event) { m_keyUpEvents.push_back(event); event.Skip(); } wxVector m_keyDownEvents, m_charEvents, m_keyUpEvents; wxDECLARE_NO_COPY_CLASS(KeyboardTestWindow); }; // Object describing the (main fields of) keyboard event. struct KeyDesc { KeyDesc(int keycode, int mods = 0) : m_keycode(keycode), m_mods(mods) { } int m_keycode; int m_mods; }; // Helper for ModKeyDown(). int GetModForKey(int keycode) { switch ( keycode ) { case WXK_CONTROL: return wxMOD_CONTROL; case WXK_SHIFT: return wxMOD_SHIFT; case WXK_ALT: return wxMOD_ALT; default: wxFAIL_MSG( "Unknown modifier key" ); } return wxMOD_NONE; } // Helper function to allow writing just ModKeyDown(WXK_CONTROL) instead of // more verbose KeyDesc(WXK_CONTROL, wxMOD_CONTROL). KeyDesc ModKeyDown(int keycode) { return KeyDesc(keycode, GetModForKey(keycode)); } // Another helper provided for symmetry with ModKeyDown() only. KeyDesc ModKeyUp(int keycode) { return KeyDesc(keycode); } // Verify that the event object corresponds to our idea of what it should be. void TestEvent(int line, const wxKeyEvent& ev, const KeyDesc& desc) { // Construct the message we'll display if an assert fails. std::string msg; const wxEventType t = ev.GetEventType(); if ( t == wxEVT_KEY_DOWN ) msg = "key down"; else if ( t == wxEVT_CHAR ) msg = "char"; else if ( t == wxEVT_KEY_UP ) msg = "key up"; else CPPUNIT_FAIL( "unknown event type" ); msg += " event at line "; msg += wxString::Format("%d", line).mb_str(); CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong key code in " + msg, desc.m_keycode, ev.GetKeyCode() ); #if wxUSE_UNICODE if ( desc.m_keycode < WXK_START ) { // For Latin-1 our key code is the same as Unicode character value. CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong Unicode key in " + msg, (char)desc.m_keycode, (char)ev.GetUnicodeKey() ); } else // Special key { // Key codes above WXK_START don't correspond to printable characters. CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong non-zero Unicode key in " + msg, 0, (int)ev.GetUnicodeKey() ); } #endif // wxUSE_UNICODE CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong modifiers in " + msg, desc.m_mods, ev.GetModifiers() ); } // Call TestEvent() passing it the line number from where it was called: this // is useful for interpreting the assert failure messages. #define ASSERT_KEY_EVENT_IS( ev, desc ) TestEvent(__LINE__, ev, desc) } // anonymous namespace // -------------------------------------------------------------------------- // test class // -------------------------------------------------------------------------- class KeyboardEventTestCase : public CppUnit::TestCase { public: KeyboardEventTestCase() {} virtual void setUp(); virtual void tearDown(); private: CPPUNIT_TEST_SUITE( KeyboardEventTestCase ); // FIXME: this test will cause test_gui segmentation fault. Disable it for now. #if !defined(__WXUNIVERSAL__) && !defined (__WXX11__) CPPUNIT_TEST( NormalLetter ); CPPUNIT_TEST( NormalSpecial ); CPPUNIT_TEST( CtrlLetter ); CPPUNIT_TEST( CtrlSpecial ); CPPUNIT_TEST( ShiftLetter ); CPPUNIT_TEST( ShiftSpecial ); #endif CPPUNIT_TEST_SUITE_END(); void NormalLetter(); void NormalSpecial(); void CtrlLetter(); void CtrlSpecial(); void ShiftLetter(); void ShiftSpecial(); KeyboardTestWindow *m_win; wxDECLARE_NO_COPY_CLASS(KeyboardEventTestCase); }; wxREGISTER_UNIT_TEST(KeyboardEvent); void KeyboardEventTestCase::setUp() { m_win = new KeyboardTestWindow(wxTheApp->GetTopWindow()); m_win->SetFocus(); wxYield(); // needed to show the new window // The window might get some key up events when it's being shown if the key // was pressed when the program was started and released after the window // was shown, e.g. this does happen in practice when launching the test // from command line. Simply discard all the spurious events so far. m_win->ClearEvents(); } void KeyboardEventTestCase::tearDown() { m_win->Destroy(); } void KeyboardEventTestCase::NormalLetter() { wxUIActionSimulator sim; sim.Char('a'); wxYield(); CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyDownCount() ); ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(), 'A' ); CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() ); ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), 'a' ); CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyUpCount() ); ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(), 'A' ); } void KeyboardEventTestCase::NormalSpecial() { wxUIActionSimulator sim; sim.Char(WXK_END); wxYield(); CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyDownCount() ); ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(), WXK_END ); CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() ); ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), WXK_END ); CPPUNIT_ASSERT_EQUAL( 1, m_win->GetKeyUpCount() ); ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(), WXK_END ); } void KeyboardEventTestCase::CtrlLetter() { wxUIActionSimulator sim; sim.Char('z', wxMOD_CONTROL); wxYield(); CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() ); ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0), ModKeyDown(WXK_CONTROL) ); ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1), KeyDesc('Z', wxMOD_CONTROL) ); CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() ); ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), KeyDesc('\x1a', wxMOD_CONTROL) ); CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() ); ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0), KeyDesc('Z', wxMOD_CONTROL) ); ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1), ModKeyUp(WXK_CONTROL) ); } void KeyboardEventTestCase::CtrlSpecial() { wxUIActionSimulator sim; sim.Char(WXK_PAGEUP, wxMOD_CONTROL); wxYield(); CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() ); ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0), ModKeyDown(WXK_CONTROL) ); ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1), KeyDesc(WXK_PAGEUP, wxMOD_CONTROL) ); CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() ); ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), KeyDesc(WXK_PAGEUP, wxMOD_CONTROL) ); CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() ); ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0), KeyDesc(WXK_PAGEUP, wxMOD_CONTROL) ); ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1), ModKeyUp(WXK_CONTROL) ); } void KeyboardEventTestCase::ShiftLetter() { wxUIActionSimulator sim; sim.Char('Q', wxMOD_SHIFT); wxYield(); CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() ); ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0), ModKeyDown(WXK_SHIFT) ); ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1), KeyDesc('Q', wxMOD_SHIFT) ); CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() ); ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), KeyDesc('Q', wxMOD_SHIFT) ); CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() ); ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0), KeyDesc('Q', wxMOD_SHIFT) ); ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1), ModKeyUp(WXK_SHIFT) ); } void KeyboardEventTestCase::ShiftSpecial() { wxUIActionSimulator sim; sim.Char(WXK_F3, wxMOD_SHIFT); wxYield(); CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyDownCount() ); ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(0), ModKeyDown(WXK_SHIFT) ); ASSERT_KEY_EVENT_IS( m_win->GetKeyDownEvent(1), KeyDesc(WXK_F3, wxMOD_SHIFT) ); CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() ); ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), KeyDesc(WXK_F3, wxMOD_SHIFT) ); CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() ); ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0), KeyDesc(WXK_F3, wxMOD_SHIFT) ); ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1), ModKeyUp(WXK_SHIFT) ); } #endif // wxUSE_UIACTIONSIMULATOR