押したキーを表示する - キー読み取り版

押したキーを読み取り、画面に表示します。

2022-06-12
公開

コード

main.c

  1. #include <genesis.h>
  2.  
  3. #define BUTTON_REPEAT_TRIGGER_COUNT 30
  4. #define BUTTON_REPEAT_INTERVAL 5
  5. #define DEFAULT_POSITION_X 12;
  6. #define DEFAULT_POSITION_Y 13;
  7.  
  8. // テキスト表示位置
  9. static u16 posX = DEFAULT_POSITION_X; // 表示文字のX座標
  10. static u16 posY = DEFAULT_POSITION_Y; // 表示文字のY座標
  11.  
  12. /**
  13. * 渡された1文字を状態に対応するパレットで画面に表示する
  14. * @param c 表示する文字
  15. * @param state 状態
  16. */
  17. static void drawChar(char c, u16 state) {
  18. // 表示するボタンの頭文字の設定(0は終端文字)
  19. char chr[2];
  20. chr[0] = c;
  21. chr[1] = 0;
  22.  
  23. // テキストのパレットを、ボタンの押下があれば0、なければ1に設定
  24. VDP_setTextPalette(state ? PAL0 : PAL1);
  25. // 対応するボタンの頭文字を表示
  26. VDP_drawText(chr, posX, posY);
  27.  
  28. // 表示の横位置をずらす
  29. posX += 2;
  30. }
  31.  
  32. /**
  33. * 1Pコントローラの変化したボタンに対応した画面上の文字の色を変更する
  34. * @param state ボタン
  35. */
  36. static void drawButtonChar(u16 state) {
  37. drawChar('U', state & BUTTON_UP);
  38. drawChar('D', state & BUTTON_DOWN);
  39. drawChar('L', state & BUTTON_LEFT);
  40. drawChar('R', state & BUTTON_RIGHT);
  41. drawChar('A', state & BUTTON_A);
  42. drawChar('B', state & BUTTON_B);
  43. drawChar('C', state & BUTTON_C);
  44. drawChar('X', state & BUTTON_X);
  45. drawChar('Y', state & BUTTON_Y);
  46. drawChar('Z', state & BUTTON_Z);
  47. drawChar('S', state & BUTTON_START);
  48. }
  49.  
  50. /**
  51. * コントローラの状態
  52. */
  53. typedef struct {
  54. u16 current; // 押下しているキー
  55. u16 trigger; // 押し始めたキー
  56. u16 off; // 離したキー
  57. u16 repeat; // 押し続けているキー
  58. u16 repeatCount; // リピートカウント
  59. } JoyState;
  60.  
  61. /**
  62. * コントローラの状態を保持するグローバル変数
  63. */
  64. JoyState joyState;
  65.  
  66. /**
  67. * VBlankごとに1回だけボタンの情報を取得する
  68. */
  69. static void joyExec() {
  70. u16 state = JOY_readJoypad(JOY_1);
  71.  
  72. joyState.trigger = state & ~joyState.current;
  73. joyState.off = joyState.current & ~state;
  74. joyState.current = state;
  75.  
  76. // 「押し続けているキー」の設定
  77. // NOTE: 「押し続けているキー」は、押し始めたあと指定の時間無効化され、
  78. // それ以降押下している間は一定の間隔でオンオフを繰り返す
  79. if (joyState.trigger) {
  80. joyState.repeat = joyState.current;
  81. joyState.repeatCount = BUTTON_REPEAT_TRIGGER_COUNT;
  82. }
  83. else if (!joyState.repeatCount) {
  84. joyState.repeat = joyState.current;
  85. joyState.repeatCount = BUTTON_REPEAT_INTERVAL;
  86. }
  87. else {
  88. joyState.repeat = 0;
  89. }
  90. // カウント
  91. if (joyState.current) {
  92. if (joyState.repeatCount > 0) {
  93. joyState.repeatCount--;
  94. }
  95. }
  96. }
  97.  
  98. int main(u16 hard) {
  99. // ボタンを押していない時のテキスト色をパレット1に設定する
  100. // NOTE: SGDKではテキスト色はパレット0~3の15番を使用する
  101. // 1パレットは16個単位だが、色を表す値は区切りなく連続して存在している
  102. // つまり16+15はパレット1の15番目の色ということ
  103. PAL_setColor(16+15, 0x0666);
  104.  
  105. // 初期テキスト
  106. VDP_drawText("1P Pad:", posX-6, posY-1);
  107. VDP_drawText("trig:", posX-6, posY);
  108. VDP_drawText("off :", posX-6, posY+1);
  109. VDP_drawText("curt:", posX-6, posY+2);
  110. VDP_drawText("rpt :", posX-6, posY+3);
  111.  
  112. // パレットを1に設定(文字色変更)
  113. VDP_setTextPalette(PAL1);
  114. // 初期テキスト2
  115. VDP_drawText("U D L R A B C X Y Z S", posX, posY);
  116. VDP_drawText("U D L R A B C X Y Z S", posX, posY+1);
  117. VDP_drawText("U D L R A B C X Y Z S", posX, posY+2);
  118. VDP_drawText("U D L R A B C X Y Z S", posX, posY+3);
  119.  
  120. // コントローラ状態を初期化(0埋め)
  121. memset(&joyState, 0, sizeof(JoyState));
  122.  
  123. // メインループ
  124. while (TRUE) {
  125. SYS_doVBlankProcess();
  126.  
  127. // ボタン状態取得
  128. joyExec();
  129.  
  130. // テキスト表示位置の初期化
  131. posX = DEFAULT_POSITION_X;
  132. posY = DEFAULT_POSITION_Y;
  133.  
  134. // 押し始めたボタン
  135. drawButtonChar(joyState.trigger);
  136.  
  137. // テキスト表示位置をずらす
  138. posX = DEFAULT_POSITION_X;
  139. posY++;
  140.  
  141. // 離したボタン
  142. drawButtonChar(joyState.off);
  143.  
  144. // テキスト表示位置をずらす
  145. posX = DEFAULT_POSITION_X;
  146. posY++;
  147.  
  148. // 押しているボタン
  149. drawButtonChar(joyState.current);
  150.  
  151. // テキスト表示位置をずらす
  152. posX = DEFAULT_POSITION_X;
  153. posY++;
  154.  
  155. // 押し続けているボタン
  156. drawButtonChar(joyState.repeat);
  157. }
  158.  
  159. return 0;
  160. }

実行結果

上記コードをSGDK1.70でコンパイルし
Gens v2.14 Souvenirで実行したスクリーンショット

解説

ボタンの状態変化を受けて処理を実行するJOY_setEventHandlerと異なり、メインループで毎回(つまりVBlankごとに)ボタンの状態を読み取ります。
ボタンの状態による変化を細かく起こしたい場合は、こちらの方が向いているかもしれません。

処理を実行する場所で毎回ボタンの状態を読み取るのではなく、読み取り自体はVBlank中に1度だけにすることで、チャタリングの防止になるそうです(参考リンク先の情報による)。

ダウンロード