devkitPro の libgba キー入力ライブラリの備忘とか
libgba のキー入力ライブラリは scanKeys 関数でキーデータ更新後、
keysUp、keysDown、keysDownRepeat 関数で入力情報を 1 度取得すると、
2 回目以降値を返してくれなくなる。
libnds 使って DS 開発してた頃も確かそういう動きだったなーと思い
ソースコード見てみたら案の定だった。
関数内で値を返しつつ 0 でクリアしていやがる。
但し、keysHeld だけは何故か値クリアされていない。
for (;;) { VBlankIntrWait(); scanKeys(); if (keysDown() & KEY_A) { iprintf("INPUT A"); } if (keysDown() & KEY_B) { iprintf("INPUT B"); } }
この場合 A ボタンの入力には反応するが
B ボタンの入力には反応しない。
なので、押したときや離したときを複数回評価したいなら
一度変数に入れてから作業することになる。
for (;;) { VBlankIntrWait(); scanKeys(); off = keysUp(); trg = keysDown(); rep = keysDownRepeat(); if (trg & KEY_A) { iprintf("INPUT A"); } if (trg & KEY_B) { iprintf("INPUT B"); } }
なお、keysUp、keysDown、keysDownRepeat の戻り値はそれぞれ別なので、
3 つの変数を用意して scanKeys で更新の度に取得しておくと
必要なとき最新のデータが手に入って何かと便利。
という事で、とりあえずライブラリ化してみたものが以下。
id:akkera102さんの key.h, key.c をリスペクト(汗)。
中身は libgba と C 標準ライブラリで実装。
…実を言うとakkeraさんのサンプルプログラムから
こそーり借用しようかと思ったけど
如何せん key.h, key.c 以外のインクルードは増やしたくなかったので
結局お借りしないでポーティングという手段を取った。
key.h
#ifndef KEY_H #define KEY_H #ifdef __cplusplus extern "C" { #endif //共通ヘッダを記述 #include <gba_types.h> #include <gba_input.h> //--------------------------------------------------------------------------- //定数を記述 #define KEY_REPEAT_CNT 30 #define KEY_REPEAT_DLY 60 //--------------------------------------------------------------------------- //構造体を記述 typedef struct { u32 cnt; // 現在のキー u32 trg; // 押されたキー u32 off; // 離されたキー u32 rep; // リピートキー } ST_KEY; //--------------------------------------------------------------------------- //プロトタイプ宣言を記述 void KeyInit(void); void KeyExec(void); u32 KeyGetCnt(void); u32 KeyGetTrg(void); u32 KeyGetOff(void); u32 KeyGetRep(void); #ifdef __cplusplus } #endif #endif
key.c
//ヘッダを記述 #include "key.h" #include <string.h> //--------------------------------------------------------------------------- //構造体変数宣言を記述 ST_KEY Key; //--------------------------------------------------------------------------- void KeyInit(void) { //初期化処理を記述 memset(&Key, 0x00, sizeof(ST_KEY)); setRepeat(KEY_REPEAT_DLY, KEY_REPEAT_CNT); } //--------------------------------------------------------------------------- // vblank中に1回だけ呼び出します(チャタリング防止) void KeyExec(void) { //主処理を記述 scanKeys(); Key.cnt = keysHeld(); Key.trg = keysDown(); Key.off = keysUp(); Key.rep = keysDownRepeat(); } //--------------------------------------------------------------------------- // 現在押されているボタン u32 KeyGetCnt(void) { return Key.cnt; } //--------------------------------------------------------------------------- // 押された時のボタン u32 KeyGetTrg(void) { return Key.trg; } //--------------------------------------------------------------------------- // 離された時のボタン u32 KeyGetOff(void) { return Key.off; } //--------------------------------------------------------------------------- // キーリピートのボタン u32 KeyGetRep(void) { return Key.rep; }