Fixed Window::EnableKeyRepeat on Linux

git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/trunk@1039 4e206d99-4929-0410-ac5d-dfc041789085
This commit is contained in:
laurentgom 2009-03-04 18:42:11 +00:00
parent 870d049bc8
commit 2ec074b12a
2 changed files with 48 additions and 44 deletions

View File

@ -362,28 +362,51 @@ void WindowImplX11::Display()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplX11::ProcessEvents() void WindowImplX11::ProcessEvents()
{ {
// 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 EnableKeyRepeat is true
// - Discard both duplicated KeyPress and KeyRelease events when EnableKeyRepeat is false
// Process any event in the queue matching our window // Process any event in the queue matching our window
XEvent Event; XEvent Event;
while (XCheckIfEvent(ourDisplay, &Event, &WindowImplX11::CheckEvent, reinterpret_cast<XPointer>(myWindow))) while (XCheckWindowEvent(ourDisplay, myWindow, ourEventMask, &Event))
{ {
// Filter repeated key events // Detect repeated key events
if ((Event.type == KeyPress) || (Event.type == KeyRelease))
{
if (Event.xkey.keycode < 256)
{
// 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 EnableKeyRepeat state,
// and we need to properly forward the first one.
char Keys[32];
XQueryKeymap(ourDisplay, Keys);
if (Keys[Event.xkey.keycode >> 3] & (1 << (Event.xkey.keycode % 8)))
{
// KeyRelease event + key down = repeated event --> discard
if (Event.type == KeyRelease) if (Event.type == KeyRelease)
{ {
if (XPending(ourDisplay)) myLastKeyReleaseEvent = Event;
continue;
}
// KeyPress event + key repeat disabled + matching KeyRelease event = repeated event --> discard
if ((Event.type == KeyPress) && !myKeyRepeat &&
(myLastKeyReleaseEvent.xkey.keycode == Event.xkey.keycode) &&
(myLastKeyReleaseEvent.xkey.time == Event.xkey.time))
{ {
XEvent NextEvent;
XPeekEvent(ourDisplay, &NextEvent);
if ((NextEvent.type == KeyPress) &&
(NextEvent.xkey.keycode == Event.xkey.keycode) &&
(NextEvent.xkey.time == Event.xkey.time))
{
if (!myKeyRepeat)
XNextEvent(ourDisplay, &NextEvent);
continue; continue;
} }
} }
} }
}
// Process the event
ProcessEvent(Event); ProcessEvent(Event);
} }
} }
@ -709,6 +732,9 @@ bool WindowImplX11::CreateContext(const VideoMode& Mode, XVisualInfo& ChosenVisu
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplX11::Initialize() void WindowImplX11::Initialize()
{ {
// Make sure the "last key release" is initialized with invalid values
myLastKeyReleaseEvent.type = -1;
// Get the atom defining the close event // Get the atom defining the close event
myAtomClose = XInternAtom(ourDisplay, "WM_DELETE_WINDOW", false); myAtomClose = XInternAtom(ourDisplay, "WM_DELETE_WINDOW", false);
XSetWMProtocols(ourDisplay, myWindow, &myAtomClose, 1); XSetWMProtocols(ourDisplay, myWindow, &myAtomClose, 1);
@ -802,17 +828,6 @@ void WindowImplX11::CleanUp()
} }
////////////////////////////////////////////////////////////
/// Filter the received events
/// (only allow those matching a specific window)
////////////////////////////////////////////////////////////
Bool WindowImplX11::CheckEvent(::Display*, XEvent* Event, XPointer UserData)
{
// Just check if the event matches our window
return Event->xany.window == reinterpret_cast< ::Window >(UserData);
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Process an incoming event from the window /// Process an incoming event from the window
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -200,18 +200,6 @@ private :
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void CleanUp(); void CleanUp();
////////////////////////////////////////////////////////////
/// Filter the received events
/// (only allow those matching a specific window)
///
/// \param Event : Event to filter
/// \param UserData : Data passed to the function (here : the window to compare)
///
/// \return True if the event belongs to the specified window
///
////////////////////////////////////////////////////////////
static Bool CheckEvent(::Display*, XEvent* Event, XPointer UserData);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Process an incoming event from the window /// Process an incoming event from the window
/// ///
@ -267,6 +255,7 @@ private :
Cursor myHiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one Cursor myHiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one
XIC myInputContext; ///< Input context used to get unicode input in our window XIC myInputContext; ///< Input context used to get unicode input in our window
bool myKeyRepeat; ///< Is the KeyRepeat feature enabled ? bool myKeyRepeat; ///< Is the KeyRepeat feature enabled ?
XEvent myLastKeyReleaseEvent; ///< Last key release event we received (needed for discarding repeated key events)
}; };
} // namespace priv } // namespace priv