From 042ddf5def3a42eefe149c2b8c8f6471454b4e31 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 11 Sep 2010 10:18:31 +0000 Subject: [PATCH] Add a simple test for keyboard events generation. Check that the events generated by wxUIActionSimulator result in the same wxKeyEvents being generated under all platforms. This is not the same as checking the event generation for the actual keys pressed by the user as there are some small differences between the two but better than nothing. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65519 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- tests/Makefile.in | 4 + tests/events/keyboard.cpp | 407 +++++++++++++++++++++++++++++++++ tests/makefile.bcc | 4 + tests/makefile.gcc | 4 + tests/makefile.vc | 4 + tests/makefile.wat | 4 + tests/test.bkl | 1 + tests/test_test_gui.dsp | 4 + tests/test_vc7_test_gui.vcproj | 3 + tests/test_vc8_test_gui.vcproj | 4 + tests/test_vc9_test_gui.vcproj | 4 + 11 files changed, 443 insertions(+) create mode 100644 tests/events/keyboard.cpp diff --git a/tests/Makefile.in b/tests/Makefile.in index 4a10638eba..47264145ba 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -195,6 +195,7 @@ TEST_GUI_OBJECTS = \ test_gui_windowtest.o \ test_gui_clone.o \ test_gui_propagation.o \ + test_gui_keyboard.o \ test_gui_fonttest.o \ test_gui_image.o \ test_gui_rawbmp.o \ @@ -803,6 +804,9 @@ test_gui_clone.o: $(srcdir)/events/clone.cpp $(TEST_GUI_ODEP) test_gui_propagation.o: $(srcdir)/events/propagation.cpp $(TEST_GUI_ODEP) $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/events/propagation.cpp +test_gui_keyboard.o: $(srcdir)/events/keyboard.cpp $(TEST_GUI_ODEP) + $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/events/keyboard.cpp + test_gui_fonttest.o: $(srcdir)/font/fonttest.cpp $(TEST_GUI_ODEP) $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/font/fonttest.cpp diff --git a/tests/events/keyboard.cpp b/tests/events/keyboard.cpp new file mode 100644 index 0000000000..9fe9a531e8 --- /dev/null +++ b/tests/events/keyboard.cpp @@ -0,0 +1,407 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: tests/events/keyboard.cpp +// Purpose: Test keyboard events +// Author: Vadim Zeitlin +// Created: 2010-09-05 +// RCS-ID: $Id$ +// Copyright: (c) 2010 Vadim Zeitlin +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "testprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_UIACTIONSIMULATOR + +#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) + { + 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; +}; + +// These functions are only needed because of wx bug: currently, modifiers key +// events are inconsistent between platforms and wxMSW generates key down event +// for e.g. WXK_CONTROL with wxMOD_CONTROL set and key up event with it unset +// while wxGTK does exactly vice versa. So we provide these helpers to make it +// possible to make the tests pass under all platforms for now but ideally they +// should all be made to behave the same and this should become unnecessary. + +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; +} + +#ifdef __WXGTK__ + +KeyDesc ModKeyDown(int keycode) +{ + // Second level bug: currently wxUIActionSimulator produces different + // modifiers than actually pressing the key. So while the above comment is + // true for keys pressed by user, when simulating them we do get the + // corresponding bit set for the modifier press events. + // + // Again, this is a bug and wxUIActionSimulator should be fixed to behave + // as the real events do but until this happens just work around this here. + return KeyDesc(keycode, GetModForKey(keycode)); +} + +KeyDesc ModKeyUp(int keycode) +{ + return KeyDesc(keycode, GetModForKey(keycode)); +} + +#else // Assume MSW-like behaviour for all the other platforms. + +KeyDesc ModKeyDown(int keycode) +{ + return KeyDesc(keycode, GetModForKey(keycode)); +} + +KeyDesc ModKeyUp(int keycode) +{ + return KeyDesc(keycode); +} + +#endif // Platforms. + +// 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 < 0x80 ) + { + // FIXME: Currently wxMSW generates 'A' key code for key down/up events + // for the 'a' physical key while wxGTK and wxOSX/Cocoa generate them + // with 'a' and it's not clear which behaviour is more correct so don't + // test this for those events, only test it for EVT_CHAR where the + // correct behaviour is clear. + + if ( t == wxEVT_CHAR ) + { + // For 7-bit ASCII Unicode keys are the same as normal key codes. + CPPUNIT_ASSERT_EQUAL_MESSAGE( "wrong Unicode key in " + msg, + (char)desc.m_keycode, + (char)ev.GetUnicodeKey() ); + } + } + else + { + // In this test we don't use any really Unicode characters so far so + // anything above 0x80 must be special keys (e.g. WXK_CONTROL &c) which + // don't have any Unicode equivalent. + 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 ); + CPPUNIT_TEST( NormalLetter ); + CPPUNIT_TEST( NormalSpecial ); + CPPUNIT_TEST( CtrlLetter ); + CPPUNIT_TEST( CtrlSpecial ); + CPPUNIT_TEST( ShiftLetter ); + CPPUNIT_TEST( ShiftSpecial ); + 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_TAB, 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_TAB, wxMOD_SHIFT) ); + + CPPUNIT_ASSERT_EQUAL( 1, m_win->GetCharCount() ); + ASSERT_KEY_EVENT_IS( m_win->GetCharEvent(), + KeyDesc(WXK_TAB, wxMOD_SHIFT) ); + + CPPUNIT_ASSERT_EQUAL( 2, m_win->GetKeyUpCount() ); + ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(0), + KeyDesc(WXK_TAB, wxMOD_SHIFT) ); + ASSERT_KEY_EVENT_IS( m_win->GetKeyUpEvent(1), + ModKeyUp(WXK_SHIFT) ); +} + +#endif // wxUSE_UIACTIONSIMULATOR diff --git a/tests/makefile.bcc b/tests/makefile.bcc index a53967ef05..f3637caa94 100644 --- a/tests/makefile.bcc +++ b/tests/makefile.bcc @@ -180,6 +180,7 @@ TEST_GUI_OBJECTS = \ $(OBJS)\test_gui_windowtest.obj \ $(OBJS)\test_gui_clone.obj \ $(OBJS)\test_gui_propagation.obj \ + $(OBJS)\test_gui_keyboard.obj \ $(OBJS)\test_gui_fonttest.obj \ $(OBJS)\test_gui_image.obj \ $(OBJS)\test_gui_rawbmp.obj \ @@ -849,6 +850,9 @@ $(OBJS)\test_gui_clone.obj: .\events\clone.cpp $(OBJS)\test_gui_propagation.obj: .\events\propagation.cpp $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\events\propagation.cpp +$(OBJS)\test_gui_keyboard.obj: .\events\keyboard.cpp + $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\events\keyboard.cpp + $(OBJS)\test_gui_fonttest.obj: .\font\fonttest.cpp $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\font\fonttest.cpp diff --git a/tests/makefile.gcc b/tests/makefile.gcc index bf03f298bb..d164e97a38 100644 --- a/tests/makefile.gcc +++ b/tests/makefile.gcc @@ -173,6 +173,7 @@ TEST_GUI_OBJECTS = \ $(OBJS)\test_gui_windowtest.o \ $(OBJS)\test_gui_clone.o \ $(OBJS)\test_gui_propagation.o \ + $(OBJS)\test_gui_keyboard.o \ $(OBJS)\test_gui_fonttest.o \ $(OBJS)\test_gui_image.o \ $(OBJS)\test_gui_rawbmp.o \ @@ -830,6 +831,9 @@ $(OBJS)\test_gui_clone.o: ./events/clone.cpp $(OBJS)\test_gui_propagation.o: ./events/propagation.cpp $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\test_gui_keyboard.o: ./events/keyboard.cpp + $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\test_gui_fonttest.o: ./font/fonttest.cpp $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< diff --git a/tests/makefile.vc b/tests/makefile.vc index e209e1b064..6160f751b0 100644 --- a/tests/makefile.vc +++ b/tests/makefile.vc @@ -175,6 +175,7 @@ TEST_GUI_OBJECTS = \ $(OBJS)\test_gui_windowtest.obj \ $(OBJS)\test_gui_clone.obj \ $(OBJS)\test_gui_propagation.obj \ + $(OBJS)\test_gui_keyboard.obj \ $(OBJS)\test_gui_fonttest.obj \ $(OBJS)\test_gui_image.obj \ $(OBJS)\test_gui_rawbmp.obj \ @@ -975,6 +976,9 @@ $(OBJS)\test_gui_clone.obj: .\events\clone.cpp $(OBJS)\test_gui_propagation.obj: .\events\propagation.cpp $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\events\propagation.cpp +$(OBJS)\test_gui_keyboard.obj: .\events\keyboard.cpp + $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\events\keyboard.cpp + $(OBJS)\test_gui_fonttest.obj: .\font\fonttest.cpp $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\font\fonttest.cpp diff --git a/tests/makefile.wat b/tests/makefile.wat index 2aeaea969c..07d754ea86 100644 --- a/tests/makefile.wat +++ b/tests/makefile.wat @@ -415,6 +415,7 @@ TEST_GUI_OBJECTS = & $(OBJS)\test_gui_windowtest.obj & $(OBJS)\test_gui_clone.obj & $(OBJS)\test_gui_propagation.obj & + $(OBJS)\test_gui_keyboard.obj & $(OBJS)\test_gui_fonttest.obj & $(OBJS)\test_gui_image.obj & $(OBJS)\test_gui_rawbmp.obj & @@ -888,6 +889,9 @@ $(OBJS)\test_gui_clone.obj : .AUTODEPEND .\events\clone.cpp $(OBJS)\test_gui_propagation.obj : .AUTODEPEND .\events\propagation.cpp $(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $< +$(OBJS)\test_gui_keyboard.obj : .AUTODEPEND .\events\keyboard.cpp + $(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $< + $(OBJS)\test_gui_fonttest.obj : .AUTODEPEND .\font\fonttest.cpp $(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $< diff --git a/tests/test.bkl b/tests/test.bkl index 555fba32e3..48f26f372a 100644 --- a/tests/test.bkl +++ b/tests/test.bkl @@ -176,6 +176,7 @@ controls/windowtest.cpp events/clone.cpp events/propagation.cpp + events/keyboard.cpp font/fonttest.cpp image/image.cpp image/rawbmp.cpp diff --git a/tests/test_test_gui.dsp b/tests/test_test_gui.dsp index dfa18f4493..c7b1e71390 100644 --- a/tests/test_test_gui.dsp +++ b/tests/test_test_gui.dsp @@ -353,6 +353,10 @@ SOURCE=.\controls\itemcontainertest.cpp # End Source File # Begin Source File +SOURCE=.\events\keyboard.cpp +# End Source File +# Begin Source File + SOURCE=.\controls\label.cpp # End Source File # Begin Source File diff --git a/tests/test_vc7_test_gui.vcproj b/tests/test_vc7_test_gui.vcproj index 82e33c436c..79d8f3292c 100644 --- a/tests/test_vc7_test_gui.vcproj +++ b/tests/test_vc7_test_gui.vcproj @@ -700,6 +700,9 @@ + + diff --git a/tests/test_vc8_test_gui.vcproj b/tests/test_vc8_test_gui.vcproj index fc6dc4c436..b372d2390c 100644 --- a/tests/test_vc8_test_gui.vcproj +++ b/tests/test_vc8_test_gui.vcproj @@ -1007,6 +1007,10 @@ RelativePath=".\controls\itemcontainertest.cpp" > + + diff --git a/tests/test_vc9_test_gui.vcproj b/tests/test_vc9_test_gui.vcproj index ddc8f51e22..7cdfdd4ed5 100644 --- a/tests/test_vc9_test_gui.vcproj +++ b/tests/test_vc9_test_gui.vcproj @@ -979,6 +979,10 @@ RelativePath=".\controls\itemcontainertest.cpp" > + + -- 2.45.2