Okay, I have come to a few results. First, I have realized how much I love Visual Studio, when I once have to work (and debug) with Code::Blocks. I'm really glad I don't have to develop with it...
This is the original code:
// Detect repeated key events
if ((windowEvent.type == KeyPress) || (windowEvent.type == KeyRelease))
{
if (windowEvent.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(m_display, keys);
if (keys[windowEvent.xkey.keycode / 8] & (1 << (windowEvent.xkey.keycode % 8)))
{
// KeyRelease event + key down = repeated event --> discard
if (windowEvent.type == KeyRelease)
{
m_lastKeyReleaseEvent = windowEvent;
return false;
}
// KeyPress event + key repeat disabled + matching KeyRelease event = repeated event --> discard
if ((windowEvent.type == KeyPress) && !m_keyRepeat &&
(m_lastKeyReleaseEvent.xkey.keycode == windowEvent.xkey.keycode) &&
(m_lastKeyReleaseEvent.xkey.time == windowEvent.xkey.time))
{
return false;
}
}
}
}
The debugger showed that duplicate events occur outside the 3rd if statement, that is when the key is not held down. Additionally, I think it would be correct to set
m_lastKeyReleaseEvent always to the last release event, not only if it is discarded, but I might be wrong here.
I have tried to adapt your code. According to your comment, the KeyPressed condition is independent of
heldDown (variable saying that the key is currently held down). In the KeyReleased condition, I discard the event if the key is down
or it's a duplicate (which may occur when the key is already up again). I also assign the last key event always. The body of the 2nd if statement then looks like this:
char keys[32];
XQueryKeymap(m_display, keys);
bool duplicate = (m_lastKeyReleaseEvent.xkey.keycode == windowEvent.xkey.keycode) &&
(m_lastKeyReleaseEvent.xkey.time == windowEvent.xkey.time);
bool heldDown = keys[windowEvent.xkey.keycode / 8] & (1 << (windowEvent.xkey.keycode % 8));
// KeyRelease event + key down = repeated event --> discard
if (windowEvent.type == KeyRelease)
{
m_lastKeyReleaseEvent = windowEvent;
if (heldDown || duplicate)
return false;
}
// KeyPress event + key repeat disabled + matching KeyRelease event = repeated event --> discard
if ((windowEvent.type == KeyPress) && !m_keyRepeat && duplicate)
{
return false;
}
It seems to work so far, but there is one situation where duplicates still occur: If the timestamp is minimally different. It happens sometimes that the time differs by 1 or 2 milliseconds. You could use an inequation for the
duplicate expression, just to make code even uglier
By the way, you should really split your
processEvent() function up
Also, the first two if statements in the original code can be merged using
operator&&.