mirror of
https://github.com/SFML/SFML.git
synced 2024-11-25 04:41:05 +08:00
Add timeout
parameter to waitEvent
This commit is contained in:
parent
51efe50ec4
commit
e7b23ffcd1
@ -33,6 +33,7 @@
|
||||
#include <SFML/Window/WindowEnums.hpp>
|
||||
#include <SFML/Window/WindowHandle.hpp>
|
||||
|
||||
#include <SFML/System/Time.hpp>
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
|
||||
#include <memory>
|
||||
@ -202,11 +203,12 @@ public:
|
||||
/// \brief Wait for an event and return it
|
||||
///
|
||||
/// This function is blocking: if there's no pending event then
|
||||
/// it will wait until an event is received. After this function
|
||||
/// returns if no error occurred, the returned event will not be
|
||||
/// empty. This function is typically used when you have a thread
|
||||
/// that is dedicated to events handling: you want to make this
|
||||
/// thread sleep as long as no new event is received.
|
||||
/// it will wait until an event is received or until the provided
|
||||
/// timeout elapses. After this function returns if no error nor
|
||||
/// timeout occurred, the returned event will not be empty.
|
||||
/// This function is typically used when you have a thread that is
|
||||
/// dedicated to events handling: you want to make this thread sleep
|
||||
/// as long as no new event is received.
|
||||
/// \code
|
||||
/// if (const auto event = window.waitEvent())
|
||||
/// {
|
||||
@ -214,12 +216,14 @@ public:
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \return The event
|
||||
/// \param timeout Maximum time to wait (`Time::Zero` for infinite)
|
||||
///
|
||||
/// \return The event; will be `Empty` (convertible to `false`) on timeout or if window was closed
|
||||
///
|
||||
/// \see pollEvent
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] Event waitEvent();
|
||||
[[nodiscard]] Event waitEvent(Time timeout = Time::Zero);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the position of the window
|
||||
|
@ -149,17 +149,17 @@ bool WindowBase::isOpen() const
|
||||
Event WindowBase::pollEvent()
|
||||
{
|
||||
Event event;
|
||||
if (m_impl && (event = m_impl->popEvent(false)))
|
||||
if (m_impl && (event = m_impl->pollEvent()))
|
||||
filterEvent(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Event WindowBase::waitEvent()
|
||||
Event WindowBase::waitEvent(Time timeout)
|
||||
{
|
||||
Event event;
|
||||
if (m_impl && (event = m_impl->popEvent(true)))
|
||||
if (m_impl && (event = m_impl->waitEvent(timeout)))
|
||||
filterEvent(event);
|
||||
return event;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <SFML/System/Time.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include <cmath>
|
||||
@ -175,35 +176,46 @@ void WindowImpl::setMaximumSize(const std::optional<Vector2u>& maximumSize)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Event WindowImpl::popEvent(bool block)
|
||||
Event WindowImpl::waitEvent(Time timeout)
|
||||
{
|
||||
const auto timedOut = [&, startTime = std::chrono::steady_clock::now()]
|
||||
{
|
||||
const bool infiniteTimeout = timeout == Time::Zero;
|
||||
return !infiniteTimeout && (std::chrono::steady_clock::now() - startTime) >= timeout.toDuration();
|
||||
};
|
||||
|
||||
// If the event queue is empty, let's first check if new events are available from the OS
|
||||
if (m_events.empty())
|
||||
populateEventQueue();
|
||||
|
||||
// Here we use a manual wait loop instead of the optimized wait-event provided by the OS,
|
||||
// so that we don't skip joystick events (which require polling)
|
||||
while (m_events.empty() && !timedOut())
|
||||
{
|
||||
sleep(milliseconds(10));
|
||||
populateEventQueue();
|
||||
}
|
||||
|
||||
return popEvent();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Event WindowImpl::pollEvent()
|
||||
{
|
||||
// If the event queue is empty, let's first check if new events are available from the OS
|
||||
if (m_events.empty())
|
||||
{
|
||||
// Get events from the system
|
||||
processJoystickEvents();
|
||||
processSensorEvents();
|
||||
processEvents();
|
||||
populateEventQueue();
|
||||
|
||||
// In blocking mode, we must process events until one is triggered
|
||||
if (block)
|
||||
{
|
||||
// Here we use a manual wait loop instead of the optimized
|
||||
// wait-event provided by the OS, so that we don't skip joystick
|
||||
// events (which require polling)
|
||||
while (m_events.empty())
|
||||
{
|
||||
sleep(milliseconds(10));
|
||||
processJoystickEvents();
|
||||
processSensorEvents();
|
||||
processEvents();
|
||||
}
|
||||
}
|
||||
return popEvent();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Event WindowImpl::popEvent()
|
||||
{
|
||||
Event event;
|
||||
|
||||
// Pop the first event of the queue, if it is not empty
|
||||
if (!m_events.empty())
|
||||
{
|
||||
event = m_events.front();
|
||||
@ -311,6 +323,15 @@ void WindowImpl::processSensorEvents()
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImpl::populateEventQueue()
|
||||
{
|
||||
processJoystickEvents();
|
||||
processSensorEvents();
|
||||
processEvents();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool WindowImpl::createVulkanSurface([[maybe_unused]] const VkInstance& instance,
|
||||
[[maybe_unused]] VkSurfaceKHR& surface,
|
||||
|
@ -55,6 +55,7 @@
|
||||
namespace sf
|
||||
{
|
||||
class String;
|
||||
class Time;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
@ -121,21 +122,28 @@ public:
|
||||
void setJoystickThreshold(float threshold);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Return the next window event available
|
||||
/// \brief Wait for and return the next available window event
|
||||
///
|
||||
/// If there's no event available, this function calls the
|
||||
/// window's internal event processing function.
|
||||
/// The \a block parameter controls the behavior of the function
|
||||
/// if no event is available: if it is true then the function
|
||||
/// doesn't return until a new event is triggered; otherwise it
|
||||
/// returns an empty event to indicate that no event is available.
|
||||
///
|
||||
/// \param block Use true to block the thread until an event arrives
|
||||
/// \param timeout Maximum time to wait (`Time::Zero` for infinite)
|
||||
///
|
||||
/// \return The event; can be `Empty` (convertible to `false`) if not blocking
|
||||
/// \return The event on success, `Event::Empty` otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
Event popEvent(bool block);
|
||||
[[nodiscard]] Event waitEvent(Time timeout);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Return the next window event, if available
|
||||
///
|
||||
/// If there's no event available, this function calls the
|
||||
/// window's internal event processing function.
|
||||
///
|
||||
/// \return The event if available, `Event::Empty` otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] Event pollEvent();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the OS-specific handle of the window
|
||||
@ -325,6 +333,12 @@ protected:
|
||||
private:
|
||||
struct JoystickStatesImpl;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Pop the first event of the queue if available, otherwise an empty event
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] Event popEvent();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Read the joysticks state and generate the appropriate events
|
||||
///
|
||||
@ -337,6 +351,12 @@ private:
|
||||
////////////////////////////////////////////////////////////
|
||||
void processSensorEvents();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Read joystick, sensors, and OS state and populate event queue
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void populateEventQueue();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <WindowUtil.hpp>
|
||||
#include <chrono>
|
||||
#include <type_traits>
|
||||
|
||||
TEST_CASE("[Window] sf::WindowBase", runDisplayTests())
|
||||
@ -103,17 +104,41 @@ TEST_CASE("[Window] sf::WindowBase", runDisplayTests())
|
||||
}
|
||||
|
||||
SECTION("pollEvent()")
|
||||
{
|
||||
SECTION("Uninitialized window")
|
||||
{
|
||||
sf::WindowBase windowBase;
|
||||
CHECK(!windowBase.pollEvent());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("waitEvent()")
|
||||
{
|
||||
SECTION("Uninitialized window")
|
||||
{
|
||||
sf::WindowBase windowBase;
|
||||
CHECK(!windowBase.waitEvent());
|
||||
}
|
||||
|
||||
SECTION("Initialized window")
|
||||
{
|
||||
sf::WindowBase windowBase(sf::VideoMode({360, 240}), "WindowBase Tests");
|
||||
|
||||
constexpr auto timeout = sf::milliseconds(100);
|
||||
|
||||
const auto startTime = std::chrono::steady_clock::now();
|
||||
const auto event = windowBase.waitEvent(timeout);
|
||||
const auto elapsed = std::chrono::steady_clock::now() - startTime;
|
||||
|
||||
REQUIRE(elapsed < (timeout + sf::milliseconds(50)).toDuration());
|
||||
|
||||
if (elapsed <= timeout.toDuration())
|
||||
CHECK(event);
|
||||
else
|
||||
CHECK(!event);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Set/get position")
|
||||
{
|
||||
sf::WindowBase windowBase;
|
||||
|
Loading…
Reference in New Issue
Block a user