Process events in order to avoid X11 input method being confused

This commit is contained in:
kimci86 2022-10-11 22:46:46 +02:00 committed by Lukas Dürrenberger
parent b11328f386
commit f796205a21
2 changed files with 73 additions and 71 deletions

View File

@ -84,21 +84,6 @@ 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 initalKeycode, Time initialTime) : keycode(initalKeycode), time(initialTime) {}
// 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)
{ {
@ -834,14 +819,61 @@ void WindowImplX11::processEvents()
// Pick out the events that are interesting for this window // 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(); // This function implements a workaround to properly discard
m_events.pop_front(); // repeated key events when necessary. The problem is that the
// system's key events policy doesn't match SFML's one: X server will generate
// both repeated KeyPress and KeyRelease events when maintaining a key down, while
// SFML only wants repeated KeyPress events. Thus, we have to:
// - Discard duplicated KeyRelease events when m_keyRepeat is true
// - Discard both duplicated KeyPress and KeyRelease events when m_keyRepeat is false
bool processThisEvent = true;
// Detect repeated key events
while (event.type == KeyRelease)
{
XEvent nextEvent;
if (XCheckIfEvent(m_display, &nextEvent, checkEvent, reinterpret_cast<XPointer>(m_window)))
{
if ((nextEvent.type == KeyPress) && (nextEvent.xkey.keycode == event.xkey.keycode) &&
(event.xkey.time <= nextEvent.xkey.time) && (nextEvent.xkey.time <= event.xkey.time + 1))
{
// This sequence of events comes from maintaining a key down
if (m_keyRepeat)
{
// Ignore the KeyRelease event and process the KeyPress event
event = nextEvent;
break;
}
else
{
// Ignore both events
processThisEvent = false;
break;
}
}
else
{
// This sequence of events does not come from maintaining a key down,
// so process the KeyRelease event normally,
processEvent(event); processEvent(event);
// but loop because the next event can be the first half
// of a sequence coming from maintaining a key down.
event = nextEvent;
}
}
else
{
// No event after this KeyRelease event so assume it can be processed.
break;
}
}
if (processThisEvent)
{
processEvent(event);
}
} }
// Process clipboard window events // Process clipboard window events
@ -1725,35 +1757,6 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
{ {
using namespace WindowsImplX11Impl; using namespace WindowsImplX11Impl;
// This function implements a workaround to properly discard
// repeated key events when necessary. The problem is that the
// system's key events policy doesn't match SFML's one: X server will generate
// both repeated KeyPress and KeyRelease events when maintaining a key down, while
// SFML only wants repeated KeyPress events. Thus, we have to:
// - Discard duplicated KeyRelease events when KeyRepeatEnabled is true
// - Discard both duplicated KeyPress and KeyRelease events when KeyRepeatEnabled is false
// Detect repeated key events
if (windowEvent.type == KeyRelease)
{
// Find the next KeyPress event with matching keycode and time
std::deque<XEvent>::iterator iter = std::find_if(
m_events.begin(),
m_events.end(),
KeyRepeatFinder(windowEvent.xkey.keycode, windowEvent.xkey.time)
);
if (iter != m_events.end())
{
// 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;
}
}
// Convert the X11 event to a sf::Event // Convert the X11 event to a sf::Event
switch (windowEvent.type) switch (windowEvent.type)
{ {

View File

@ -305,7 +305,6 @@ private:
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
std::deque<XEvent> m_events; ///< Queue we use to store pending events for this window
bool m_isExternal; ///< Tell whether the window has been created externally or by SFML bool m_isExternal; ///< Tell whether the window has been created externally or by SFML
RRMode m_oldVideoMode; ///< Video mode in use before we switch to fullscreen RRMode m_oldVideoMode; ///< Video mode in use before we switch to fullscreen
RRCrtc m_oldRRCrtc; ///< RRCrtc in use before we switch to fullscreen RRCrtc m_oldRRCrtc; ///< RRCrtc in use before we switch to fullscreen