Fixed X11 key repeat handling not filtering out events from other windows. (Fixes #1223)

This commit is contained in:
binary1248 2017-09-25 13:38:58 +02:00 committed by Lukas Dürrenberger
parent 0dd24c8f1f
commit 44944989e8
2 changed files with 56 additions and 38 deletions

View File

@ -77,6 +77,21 @@ namespace
static const unsigned int maxTrialsCount = 5; static const unsigned int maxTrialsCount = 5;
// Predicate we use to find key repeat events in processEvent
struct KeyRepeatFinder
{
KeyRepeatFinder(unsigned int keycode, Time time) : keycode(keycode), time(time) {}
// Predicate operator that checks event type, keycode and timestamp
bool operator()(const XEvent& event)
{
return ((event.type == KeyPress) && (event.xkey.keycode == keycode) && (event.xkey.time - time < 2));
}
unsigned int keycode;
Time time;
};
// Filter the events received by windows (only allow those matching a specific window) // Filter the events received by windows (only allow those matching a specific window)
Bool checkEvent(::Display*, XEvent* event, XPointer userData) Bool checkEvent(::Display*, XEvent* event, XPointer userData)
{ {
@ -752,8 +767,16 @@ WindowHandle WindowImplX11::getSystemHandle() const
void WindowImplX11::processEvents() void WindowImplX11::processEvents()
{ {
XEvent event; XEvent event;
// Pick out the events that are interesting for this window
while (XCheckIfEvent(m_display, &event, &checkEvent, reinterpret_cast<XPointer>(m_window))) while (XCheckIfEvent(m_display, &event, &checkEvent, reinterpret_cast<XPointer>(m_window)))
m_events.push_back(event);
// Handle the events for this window that we just picked out
while (!m_events.empty())
{ {
event = m_events.front();
m_events.pop_front();
processEvent(event); processEvent(event);
} }
} }
@ -1533,29 +1556,23 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
// - Discard both duplicated KeyPress and KeyRelease events when KeyRepeatEnabled is false // - Discard both duplicated KeyPress and KeyRelease events when KeyRepeatEnabled is false
// Detect repeated key events // Detect repeated key events
// (code shamelessly taken from SDL)
if (windowEvent.type == KeyRelease) if (windowEvent.type == KeyRelease)
{ {
// Check if there's a matching KeyPress event in the queue // Find the next KeyPress event with matching keycode and time
XEvent nextEvent; std::deque<XEvent>::iterator iter = std::find_if(
if (XPending(m_display)) m_events.begin(),
{ m_events.end(),
// Grab it but don't remove it from the queue, it still needs to be processed :) KeyRepeatFinder(windowEvent.xkey.keycode, windowEvent.xkey.time)
XPeekEvent(m_display, &nextEvent); );
if (nextEvent.type == KeyPress)
{
// Check if it is a duplicated event (same timestamp as the KeyRelease event)
if ((nextEvent.xkey.keycode == windowEvent.xkey.keycode) &&
(nextEvent.xkey.time - windowEvent.xkey.time < 2))
{
// If we don't want repeated events, remove the next KeyPress from the queue
if (!m_keyRepeat)
XNextEvent(m_display, &nextEvent);
// This KeyRelease is a repeated event and we don't want it if (iter != m_events.end())
return false; {
} // If we don't want repeated events, remove the next KeyPress from the queue
} if (!m_keyRepeat)
m_events.erase(iter);
// This KeyRelease is a repeated event and we don't want it
return false;
} }
} }

View File

@ -267,24 +267,25 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
::Window m_window; ///< X identifier defining our window ::Window m_window; ///< X identifier defining our window
::Display* m_display; ///< Pointer to the display ::Display* m_display; ///< Pointer to the display
int m_screen; ///< Screen identifier int m_screen; ///< Screen identifier
XIM m_inputMethod; ///< Input method linked to the X display XIM m_inputMethod; ///< Input method linked to the X display
XIC m_inputContext; ///< Input context used to get unicode input in our window XIC m_inputContext; ///< Input context used to get unicode input in our window
bool m_isExternal; ///< Tell whether the window has been created externally or by SFML std::deque<XEvent> m_events; ///< Queue we use to store pending events for this window
int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen bool m_isExternal; ///< Tell whether the window has been created externally or by SFML
::Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hiding, we must create a transparent one int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen
::Cursor m_lastCursor; ///< Last cursor used -- this data is not owned by the window and is required to be always valid ::Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hiding, we must create a transparent one
bool m_keyRepeat; ///< Is the KeyRepeat feature enabled? ::Cursor m_lastCursor; ///< Last cursor used -- this data is not owned by the window and is required to be always valid
Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only) bool m_keyRepeat; ///< Is the KeyRepeat feature enabled?
bool m_useSizeHints; ///< Is the size of the window fixed with size hints? Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only)
bool m_fullscreen; ///< Is the window in fullscreen? bool m_useSizeHints; ///< Is the size of the window fixed with size hints?
bool m_cursorGrabbed; ///< Is the mouse cursor trapped? bool m_fullscreen; ///< Is the window in fullscreen?
bool m_windowMapped; ///< Has the window been mapped by the window manager? bool m_cursorGrabbed; ///< Is the mouse cursor trapped?
Pixmap m_iconPixmap; ///< The current icon pixmap if in use bool m_windowMapped; ///< Has the window been mapped by the window manager?
Pixmap m_iconMaskPixmap; ///< The current icon mask pixmap if in use Pixmap m_iconPixmap; ///< The current icon pixmap if in use
::Time m_lastInputTime; ///< Last time we received user input Pixmap m_iconMaskPixmap; ///< The current icon mask pixmap if in use
::Time m_lastInputTime; ///< Last time we received user input
}; };
} // namespace priv } // namespace priv