mirror of
https://github.com/SFML/SFML.git
synced 2024-11-28 22:31:09 +08:00
Process events in order to avoid X11 input method being confused
This commit is contained in:
parent
b11328f386
commit
f796205a21
@ -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
|
||||||
processEvent(event);
|
// 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);
|
||||||
|
// 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)
|
||||||
{
|
{
|
||||||
|
@ -300,26 +300,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
|
||||||
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
|
::Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hiding, we must create a transparent one
|
||||||
::Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hiding, we must create a transparent one
|
::Cursor m_lastCursor; ///< Last cursor used -- this data is not owned by the window and is required to be always valid
|
||||||
::Cursor m_lastCursor; ///< Last cursor used -- this data is not owned by the window and is required to be always valid
|
bool m_keyRepeat; ///< Is the KeyRepeat feature enabled?
|
||||||
bool m_keyRepeat; ///< Is the KeyRepeat feature enabled?
|
Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only)
|
||||||
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_useSizeHints; ///< Is the size of the window fixed with size hints?
|
||||||
bool m_useSizeHints; ///< Is the size of the window fixed with size hints?
|
bool m_fullscreen; ///< Is the window in fullscreen?
|
||||||
bool m_fullscreen; ///< Is the window in fullscreen?
|
bool m_cursorGrabbed; ///< Is the mouse cursor trapped?
|
||||||
bool m_cursorGrabbed; ///< Is the mouse cursor trapped?
|
bool m_windowMapped; ///< Has the window been mapped by the window manager?
|
||||||
bool m_windowMapped; ///< Has the window been mapped by the window manager?
|
Pixmap m_iconPixmap; ///< The current icon pixmap if in use
|
||||||
Pixmap m_iconPixmap; ///< The current icon pixmap if in use
|
Pixmap m_iconMaskPixmap; ///< The current icon mask pixmap if in use
|
||||||
Pixmap m_iconMaskPixmap; ///< The current icon mask pixmap if in use
|
::Time m_lastInputTime; ///< Last time we received user input
|
||||||
::Time m_lastInputTime; ///< Last time we received user input
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace priv
|
} // namespace priv
|
||||||
|
Loading…
Reference in New Issue
Block a user