nintendo-dslibnds

Why doesn't keysDownRepeat() in libnds seem to work when calling it multiple times?


I have code like this to move the player in my game left, right, up, and down:

keysSetRepeat(20, 5);

while (lives) {
    scanKeys();

    if (keysDownRepeat() & (KEY_LEFT | KEY_RIGHT | KEY_UP | KEY_DOWN)) {
        u8 new_x = x;
        u8 new_y = y;

        if (keysDownRepeat() & KEY_LEFT) {
            new_x--;
        } else if (keysDownRepeat() & KEY_RIGHT) {
            new_x++;
        } else if (keysDownRepeat() & KEY_DOWN) {
            new_y++;
        } else if (keysDownRepeat() & KEY_UP) {
            new_y--;
        }

        // ...
    }

    // ...

    swiWaitForVBlank();
}

Why are the keys not being detected? If I replace keysDownRepeat() with keysDown() it works (without the repeat rate, of course). The documentation is no help here.


Solution

  • I had to find the libnds source code to figure this out. Look at the implementation of keysDownRepeat():

    uint32 keysDownRepeat(void) {
        uint32 tmp = keysrepeat;
    
        keysrepeat = 0;
    
        return tmp;
    }
    

    It actually returns the keys then resets them back to 0. This wasn't documented. I solved this by storing the result of keysDownRepeat() into a variable and using the variable to check the keys:

    keysSetRepeat(20, 5);
    
    while (lives) {
        scanKeys();
        u32 keys_down_repeat = keysDownRepeat();
    
        if (keys_down_repeat & (KEY_LEFT | KEY_RIGHT | KEY_UP | KEY_DOWN)) {
            u8 new_x = x;
            u8 new_y = y;
    
            if (keys_down_repeat & KEY_LEFT) {
                new_x--;
            } else if (keys_down_repeat & KEY_RIGHT) {
                new_x++;
            } else if (keys_down_repeat & KEY_DOWN) {
                new_y++;
            } else if (keys_down_repeat & KEY_UP) {
                new_y--;
            }
    
            // ...
        }
    
        // ...
    
        swiWaitForVBlank();
    }