views:

449

answers:

2

Hello,
I am programming a game in "OpenGL" and using "Gtkmm" as a window manager. I want to use the keyboard to camera moving (thus, "UP-key" to move forward, "DOWN-key" to move backward, etc...)

Some time ago, when I programmed in Java, I used this technique to "move":
When the application received for example the "UP-key-press" signal, it subsequently set the flag "shouldMoveForward" to "true" and when it later received the "UP-key-release" signal, it set the flag back to "false".
And the "game loop" continuously checked for that flag, and if it was true, it moves the camera forward, otherwise it did nothing.

So that I would like to use the same technique in "Gtkmm". So I just overrided these functions of my "Gtk::DrawingArea":

bool Gtk::Widget::on_key_press_event(GdkEventKey* event)
bool Gtk::Widget::on_key_release_event(GdkEventKey* event)

But the problem is in this: when I for example press the "UP" key and hold it for 5 seconds, then this sequence of signals is emitted:

press  ...<little time waiting>...  release  press  release  press  release  press  release   ..........   press  release  press  release

The previous situation appears when I am running my game "on Linux".

When I am "on Windows", it is as I want it to be, thus:

press  ...<little time waiting>...  press  press  press  press  press  ..........  press  press  release

So this seems to be a "non-portable" solution for camera moving in Gtkmm.

So is there any other ("PORTABLE") solution to achieve camera moving using Gtkmm as a window manager?

+1  A: 

This thread describes the problem (which is not in GTK+ itself), and a few workarounds.

unwind
A: 

I just encountered the auto repeat "feature" in my java game, and I got it fixed.

Since you know java you shouldn't have trouble porting the following code:

// Keyboard
private final List<Integer> keysPressed = new LinkedList<Integer>();
private final List<Integer> keysDown = new LinkedList<Integer>();
private final List<Integer> keysRemove = new LinkedList<Integer>();

public final void keyPressed(final KeyEvent e) {
    int key = e.getKeyCode();

    // Fix AutoKeyRepeat under X11
    if (keysRemove.contains(key)) {
        keysRemove.remove(Integer.valueOf(key));
    }

    if (!keysDown.contains(key)) {
        keysDown.add(key);
        keysPressed.add(key);
    }
    e.consume();
}

public final void keyReleased(final KeyEvent e) {
    int key = e.getKeyCode();
    keysRemove.add(key);
    e.consume();
}

public final void clearKeys() {
    for (Integer key : keysRemove) {
        keysDown.remove(Integer.valueOf(key));
        if (keysPressed.contains(key)) {
            keysPressed.remove(Integer.valueOf(key));
        }
    }
    keysRemove.clear();
    keysPressed.clear();
}

The method clearKeys gets called in the main loop just after the game state has been updated(checked for keyboard input / moved objects) the trick here is the first if in keyPressed. The auto generated key events occur at the exact same time, so it's nearly impossible that something happens between the fake keyReleased and keyPressed events. The only way a key can be in the keyRemove list when a keyPressed event occurs is that it's a fake event, so in that case we just remove the key from the keyRemove list.

When you release the key normally it's not followed by an immediate keyPressed event, so it's not removed from the list and processed by clearKeys.

For the rest of the code(like checking if a key is down or has been pressed) check out the source: http://github.com/BonsaiDen/Bonsai-Game-Library/blob/master/src/org/bonsai/dev/GameInput.java

Ivo Wetzel