mirror of
https://github.com/SFML/SFML.git
synced 2024-11-28 22:31:09 +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/WindowEnums.hpp>
|
||||||
#include <SFML/Window/WindowHandle.hpp>
|
#include <SFML/Window/WindowHandle.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
#include <SFML/System/Vector2.hpp>
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -202,11 +203,12 @@ public:
|
|||||||
/// \brief Wait for an event and return it
|
/// \brief Wait for an event and return it
|
||||||
///
|
///
|
||||||
/// This function is blocking: if there's no pending event then
|
/// This function is blocking: if there's no pending event then
|
||||||
/// it will wait until an event is received. After this function
|
/// it will wait until an event is received or until the provided
|
||||||
/// returns if no error occurred, the returned event will not be
|
/// timeout elapses. After this function returns if no error nor
|
||||||
/// empty. This function is typically used when you have a thread
|
/// timeout occurred, the returned event will not be empty.
|
||||||
/// that is dedicated to events handling: you want to make this
|
/// This function is typically used when you have a thread that is
|
||||||
/// thread sleep as long as no new event is received.
|
/// dedicated to events handling: you want to make this thread sleep
|
||||||
|
/// as long as no new event is received.
|
||||||
/// \code
|
/// \code
|
||||||
/// if (const auto event = window.waitEvent())
|
/// if (const auto event = window.waitEvent())
|
||||||
/// {
|
/// {
|
||||||
@ -214,12 +216,14 @@ public:
|
|||||||
/// }
|
/// }
|
||||||
/// \endcode
|
/// \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
|
/// \see pollEvent
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
[[nodiscard]] Event waitEvent();
|
[[nodiscard]] Event waitEvent(Time timeout = Time::Zero);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Get the position of the window
|
/// \brief Get the position of the window
|
||||||
|
@ -149,17 +149,17 @@ bool WindowBase::isOpen() const
|
|||||||
Event WindowBase::pollEvent()
|
Event WindowBase::pollEvent()
|
||||||
{
|
{
|
||||||
Event event;
|
Event event;
|
||||||
if (m_impl && (event = m_impl->popEvent(false)))
|
if (m_impl && (event = m_impl->pollEvent()))
|
||||||
filterEvent(event);
|
filterEvent(event);
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Event WindowBase::waitEvent()
|
Event WindowBase::waitEvent(Time timeout)
|
||||||
{
|
{
|
||||||
Event event;
|
Event event;
|
||||||
if (m_impl && (event = m_impl->popEvent(true)))
|
if (m_impl && (event = m_impl->waitEvent(timeout)))
|
||||||
filterEvent(event);
|
filterEvent(event);
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <SFML/System/Time.hpp>
|
#include <SFML/System/Time.hpp>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <cmath>
|
#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 the event queue is empty, let's first check if new events are available from the OS
|
||||||
if (m_events.empty())
|
if (m_events.empty())
|
||||||
{
|
populateEventQueue();
|
||||||
// Get events from the system
|
|
||||||
processJoystickEvents();
|
|
||||||
processSensorEvents();
|
|
||||||
processEvents();
|
|
||||||
|
|
||||||
// In blocking mode, we must process events until one is triggered
|
return popEvent();
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Event WindowImpl::popEvent()
|
||||||
|
{
|
||||||
Event event;
|
Event event;
|
||||||
|
|
||||||
// Pop the first event of the queue, if it is not empty
|
|
||||||
if (!m_events.empty())
|
if (!m_events.empty())
|
||||||
{
|
{
|
||||||
event = m_events.front();
|
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,
|
bool WindowImpl::createVulkanSurface([[maybe_unused]] const VkInstance& instance,
|
||||||
[[maybe_unused]] VkSurfaceKHR& surface,
|
[[maybe_unused]] VkSurfaceKHR& surface,
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
class String;
|
class String;
|
||||||
|
class Time;
|
||||||
|
|
||||||
namespace priv
|
namespace priv
|
||||||
{
|
{
|
||||||
@ -121,21 +122,28 @@ public:
|
|||||||
void setJoystickThreshold(float threshold);
|
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
|
/// If there's no event available, this function calls the
|
||||||
/// window's internal event processing function.
|
/// 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
|
/// \brief Get the OS-specific handle of the window
|
||||||
@ -325,6 +333,12 @@ protected:
|
|||||||
private:
|
private:
|
||||||
struct JoystickStatesImpl;
|
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
|
/// \brief Read the joysticks state and generate the appropriate events
|
||||||
///
|
///
|
||||||
@ -337,6 +351,12 @@ private:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void processSensorEvents();
|
void processSensorEvents();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Read joystick, sensors, and OS state and populate event queue
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void populateEventQueue();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include <WindowUtil.hpp>
|
#include <WindowUtil.hpp>
|
||||||
|
#include <chrono>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
TEST_CASE("[Window] sf::WindowBase", runDisplayTests())
|
TEST_CASE("[Window] sf::WindowBase", runDisplayTests())
|
||||||
@ -104,14 +105,38 @@ TEST_CASE("[Window] sf::WindowBase", runDisplayTests())
|
|||||||
|
|
||||||
SECTION("pollEvent()")
|
SECTION("pollEvent()")
|
||||||
{
|
{
|
||||||
sf::WindowBase windowBase;
|
SECTION("Uninitialized window")
|
||||||
CHECK(!windowBase.pollEvent());
|
{
|
||||||
|
sf::WindowBase windowBase;
|
||||||
|
CHECK(!windowBase.pollEvent());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("waitEvent()")
|
SECTION("waitEvent()")
|
||||||
{
|
{
|
||||||
sf::WindowBase windowBase;
|
SECTION("Uninitialized window")
|
||||||
CHECK(!windowBase.waitEvent());
|
{
|
||||||
|
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")
|
SECTION("Set/get position")
|
||||||
|
Loading…
Reference in New Issue
Block a user