d0fb62a656
Resolve the discrepancy between modifier flags of the key events corresponding to the modifier key itself between wxMSW and wxGTK by changing the latter to follow wxMSW behaviour. Clearly document the now officially correct behaviour of the modifiers for the key events corresponding to the modifiers keys themselves in the manual. This fix also makes it unnecessary to work around this bug in the keyboard unit test so remove it from there. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65527 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
371 lines
11 KiB
C++
371 lines
11 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: tests/events/keyboard.cpp
|
|
// Purpose: Test keyboard events
|
|
// Author: Vadim Zeitlin
|
|
// Created: 2010-09-05
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) 2010 Vadim Zeitlin <vadim@wxwidgets.org>
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// 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<wxKeyEvent>();
|
|
}
|
|
|
|
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<wxKeyEvent> 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 );
|
|
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
|