Skip to content

3.3. Handling key input

N•I•L edited this page Jan 9, 2022 · 9 revisions

Main reference: touch pad example.

Key input handling is a must-know in DS programming. The Nintendo DS features 12 buttons (DPad Up/Down/Left/Right, A/B/X/Y, L/R, Start/Select), plus the the Power button and the TouchScreen (which is also handled through keys API).

libnds makes things incredibly simple:

while(1)
{
    scanKeys();
    int keys=keysDown();
    if(keys & KEYS_DOWN)
    {
        iprintf("Down key pressed\n");
    }
    swiWaitForVBlank();
}

scanKeys();

This gets the current keys state (for each key check either if it has been pressed or not at the current time). As libnds documentation recommends, we should "call this function once per main loop in order to use the keypad functions".

keysDown(), keysHeld()

The difference between these two is the moment of reference. keysDown() gets the keys newly pressed at the current moment, while keysHeld() gets all the heys held at the moment of calling, regardless of when they have been pressed.

Both functions return an uint32_t whose bits tell whether a key is pressed or not. Each key is assigned to a certain bit position in the key states uint, and we can get the state of a current key by asking if that bit if it's set or not. We can do that by masking the key states returned by keysDown/keysHeld/keysUp with the predefined key masks KEY_<key_name>, which is internally represented as (1<<key_id). If the result of key_states & KEY_<key_name> is not zero, then the key in discussion has been triggered at the last key states check.

Step Keys down Keys held Keys Up keysDown() & KEY_A keysHeld() & KEY_A keysUp() & KEY_A
1 Up 0 0 0
2 A Up KEY_A 0 0
3 Up A 0 KEY_A 0
4 A Up 0 KEY_A 0
5 A 0 KEY_A 0
6 A 0 0 KEY_A
7 0 0 0

Please also check this post in order not to repeat the same easy-to-do mistake. Don't expect a code block inside if(keysDown() & KEY_<key_name>) { ... } continuously run every frame you hold (not sistematically press and release) the <key_name>. Be aware of the situations when to use keysDown and keysHeld!

The following code is a demonstration of key handling process in libnds:

#include <nds.h>
#include <stdio.h>

inline void goto_xy(int x,int y) { iprintf("\033[%d;%dH", y, x); }

// prints a table row showing data for each key
inline void writeRow(char* key_name,char* state_down,char* state_held,char* state_up)
{
    iprintf("| %-9s| %-5s| %-5s| %-4s|",key_name,state_down,state_held,state_up);
}

const int KEYS_COUNT = 12; // Number of keys we want to check (w/o TOUCH, LID)

int main(void)
{
    int keyIds[KEYS_COUNT] = {KEY_A, KEY_B, KEY_SELECT, KEY_START, KEY_RIGHT, KEY_LEFT,
          KEY_UP, KEY_DOWN, KEY_R, KEY_L, KEY_X, KEY_Y};
    char keyNames[KEYS_COUNT][10] = {"A", "B", "Select", "Start", "Right", "Left",
          "Up", "Down", "R", "L", "X", "Y"};

    char key_triggered[2]="X";
    char key_not_trigg[2]="";

    consoleDemoInit();
    writeRow("Key name","Down","Held","Up");
    iprintf("|----------|------|------|-----|");
    while(1)
    {
        scanKeys(); // fetch key states
        int keys_down = keysDown(); 
        int keys_held = keysHeld();
        int keys_up = keysUp();
        goto_xy(0,2);
        for(int i=0;i<KEYS_COUNT;i++)
        {
            writeRow(keyNames[i],
                     (keys_down & keyIds[i]) ? key_triggered:key_not_trigg, // prints X if key i id down
                     (keys_held & keyIds[i]) ? key_triggered:key_not_trigg, // prints X if key i id held
                     (keys_up & keyIds[i]) ? key_triggered:key_not_trigg);  // prints X if key i id up
        }
        swiWaitForVBlank();
    }

   return 0;
}

This code illustrates the way keysDown, keysHeld and keysUp work.