Fixed KeyRelease events sometimes not reported on Linux (#404)
This commit is contained in:
parent
6ec100aeb7
commit
73ec7ab483
@ -356,8 +356,8 @@ void WindowImplX11::setTitle(const String& title)
|
||||
// There is however an option to tell the window manager your unicode title via hints.
|
||||
|
||||
// Convert to UTF-8 encoding.
|
||||
std::basic_string<sf::Uint8> utf8Title;
|
||||
sf::Utf32::toUtf8(title.begin(), title.end(), std::back_inserter(utf8Title));
|
||||
std::basic_string<Uint8> utf8Title;
|
||||
Utf32::toUtf8(title.begin(), title.end(), std::back_inserter(utf8Title));
|
||||
|
||||
// Set the _NET_WM_NAME atom, which specifies a UTF-8 encoded window title.
|
||||
Atom wmName = XInternAtom(m_display, "_NET_WM_NAME", False);
|
||||
@ -513,11 +513,6 @@ void WindowImplX11::switchToFullscreen(const VideoMode& mode)
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplX11::initialize()
|
||||
{
|
||||
// Make sure the "last key release" is initialized with invalid values
|
||||
m_lastKeyReleaseEvent.type = -1;
|
||||
m_lastKeyReleaseEvent.xkey.keycode = 0;
|
||||
m_lastKeyReleaseEvent.xkey.time = 0;
|
||||
|
||||
// Get the atom defining the close event
|
||||
m_atomClose = XInternAtom(m_display, "WM_DELETE_WINDOW", false);
|
||||
XSetWMProtocols(m_display, m_window, &m_atomClose, 1);
|
||||
@ -613,33 +608,30 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
|
||||
// - Discard both duplicated KeyPress and KeyRelease events when KeyRepeatEnabled is false
|
||||
|
||||
// Detect repeated key events
|
||||
if (((windowEvent.type == KeyPress) || (windowEvent.type == KeyRelease)) && (windowEvent.xkey.keycode < 256))
|
||||
// (code shamelessly taken from SDL)
|
||||
if (windowEvent.type == KeyRelease)
|
||||
{
|
||||
// To detect if it is a repeated key event, we check the current state of the key:
|
||||
// - If the state is "down", KeyReleased events must obviously be discarded
|
||||
// - KeyPress events are a little bit harder to handle: they depend on the KeyRepeatEnabled state,
|
||||
// and we need to properly forward the first one
|
||||
|
||||
// Check if the key is currently down
|
||||
char keys[32];
|
||||
XQueryKeymap(m_display, keys);
|
||||
bool isDown = keys[windowEvent.xkey.keycode / 8] & (1 << (windowEvent.xkey.keycode % 8));
|
||||
// Check if there's a matching KeyPress event in the queue
|
||||
XEvent nextEvent;
|
||||
if (XPending(m_display))
|
||||
{
|
||||
// Grab it but don't remove it from the queue, it still needs to be processed :)
|
||||
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);
|
||||
|
||||
// Check if it's a duplicate event
|
||||
bool isDuplicate = (windowEvent.xkey.keycode == m_lastKeyReleaseEvent.xkey.keycode) &&
|
||||
(windowEvent.xkey.time - m_lastKeyReleaseEvent.xkey.time <= 5);
|
||||
|
||||
// Keep track of the last KeyRelease event
|
||||
if (windowEvent.type == KeyRelease)
|
||||
m_lastKeyReleaseEvent = windowEvent;
|
||||
|
||||
// KeyRelease event + key down or duplicate event = repeated event --> discard
|
||||
if ((windowEvent.type == KeyRelease) && (isDown || isDuplicate))
|
||||
return false;
|
||||
|
||||
// KeyPress event + matching KeyRelease event = repeated event --> discard if key repeat is disabled
|
||||
if ((windowEvent.type == KeyPress) && isDuplicate && !m_keyRepeat)
|
||||
return false;
|
||||
// This KeyRelease is a repeated event and we don't want it
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the X11 event to a sf::Event
|
||||
|
@ -212,18 +212,17 @@ private :
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
::Window m_window; ///< X11 structure defining our window
|
||||
::Display* m_display; ///< Pointer to the display
|
||||
int m_screen; ///< Screen identifier
|
||||
XIM m_inputMethod; ///< Input method linked to the X display
|
||||
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
|
||||
Atom m_atomClose; ///< Atom used to identify the close event
|
||||
int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen
|
||||
Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one
|
||||
bool m_keyRepeat; ///< Is the KeyRepeat feature enabled ?
|
||||
XEvent m_lastKeyReleaseEvent; ///< Last key release event we received (needed for discarding repeated key events)
|
||||
Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only)
|
||||
::Window m_window; ///< X11 structure defining our window
|
||||
::Display* m_display; ///< Pointer to the display
|
||||
int m_screen; ///< Screen identifier
|
||||
XIM m_inputMethod; ///< Input method linked to the X display
|
||||
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
|
||||
Atom m_atomClose; ///< Atom used to identify the close event
|
||||
int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen
|
||||
Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one
|
||||
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)
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
Loading…
Reference in New Issue
Block a user