| ホーム | チュートリアル | プログラム | ||
|---|---|---|---|---|
| 1-セットアップ | 4-サウンド | 7-FIFO | インベーダー | |
| 2-フレームバッファ | 5-SRAM | 8-割り込み | DSEmu | |
| 3-キー入力 | 6-ファイルシステム | 9-マイク | ||
| 10-拡張回転バックグラウンド | ||||
このチュートリアルシリーズのPart 2ではフレームバッファグラフィックスモードと垂直ブランク割り込みの使用に関して解説しました。
このPart 3ではユーザが任天堂DS上のキー(ボタン)を押したときのハンドリングに関して解説します。
任天堂DSには、装置の上のキーが押されている時にオフとなるビットを含むハードウェアレジスタがあります。 このレジスタは 'ndslib' では KEYS と名付けられており、メモリアドレス 0x4000130 に位置していて書き込み禁止です。そして、関連キーが押されると、以下のビットはオフ('0'のセット)にされます。
| KEYS ビット | キー | 'ndslib' での定義 | 押された時 | 話された時 |
|---|---|---|---|---|
| 0 | Aボタン | KEY_A | Cleared | Set |
| 1 | Bボタン | KEY_B | Cleared | Set |
| 2 | Selectボタン | KEY_SELECT | Cleared | Set |
| 3 | Startボタン | KEY_START | Cleared | Set |
| 4 | 十字ボタン 右 | KEY_RIGHT | Cleared | Set |
| 5 | 十字ボタン 左 | KEY_LEFT | Cleared | Set |
| 6 | 十字ボタン 上 | KEY_UP | Cleared | Set |
| 7 | 十字ボタン 下 | KEY_DOWN | Cleared | Set |
| 8 | Rボタン | KEY_R | Cleared | Set |
| 9 | Lボタン | KEY_L | Cleared | Set |
上記レジスタには2つのキーが抜けているのに気付くでしょう。それはゲームボーイアドバンスにはなくて、任天堂DSで新しく追加された 'X' と 'Y' キーです。
これらの2つのキーはメモリアドレス 0x04000136 に位置する別のレジスタ XKEYS から読み出すことができます。残念ながらこのレジスタは ARM7 からしかアクセスできません。それに対して KEYS レジスタは、ARM7 および ARM9 からアクセスできます。
ARM9 からこのレジスタを読み出すために、'ndslib' に含まれるデフォルトの ARM7 テンプレートコードでは垂直ブランク割り込み中に読み込んで、IPC->buttons に値を設定します。IPC とは構造体で ARM7 によって読み込まれた有用なデータを含んでおり、ARM9 からアクセス可能です。ARM7 テンプレートコードの関連セクションを記載します。
void InterruptHandler(void) {
[...]
but = XKEYS;
[...]
IPC->heartbeat = heartbeat;
IPC->buttons = but;
IPC->touchX = x;
[...]
}
XボタンまたはYボタンが押された時、XKEYS レジスタの該当ビットがオフにされます。また、タッチスクリーンでのペンの押下およびスクリーンが閉じられたことを示すビットを含んでいます。
| XKEYS ビット | キー | 'ndslib' での定義 | 押された時 | 離された時 |
|---|---|---|---|---|
| 0 | Xボタン | (1 << 0) | Cleared | Set |
| 1 | Yボタン | (1 << 1) | Cleared | Set |
| 2 | ペンダウン | (1 << 6) | Cleared | Set |
| 3 | スクリーン閉鎖 | (1 << 7) | Set | Cleared |
注)'スクリーン閉鎖'は他のビットと意味が異なります。スクリーンが閉じられたときにビットがオンになり、スクリーンが開けられるとビットがオフになります。
'ndslib' ライブラリには便利なマクロ READ_KEYS があり、それは KEYS の未使用のビットをマスクし、それの補数を得ます。これで、キーが押されているかどうかは '&' オペレーション間単に取得できます。READ_KEYS マクロを使用したコーディングの例です。
if(READ_KEYS & KEY_UP)
--shape_y;
Instead of the less intuitive:
if(!(KEYS & KEY_UP))
--shape_y;
7ndslib'には READ_KEYS と同等の XKEYS レジスタに対するマクロが見つかりませんでした。したがって、IPC->buttons から直接値を取得しなければなりません。
uint16 specialKeysPressed = ~IPC->buttons;
// Y Key
if(specialKeysPressed & (1 << 1))
shape_color = RGB15(7, 7, 7);
// X Key
if(specialKeysPressed & (1 << 0))
shape_color = RGB15(0, 15, 15);
// Pen Down
if(specialKeysPressed & (1 << 6))
shape_color = RGB15(0, 31, 31);
// Hinge closed
if(!(specialKeysPressed & (1 << 7)))
shape_color = RGB15(0, 0, 0);
注)スクリーンが閉じているかのビットの判定は他のビットと異なり '!' (not)が必要です。
キーも使用のデモとして、チュートリアル2の図形のサンプルをちょっと変更してみます。
図形を自動的に移動させる代わりに、十字ボタンを使用して図形を移動させます 他のボタンは図形の色を変更します。スクリーンを閉じるとそれは見えなくなります。(色を黒にします。というか、閉じたら見えないと思うのですが・・・)スクリーンをオープンにして、別のボタンを押すと、再度図形が表示されます。
色を変更するために、現在の色を保持するグローバル変数を使用します。
static uint16 shape_color = RGB15(31, 0, 0);
そしてこの変数を使用するために描画コードを変更します。
void on_irq()
{
if(IF & IRQ_VBLANK) {
draw_shape(old_x, old_y, VRAM_A, RGB15(0, 0, 0));
draw_shape(shape_x, shape_y, VRAM_A, shape_color);
// VBLANK割り込みをハンドルしたことをDSに伝達
VBLANK_INTR_WAIT_FLAGS |= IRQ_VBLANK;
IF |= IRQ_VBLANK;
}
else {
// 他の割り込みを無視
IF = IF;
}
}
図形は十字ボタンで移動します。READ_KEYS マクロを使用して、関連したキーのテストを行います。テストは斜めに移動するのを許すために、キーの組み合わせを判定するように、分離した 'if' を使用します。
uint16 keysPressed = READ_KEYS;
// 押されたボタンに基づいて、図形を移動
if(keysPressed & KEY_UP)
--shape_y;
if(keysPressed & KEY_DOWN)
++shape_y;
if(keysPressed & KEY_LEFT)
--shape_x;
if(keysPressed & KEY_RIGHT)
++shape_x;
色を変更するボタンをテストするために IPC->buttons (XKEYSを保持) の値を使用します。しかし、まず直感的なテストができるようにそれの補数を計算します。
uint16 specialKeysPressed = ~IPC->buttons;
// 関連キーが押されたら、図形の色を変更
if(keysPressed & KEY_A)
shape_color = RGB15(31, 0, 0);
if(keysPressed & KEY_B)
shape_color = RGB15(0, 31, 0);
if(keysPressed & KEY_SELECT)
shape_color = RGB15(0, 0, 31);
if(keysPressed & KEY_START)
shape_color = RGB15(31, 31, 31);
if(keysPressed & KEY_R)
shape_color = RGB15(15, 0, 15);
if(keysPressed & KEY_L)
shape_color = RGB15(7, 15, 7);
// Y Key
if(specialKeysPressed & (1 << 1))
shape_color = RGB15(7, 7, 7);
// X Key
if(specialKeysPressed & (1 << 0))
shape_color = RGB15(0, 15, 15);
// Pen Down
if(specialKeysPressed & (1 << 6))
shape_color = RGB15(0, 31, 31);
// Hinge closed
if(!(specialKeysPressed & (1 << 7)))
shape_color = RGB15(0, 0, 0);
アプリケーションをビルドする手順はチュートリアル2に概説しています。私はデフォルトのarm7_main.cppとARM9コード arm9_main.cppを使用しています。コンパイルコマンドを実行するための簡単な Makefile ファイルを提供します。
完全なソースコードは keys_demo1.zip ファイルで、エミュレータまたは実機で実行できる keys_demo1.nds と keys_demo1.nds.gba ファイルをダウンロードできます。
このチュートリアルでは、どのようにDS上の異なったキー(ボタン)の押下を検出するかを示しました。もちろん使用した手法が唯一の方法ではありません。
この手法では私達が特定の時点で、キー関連レジスタの値を確認する'ポーリング'方式です。これを垂直ブランク割り込み期間内に実行しました。ユーザが非常に速くキーを押して、離す事ができますので、両方ののイベントがポーリングチェックの前または後に起こる可能性があります。今回のプログラムではボタンの押下を通知を見過ごす可能性があります。
これが1秒間に60フレームの割り込み以上に起きている場合は、'割り込み'を使用することによって、それを回避することができます。垂直ブランク割り込みと同様にキーイベントに対する割り込みがあります。私達はキーが押された時にすぐに呼び出される割り込み機能を持つことができます。割り込みチュートリアルは、どのようにこれを処理するかを示してます。また割り込み方式でのいくつかの損失についても概説しています。チュートリアル6では実際のアプリケーションで有効なキーハンドリングの別の手法を提示しています。
いろいろなコメントや提案は歓迎します。 以下の私の連絡先を見てください。
Copyright (c) 2005, Chris Double. All Rights Reserved.