PDA

View Full Version : Keyboard auto repeat



akiross
4th March 2007, 13:05
hi there,
i need to disable autorepeat of keyboard events. This means that a single KeyPress event is generated for each key pressed, and a KeyRelease is shot only when a key is released on the keyboard.

I didn't find anything userful about key autorepeat on the documentation, but some info about QKeyEvent::isAutoRepeat() but, like documentation say:

Note that if the event is a multiple-key compressed event that is partly due to auto-repeat, this function could return either true or false indeterminately.

sometimes it can't be reliable to use this funcion (and for my needs, it's quite bad)

Any help is really appreciated.

Thanks

fullmetalcoder
4th March 2007, 13:41
I didn't find anything userful about key autorepeat on the documentation, but some info about QKeyEvent::isAutoRepeat() but, like documentation say:


Note that if the event is a multiple-key compressed event that is partly due to auto-repeat, this function could return either true or false indeterminately.

sometimes it can't be reliable to use this function (and for my needs, it's quite bad)

Noticed the "compressed event"??? It means that the unreliability occurs only when two conditions several key press are compressed into a single key event and in this case text() return a multi-character string. This can only happen on input widgets whose attribute Qt::WA_KeyCompression (http://doc.trolltech.com/4.1/qt.html#WidgetAttribute-enum) is set to true. Hopefully this attribute is off by default and is set to on only in text editing widgets (QTextEdit and QLineEdit for instance) If you use such widgets and can't afford this (highly improbable) lack of reliability the simplest solution is to disable key compression for them. It may make them a little slower but in most case will be unnoticeable and will let you do proper checks on key events...

Hope this helps. :)

wysota
4th March 2007, 14:30
If all elses fail you can always set a flag on first press event and check the flag in each subsequent key press event. If it is set, simply don't handle the event. And of course you'll need to clear the flag in release event. Note that the flag can be a QSet and not boolean if you need to handle more than one key at a time.

akiross
4th March 2007, 14:35
Yep! It helps :) Thanks i didn't notice it.

Ok, at least now i can use that function to check... But i still prefer to choose if enabling key repeat (well, i'm doing a game, and i come with the libSDL experience, where by default key repeat is off but you can enable and modify it as your wish). To me, disabling it at all will result in a more straightforward code...

... But for now this is ok :D

So, well, this is just mine sudgestion for qt developers: a function like QWidget::enableKeyRepeat(bool) would be even better ;)

Fullmetalcoder, thanks a lot!

EDIT: Also thanks to wysota, the idea of using a set for multiple keypress is really nice! I used (but in C, without sets) to do something like char pressed[256]; :D
But sets are far better for this.
Thanks again!

wysota
4th March 2007, 15:00
If you're making a game, then you have a very simple solution... As you probably want your game to be stable independent of the computer it is running on, you should use a QTimer object (or a timer event) to synchronise your game loop. And if you do, you can simply check the key state there instead of relying on key press/release events. QSet might be helpfull here as well.


QSet<Qt::Key> keysPressed;
void W::keyPressEvent(QKeyEvent *ev){
keysPressed += (Qt::Key)ev->key();
}
void W::keyReleaseEvent(QKeyEvent *ev){
keysPressed -= (Qt::Key)ev->key();
}

void W::timerEvent(QTimerEvent *ev){
foreach(Qt::Key k, keysPressed){
//...
}
}

akiross
4th March 2007, 15:14
Mmh well actually i won't need the set in this particular game, i just liked the idea :)

For this one i'll rely on events to handle user inputs. Main loop will be used only for drawing purpose. Actually, Qt is class based, so events are outside the main loop.
In SDL context, events were put in an event queue and polled at every refresh, so a set would be wonderful there.

But here i'm using a timer for refresh, events aren't syncronized with this timer because i'm keeping objects interact asyncronously: a physic engine will have its loop for integrate the simulation, GLwidget loop will have its loop for refreshing the screen, but the game under the hood isn't synced.

Well, i'm just trying this approach, since it's the first time i do a game with Qt (and C++)... If i'll found that doesn't work good, i'll use the classic method :)

Thanks anyway

fullmetalcoder
4th March 2007, 15:44
Actually, Qt is class based, so events are outside the main loop.
In Qt input events are fed by the system (X11, Window$, ...) to the event loop of the GUI thread (== main loop) which dispatch them to proper receivers.

akiross
4th March 2007, 16:05
yes yes, i know :)

I intended to say that usually you do it by hand (in SDL it's like)


while (1) { // main loop
while (SDL_PollEvent(&ev)) {
switch (ev.type) {
// Handle here events
}
// Here game drawing loop
}


While in qt the event polling is done by Qt; I'm saying that in Qt events are handled outside main loop because a Press method will be called on Press event.

To me, this is not only more readable and clear to write in code, but leaves also implementation freedom. If Qt a day will prefer to map directly system's event to my application, in this way there is no need to pass by an event queue, with SDL method it doesn't.

(well, it's quite ugly as example but i hope you got :D)