Don't call wxYield() after key release in wxUIActionSimulator

This breaks existing unit tests using wxUIActionSimulator that do things
similar to

	wxUIActionSimulator sim;
	sim.Char('o', wxMOD_CMD);
	wxTEST_DIALOG(wxYield(), ... expected "Open" dialog ...);

because the expected dialog would be shown from inside Char(), unlike
with the wxMSW implementation and GTK until the changes of 59ad9f46e6
(Make wxUIActionSimulator works more reliably on GTK/X11, 2020-05-07).

To still make sure there is a delay after the event, sleep, if
necessary, before simulating the next event: this is still enough for wx
test suite to pass, but allows the code like above to work with both
wxMSW and wxGTK.

In fact, doing it like this makes the code simpler and removes the need
to distinguish between press and release events or maintaining the
number of currently simulated-as-depressed buttons or keys, so it also
simplifies things as a side effect.

Also add some comments and rename Default_Delay constant to a more
accurately named MIN_DELAY_BETWEEN_EVENTS.

Closes https://github.com/wxWidgets/wxWidgets/pull/2318
This commit is contained in:
Vadim Zeitlin
2021-04-10 18:36:10 +02:00
parent c82ff381f5
commit cf01fe536d

View File

@@ -16,6 +16,7 @@
#include "wx/uiaction.h"
#include "wx/event.h"
#include "wx/evtloop.h"
#include "wx/time.h"
#include "wx/private/uiaction.h"
@@ -55,17 +56,21 @@ namespace
class wxXSync
{
public:
// This constructor is used before simulating mouse move events.
wxXSync(wxX11Display& display)
: m_display(display), m_isMotion(true)
{
WaitIfNecessary();
}
wxXSync(wxX11Display& display, bool depressed)
// This constructor is used before simulating mouse button or key press or
// release events. Currently we handle presses and releases in the same
// way, so we don't use the "depressed" parameter, but it conveniently
// allows us to distinguish this ctor from the one above, so still keep it.
wxXSync(wxX11Display& display, bool WXUNUSED(depressed))
: m_display(display), m_isMotion(false)
{
depressed ? ++ms_numDepressed : --ms_numDepressed;
wxASSERT_MSG( ms_numDepressed >= 0, "Invalid call to wxXSync() ctor" );
WaitIfNecessary();
}
~wxXSync()
@@ -74,37 +79,45 @@ public:
if ( m_isMotion )
{
// We need to yield here to let things update in response to
// the move, existing tests in wx own test suite rely on this
// (i.e. start failing if this wxYield() is removed) and doing
// this doesn't seem to result in any harm.
wxYield();
}
else // it's button or key event
{
if ( ms_numDepressed > 0 )
{
// Do nothing if a key / button is still depressed.
return;
}
wxYield();
wxMilliSleep(Default_Delay);
// Don't do anything here, in particular do not call wxYield()
// as dispatching events from inside e.g. KeyDown() call would
// be unexpected -- testing code using wxUIActionSimulator
// expects such events to be generated by a call to wxYield()
// after simulating them and this is how wxMSW works.
}
ms_lastEvent = wxGetLocalTimeMillis();
}
private:
void WaitIfNecessary()
{
// Simulating events too fast results in just losing them somehow, so
// ensure that there is some minimal delay between subsequent events.
static int MIN_DELAY_BETWEEN_EVENTS = 20;
if ( wxGetLocalTimeMillis() < ms_lastEvent + MIN_DELAY_BETWEEN_EVENTS )
wxMilliSleep(MIN_DELAY_BETWEEN_EVENTS);
}
wxX11Display& m_display;
const bool m_isMotion; // false if it's button or key event.
enum
{
Default_Delay = 20 // amount of ms to sleep after key/button release.
};
static int ms_numDepressed;
// Time of the last simulated event.
static wxMilliClock_t ms_lastEvent;
wxDECLARE_NO_COPY_CLASS(wxXSync);
};
/*static*/
int wxXSync::ms_numDepressed = 0;
/* static */
wxMilliClock_t wxXSync::ms_lastEvent = 0;
// Base class for both available X11 implementations.
class wxUIActionSimulatorX11Impl : public wxUIActionSimulatorImpl