Python でゲームパッドの入力イベントを取得する

はじめに

以前 Linux Input Subsystem を使ってキーボードの入力イベントを取得して,カムロボの操作を試みた.

確かにキーボードイベントは取得できたが,キーボードでは ON/OFF の操作しかできず,カムロボの移動速度の調整が難しく,変速ボタンを実装して無理やり対応していた.

今回は移動速度を調整できるようゲームパッドの入力イベント取得方法を模索する.

pygame 導入

ゲームパッド

今回使うゲームパッドはこれ.

https://amzn.to/3V6fCCa

Xbox のパッドとして認識されてる様子.

$ cat /proc/bus/input/devices 
I: Bus=0003 Vendor=045e Product=028e Version=0114
N: Name="Microsoft X-Box 360 pad"
P: Phys=usb-0000:00:14.0-8/input0
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/input/input122
U: Uniq=
H: Handlers=event23 js0 
B: PROP=0
B: EV=20000b
B: KEY=7cdb000000000000 0 0 0 0
B: ABS=3003f
B: FF=107030000 0

キーボードの時と同様,インプットデバイスの出力を解析すれば何を入力しているのか判別できるようになるが,今回は pygame という便利なライブラリを使って楽をする.

$ hexdump -C /dev/input/js0 
00000000  28 de da 2d 00 00 81 00  28 de da 2d 00 00 81 01  |(..-....(..-....|
00000010  28 de da 2d 00 00 81 02  28 de da 2d 00 00 81 03  |(..-....(..-....|
00000020  28 de da 2d 00 00 81 04  28 de da 2d 00 00 81 05  |(..-....(..-....|
00000030  28 de da 2d 00 00 81 06  28 de da 2d 00 00 81 07  |(..-....(..-....|
...

pygame

pygame は高水準言語でありながらゲーム開発ができる便利なライブラリの集まり.

pygame news

pygame をインストールする.

$ pip install pygame

適当に入力イベントを拾うだけのコードを書いて,どんなイベントが発生してるか観察する.C では 50 行くらい書いた内容が,Python では 10 行程度で終わってしまった.pygame すごい.

import pygame
import time

pygame.init()
pygame.joystick.init()
joys = pygame.joystick.Joystick(0)
joys.init()

while True:
    eventlist = pygame.event.get()
    print(eventlist)
    time.sleep(0.5)

キャプチャできた Event は eventlist に格納される.あとはを適当に処理すればいい.

>>> type(eventlist)
<class 'list'>
>>> eventlist
[<Event(1540-JoyButtonUp {'joy': 0, 'instance_id': 0, 'button': 1})>]
>>> type(eventlist[0])
<class 'Event'>
>>> eventlist[0].joy
0
KEYTYPEINDEX
Bbutton0
Abutton1
Ybutton2
Xbutton3
L1button4
R1button5
Selectbutton6
Startbutton7
Hartbutton8
Stick Left (Press)button9
Stick Right (Press)button10
Hat Uphat0
Hat Downhat0
Hat Righthat0
Hat Lefthat0
Stick Left (Horizontal)axis0
Stick Left (Vertical)axis1
L2axis2
Stick Right (Horizontal)axis3
Stick Right (Vertical)axis4
R2axis5

ここで得られたデータをもとに,もう少しこのゲームパッドに合わせたコードに修正する.

import pygame
from pygame.locals import *
import time

PAD_BUTTON_B         =  0
PAD_BUTTON_A         =  1
PAD_BUTTON_Y         =  2
PAD_BUTTON_X         =  3
PAD_BUTTON_L1        =  4
PAD_BUTTON_R1        =  5
PAD_BUTTON_SELECT    =  6
PAD_BUTTON_START     =  7
PAD_BUTTON_HART      =  8
PAD_BUTTON_JOY_LEFT  =  9
PAD_BUTTON_JOY_RIGHT = 10
PAD_HAT = 0
PAD_AXIS_LEFT_HORIZONTAL  = 0
PAD_AXIS_LEFT_VERTICAL    = 1
PAD_AXIS_L2               = 2
PAD_AXIS_RIGHT_HORIZONTAL = 3
PAD_AXIS_RIGHT_VERTICAL   = 4
PAD_AXIS_R2               = 5


pygame.init()
pygame.joystick.init()
joys = pygame.joystick.Joystick(0)
joys.init()

while True:
    eventlist = pygame.event.get()
    for e in eventlist:
        #print(e)
        if e.type == pygame.locals.JOYBUTTONDOWN:
            if e.button == PAD_BUTTON_B:
                print("B down")
            elif e.button == PAD_BUTTON_A:
                print("A down")
            elif e.button == PAD_BUTTON_Y:
                print("Y down")
            elif e.button == PAD_BUTTON_X:
                print("X down")
            elif e.button == PAD_BUTTON_L1:
                print("L1 down")
            elif e.button == PAD_BUTTON_R1:
                print("R1 down")
            elif e.button == PAD_BUTTON_SELECT:
                print("SELECT down")
            elif e.button == PAD_BUTTON_START:
                print("START down")
            elif e.button == PAD_BUTTON_HART:
                print("HART down")
            elif e.button == PAD_BUTTON_JOY_RIGHT:
                print("JOY R down")
            elif e.button == PAD_BUTTON_JOY_LEFT:
                print("JOY L down")

        elif e.type == pygame.locals.JOYBUTTONUP:
             if e.button == PAD_BUTTON_B:
                 print("B up")
             elif e.button == PAD_BUTTON_A:
                 print("A up")
             elif e.button == PAD_BUTTON_Y:
                 print("Y up")
             elif e.button == PAD_BUTTON_X:
                 print("X up")
             elif e.button == PAD_BUTTON_L1:
                 print("L1 up")
             elif e.button == PAD_BUTTON_R1:
                 print("R1 up")
             elif e.button == PAD_BUTTON_SELECT:
                 print("SELECT up")
             elif e.button == PAD_BUTTON_START:
                 print("START up")
             elif e.button == PAD_BUTTON_HART:
                 print("HART up")
             elif e.button == PAD_BUTTON_JOY_RIGHT:
                 print("JOY R up")
             elif e.button == PAD_BUTTON_JOY_LEFT:
                 print("JOY L up")

        elif e.type == pygame.locals.JOYAXISMOTION:
            if e.axis == PAD_AXIS_LEFT_HORIZONTAL:
                print("axis L H", e.value)
            elif e.axis == PAD_AXIS_LEFT_VERTICAL:
                print("axis L V", e.value)
            elif e.axis == PAD_AXIS_R2:
                print("axis R2", e.value)
            elif e.axis == PAD_AXIS_RIGHT_HORIZONTAL:
                print("axis R H", e.value)
            elif e.axis == PAD_AXIS_RIGHT_VERTICAL:
                print("axis R V", e.value)
            elif e.axis == PAD_AXIS_L2:
                print("axis L2", e.value)

        elif e.type == pygame.locals.JOYHATMOTION:
            if e.value[0] > 0:
                print("hat Right", e.value[0])
            if e.value[0] < 0:
                print("hat Left", e.value[0])
            if e.value[1] > 0:
                print("hat Up", e.value[1])
            if e.value[1] < 0:
                print("hat Down", e.value[1])

    time.sleep(0.1)

ソケットと組み合わせて tcp で操作してみた感じはこんな.

おわりに

今回は 8bitdo SN30 Pro の入力イベント取得方法を模索した.思いの外簡単に実装できた.

今回使ったのはほぼジョイスティック周りのライブラリのみなので,他にも使えそうなものがあったら紹介する.たぶん.

コメント

タイトルとURLをコピーしました