VirtualBoxのUbuntuのC言語でゲームパッド

VirtualBoxUbuntuC/C++で、USB接続のゲームパッド/ジョイスティックを扱いたい。

まずWindowsで動作確認

「コントロールパネル」→「デバイスとプリンター」でゲームパッドを選択し、右クリックで「ゲームコントローラの設定」→「プロパティ」の「テスト」タブで動作を確認する。


VirtualBoxゲームパッドをゲストOSに接続

仮想マシンの「デバイス」→「USB」から、ゲームパッドをゲストOSに接続する。

Ubuntuで動作確認

USBデバイスとして認識されていることを確認する。
以下の例では、ゲームパッド「JC-U3912T」が認識されていることが分かる。

$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 007: ID 056e:200e Elecom Co., Ltd JC-U3912T
Bus 002 Device 002: ID 80ee:0021 VirtualBox USB Tablet
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

jstest-gtkをインストール。

$ sudo apt-get install jstest-gtk

jstest-gtkを実行する。

$ jstest-gtk

この例では、/dev/input/js2 が所望のゲームパッド「JC-U3912T」であることが分かる。
ゲームパッドを選択して「Properties」を開くと、ゲームパッドの動作確認ができる。


C/C++ゲームパッドを扱う

#include <vector>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/joystick.h>

using namespace std;

// ゲームパッドのデバイスを指定
#define JOY_DEV "/dev/input/js2"

int main()
{
  int joy_fd = -1;          // ゲームパッドのファイル指定子
  int num_of_axis    = 0;   // 軸の数
  int num_of_buttons = 0;   // ボタンの数
  char name_of_joystick[80];// ゲームパッドの名前
  vector<int>  joy_axis;    // 各軸の値
  vector<char> joy_button;  // 各ボタンの値

  // ゲームパッドを開く
  if((joy_fd=open(JOY_DEV, O_RDONLY)) < 0) {
    printf("Failed to open %s\n", JOY_DEV);
    return -1;
  }
  // ゲームパッドの軸の数、ボタンの数、名前を取得
  ioctl(joy_fd, JSIOCGAXES, &num_of_axis);
  ioctl(joy_fd, JSIOCGBUTTONS, &num_of_buttons);
  ioctl(joy_fd, JSIOCGNAME(80), &name_of_joystick);

  printf("Joystick: %s\n", name_of_joystick);
  printf("Axis:     %d\n", num_of_axis);
  printf("Buttons:  %d\n", num_of_buttons);

  // Enter入力待ち
  printf("\nHit Enter key\n");
  while ( getchar() != '\n') { ; }

  // 軸の値、ボタンの値を取得するためのメモリ確保
  joy_button.resize(num_of_buttons,0);
  joy_axis.resize(num_of_axis,0);

  // ファイル制御:ノンブロッキングモード
  fcntl(joy_fd, F_SETFL, O_NONBLOCK);

  while(true)
  {
    // イベント取得
    js_event js;
    read(joy_fd, &js, sizeof(js_event));

    // イベント種別ごとの処理
    switch (js.type & ~JS_EVENT_INIT)
    {
    // 軸イベント
    case JS_EVENT_AXIS:
      // 軸番号のチェック
      if((int)js.number >= num_of_axis){
        printf("Axis number error: %d\n", (int)js.number);
        continue;
      }
      // 軸の値の取得
      joy_axis[(int)js.number] = js.value;
      break;
    // ボタンイベント
    case JS_EVENT_BUTTON:
      // ボタン番号のチェック
      if((int)js.number >= num_of_buttons){
        printf("Button number error: %d\n", (int)js.number);
        continue;
      }
      // ボタンの値の取得
      joy_button[(int)js.number] = js.value;
      break;
    }

    // 表示
    printf("Axis:");
    for(int i = 0; i < num_of_axis; i++){ printf(" %6d", joy_axis[i]); }
    printf("\n");
    printf("Button:");
    for(int i = 0; i < num_of_buttons; i++){ printf(" %d", joy_button[i]); }
    printf("\n");

    usleep(1000);
  }
  // ゲームパッドを閉じる
  close(joy_fd);
  return 0;
}

参考