1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

vgamepad でゲームパッドをエミュレートする

Posted at

概要

python vgamepad でゲームパッドをエミュレートする。

自作したゲームパッドからUART等でパソコンにデータを送信しても、他のアプリはゲームパッドの入力として認識しない。
そのためpythonでCOMポートからデータを受信し、vgamepad でゲームパッドの入力と認識させる。

vgamepad のインストール

途中でドライバのインストールを求められるのでインストールする。

pip install vgamepad

vgamepad の使い方

vgamepad の使用方法は下記に記載されている。
https://pypi.org/project/vgamepad/

コードとメモ
import vgamepad as vg

# 初期化 (内部でresetとupdateが行われる)
gamepad = vg.VDS4Gamepad() # DualShock4 gamepad.

# ボタンを押す (button1=0x0010, button2=0x0020, button3=0x0040 ... button12=0x8000)
gamepad.press_button(button=vg.DS4_BUTTONS.DS4_BUTTON_TRIANGLE)
gamepad.press_special_button(special_button=vg.DS4_SPECIAL_BUTTONS.DS4_SPECIAL_BUTTON_TOUCHPAD)
gamepad.update()
# ボタンを離す
gamepad.release_button(button=vg.DS4_BUTTONS.DS4_BUTTON_TRIANGLE)
gamepad.release_special_button(special_button=vg.DS4_SPECIAL_BUTTONS.DS4_SPECIAL_BUTTON_TOUCHPAD)
gamepad.update()

# 十字キー (0=上,1=右上,2=右,3=右下,4=下,5=左下,6=左,7=右上,8=入力無し)
gamepad.directional_pad(direction=vg.DS4_DPAD_DIRECTIONS.DS4_BUTTON_DPAD_NORTHWEST)
gamepad.update()

# トリガー (0.0=入力無し, 1.0=最大)
gamepad.left_trigger_float(value_float=0.5)
gamepad.right_trigger_float(value_float=0.5)
gamepad.update()
# 引数を整数で受け取る場合 (0x00=入力無し, 0xFF=最大)
gamepad.left_trigger( 0x80 )
gamepad.right_trigger( 0x00 )
gamepad.update()

# ジョイスティック (-1.0=左/下, 0.0=中央(入力無し), 1.0=右/上)
gamepad.left_joystick_float(x_value_float=0.0, y_value_float=0.2)
gamepad.right_joystick_float(x_value_float=-1.0, y_value_float=1.0)
gamepad.update()
# 引数を整数で受け取る場合 (0x00=左/下, 0x80=中央(入力無し), 0xFF=右/上)
gamepad.left_joystick( 0x20, 0x80 )
gamepad.right_joystick( 0x20, 0x80 )
gamepad.update()

# プログラム終了前に状態をデフォルトに戻す
gamepad.reset()  # 全ての入力をデフォルト(無し)に戻す
gamepad.update() # 変更を反映する

COMポートから読み出してゲームパッドに反映するサンプル

COMポートから16進文字列を読み出してゲームボタンの押下に反映する。
データの区切りは改行コードで、例えば右上を押しながら×を押した場合は C2\r\n
8bitのうち上位4bitが十字キー、下位4bitがボタンで詳細は下記の通り。

7 6 5 4 3 2 1 0
×
コード
import vgamepad as vg
import time
import serial

# pip install vgamepad
# pip install pyserial

def get_pad_dir(pad):
  PAD_N = 0x8 # ↑
  PAD_E = 0x4 # →
  PAD_S = 0x2 # ↓
  PAD_W = 0x1 # ←
  if pad == PAD_N | PAD_W: return vg.DS4_DPAD_DIRECTIONS.DS4_BUTTON_DPAD_NORTHWEST
  if pad == PAD_N:         return vg.DS4_DPAD_DIRECTIONS.DS4_BUTTON_DPAD_NORTH
  if pad == PAD_N | PAD_E: return vg.DS4_DPAD_DIRECTIONS.DS4_BUTTON_DPAD_NORTHEAST
  if pad == PAD_E:         return vg.DS4_DPAD_DIRECTIONS.DS4_BUTTON_DPAD_EAST
  if pad == PAD_S | PAD_E: return vg.DS4_DPAD_DIRECTIONS.DS4_BUTTON_DPAD_SOUTHEAST
  if pad == PAD_S:         return vg.DS4_DPAD_DIRECTIONS.DS4_BUTTON_DPAD_SOUTH
  if pad == PAD_S | PAD_W: return vg.DS4_DPAD_DIRECTIONS.DS4_BUTTON_DPAD_SOUTHWEST
  if pad == PAD_W:         return vg.DS4_DPAD_DIRECTIONS.DS4_BUTTON_DPAD_WEST
  return vg.DS4_DPAD_DIRECTIONS.DS4_BUTTON_DPAD_NONE

if __name__ == "__main__":
  buttons = [
    vg.DS4_BUTTONS.DS4_BUTTON_TRIANGLE, # △
    vg.DS4_BUTTONS.DS4_BUTTON_CIRCLE,   # ○
    vg.DS4_BUTTONS.DS4_BUTTON_CROSS,    # ×
    vg.DS4_BUTTONS.DS4_BUTTON_SQUARE    # □
  ]
  gamepad = vg.VDS4Gamepad()
  port_num = '10'
  with serial.Serial('COM' + port_num, baudrate=38400, stopbits=serial.STOPBITS_ONE, parity=serial.PARITY_NONE) as comport:
    try:
      prev_str = ''
      while True:
        time.sleep(10.0 / 1000)

        recv_str_list = (prev_str + comport.read_all().decode()).replace('\r', '\n').split('\n')
        prev_str = ''
        for recv_str in recv_str_list:
          if len(recv_str) >= 2:
            # print(recv_str)
            recv_data = int(recv_str, 16) & 0xFF

            gamepad.directional_pad( get_pad_dir(recv_data >> 4) )

            button_stat = recv_data & 0x0F
            for i in range(4):
              if (button_stat & (0x8 >> i)) != 0:
                gamepad.press_button(button=buttons[i])
              else:
                gamepad.release_button(button=buttons[i])

            gamepad.update()
          elif len(recv_str) >= 1:
            prev_str = recv_str

    except KeyboardInterrupt: # Ctrl + C で終了
      pass

  gamepad.reset()
  gamepad.update()

入力テスト

下記サイトでゲームパッドとして認識されているか確認できる。
https://gamepad-tester.com/

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?