Posted 05 April 2011 - 01:51 AM
Linux input events basically go "KEYDOWN... {pause}, KEYREPEAT, KEYREPEAT, KEYREPEAT, KEYREPEAT, KEYREPEAT, KEYREPEAT, KEYREPEAT,KEYUP"
What you need to do is remember the state of the keys between events and query that state store instead of examining the events themselves.
If you set up a mapping between X keynames ( the ones in the events ) and your interpretation (up, down, left, right etc which you can enumerate as small integers), then you can have a small array to store the keystates.
The event interpretation then just puts a 1 or 0 in the appropriate array slot for up and down. Ignore the keyrepeats.
There are TWO important gotchas here. One is obvious and one isn't.
The first is that X11 doesn't actually conveniently send you a keyrepeat code for you to ignore. Why it doesn't I don't know but hacky bodging seems likely.
So what you get is a "keyup/keydown" pair of events.
Your options here are just use them as they are or to find the repeat and deliberately ignore it.
If you process ALL pending events between frames, chances are you'll always process both parts and your state array will still hold a "1" for key down, and then everything "just works"
If you timelimit or countlimit your event handling, you may not process both halves, so you need to check if an UP is really an up or part of a repeat. The way to test that (and hence whether to discard) is to take the event, and if it's a keyup peek at the next one. If that's a keydown for the same key AND has the same timestamp as your keyup then you've got a repeat and you can bin them both.
{Technically you're supposed to go on a crawl of the event stack because there technically might be an event in between, but a) that's a pain to do because it needs predicate routines and void casts and nasty stuff like that and b) it's usually never the case on local servers.}
Your second gotcha is the focus. If you lose keyboard focus, you will not get key up events. Hence -- press the button, hold it, click mouse outside the window, release key.... and you'll never see the up event because it went to another window and in this new world of processing state and not events, that's a perpetual turn.
There are two fixes -- the easy way and the technically correct way. The latter is to use a keyboard grab. I wouldn't bother if I were you. Do the easy thing; catch the "lost focus" event (which you WILL get as you click) and clear down your state array at that point ending the movement. It'll be good enough while you're developing and it's less likely to lead to tears than keyboard grabs.