【Unity】Input Systemで接続中のデバイスを取得する

こじゃらこじゃら

接続されているゲームコントローラーなどを調べる方法はないの?プレイヤー毎のコントローラーも調べたいの。

このはこのは

デバイス一覧は簡単に取得できるわ。プレイヤー毎のデバイスはPlayerInputを使えば良いわ。

Input System環境下で現在接続されているデバイス一覧を取得する方法の解説記事です。

システム全体で接続されているデバイスの他、各々のプレイヤーにペアリングされているデバイスのみを取得することも可能です。

デバイス一覧の取得方法
  • Input System全体で接続されているデバイス一覧を取得する
  • 各プレイヤー毎のデバイス一覧を取得する

これ以外にも、プレイヤー毎のControl Schemeを取得することも可能です。これにより、例えばそのプレイヤーがキーボード・マウス操作なのか、ゲームパッド操作なのかといった判断が可能になります。

本記事では、Input Systemを通じて現在接続されているデバイス一覧を取得する方法について解説していきます。

動作環境
  • Unity 2022.3.0f1
  • Input System 1.5.1

スポンサーリンク

前提条件

事前にInput Systemパッケージがインストールされ、有効化されているものとします。

ここまでの手順が分からない方は、以下記事を参考にセットアップを進めてください。

また、プレイヤー毎に接続されているデバイス一覧を取得するためには、Player Inputを使用している必要があります。

Player Inputの基本的な使い方は、以下記事をご覧ください。

Input System全体で接続されているデバイス一覧を取得する

InputSystem.devicesプロパティから取得できます。

public static ReadOnlyArray<InputDevice> devices { get; }

現在接続されているデバイス一覧をInputDevice型のコレクションとして返します。

参考:Class InputSystem | Input System | 1.5.1

参考:Struct ReadOnlyArray<TValue> | Input System | 1.5.1

サンプルスクリプト

以下、Input Systemで接続されているデバイス一覧をログ出力するサンプルスクリプトです。

GetDevicesExample.cs
using UnityEngine;
using UnityEngine.InputSystem;

public class GetDevicesExample : MonoBehaviour
{
    private void Start()
    {
        // デバイス一覧を取得
        foreach (var device in InputSystem.devices)
        {
            // デバイス名をログ出力
            Debug.Log(device.name);
        }
    }
}

上記をGetDevicesExample.csという名前でUnityプロジェクトに保存し、適当なゲームオブジェクトにアタッチすると機能するようになります。

実行結果

ゲームを実行すると、Input System全体で認識されている接続デバイス一覧がコンソールログに出力されます。

スクリプトの説明

次のコードでデバイス一覧を列挙し、デバイス名をログ出力しています。

// デバイス一覧を取得
foreach (var device in InputSystem.devices)
{
    // デバイス名をログ出力
    Debug.Log(device.name);
}

InputSystem.devicesプロパティが返すReadOnlyArray<T>型はIReadOnlyList<T>型を継承したコレクションのため、foreachやforループが使えます。

プレイヤーにペアリングされているデバイス一覧を取得する

前述の方法はInput Systemのデバイス全体を対象としていました。

現在操作しているプレイヤーにペアリングされているデバイス一覧に限定して取得するには、PlayerInput.devicesプロパティを使います。

public ReadOnlyArray<InputDevice> devices { get; }

InputSystem.devicesプロパティとは違い、staticプロパティでないことにご注意ください。

通常は、プレイヤーオブジェクトなどにアタッチされているPlayerInputコンポーネントに対してアクセスします。

参考:Class PlayerInput | Input System | 1.5.1

サンプルスクリプト

指定されたプレイヤーにペアリングされているデバイス一覧を取得する例です。Player Inputコンポーネントをプレイヤーとして取得します。

GetPlayerDevicesExample.cs
using UnityEngine;
using UnityEngine.InputSystem;

public class GetPlayerDevicesExample : MonoBehaviour
{
    [SerializeField] private PlayerInput _playerInput;

    private void Start()
    {
        if (_playerInput == null)
            return;

        // プレイヤーはアクティブかどうかチェック
        if (!_playerInput.user.valid)
        {
            Debug.Log("アクティブなプレイヤーではありません");
            return;
        }

        // プレイヤー番号をログ出力
        Debug.Log($"===== プレイヤー#{_playerInput.user.index} =====");

        // デバイス一覧を取得
        foreach (var device in _playerInput.devices)
        {
            // デバイス名をログ出力
            Debug.Log(device.name);
        }
    }
}

上記をGetPlayerDevicesExample.csという名前でUnityプロジェクトに保存し、適当なゲームオブジェクトにアタッチし、インスペクターよりプレイヤーのPlayer Inputコンポーネントを指定します。

Player Inputコンポーネントには、予めActions項目にInput Action Assetを指定してください。

実行結果

プレイヤー(Player Inputコンポーネントがアタッチされているオブジェクト)をシーンに追加していくと、各プレイヤー毎にペアリングされたデバイス一覧がログ出力されます。

コントローラー不足などでデバイスが割り当てられなかったプレイヤーは、非アクティブなプレイヤーとみなして取得を行いません。

スクリプトの説明

まず、追加されたプレイヤーがアクティブかどうかをチェックし、アクティブなら以降の処理に進むようにしています。

// プレイヤーはアクティブかどうかチェック
if (!_playerInput.user.valid)
{
    Debug.Log("アクティブなプレイヤーではありません");
    return;
}

PlayerInput.userプロパティは、そのプレイヤーのユーザー情報をInputUser構造体として取得するプロパティです。そして、InputUser.validプロパティアクティブかどうかを判断しています。

非アクティブになる条件は、例えば接続されているコントローラーが足りないなどでペアリングされたデバイスが存在しない場合などです。

参考:Class PlayerInput | Input System | 1.5.1

参考:Struct InputUser | Input System | 1.5.1

アクティブであるかどうかを確認出来たら、以下でプレイヤーのインデックスを取得してログ出力しています。

// プレイヤー番号をログ出力
Debug.Log($"===== プレイヤー#{_playerInput.user.index} =====");

インデックスは0始まりで、プレイヤーが増えるごと1つずつ増えていきます。

シングルプレイヤーの場合は常に0が返されることになります。

参考:Struct InputUser | Input System | 1.5.1

そして、以下処理でPlayerInputインスタンスのdevicesプロパティ経由でペアリングされたデバイス一覧を取得し、ログ出力しています。

// デバイス一覧を取得
foreach (var device in _playerInput.devices)
{
    // デバイス名をログ出力
    Debug.Log(device.name);
}

メモ

PlayerInput.devicesプロパティは、内部的にはPlayerInput.user.pairedDevicesの結果を返しています。

ただし、非アクティブなプレイヤーだった場合は空の結果を返す挙動になっています。

参考:Struct InputUser | Input System | 1.5.1

プレイヤーのControl Schemeを取得する

もし接続されたデバイス一覧ではなく、キーボード&マウス、ゲームパッドなどのControl Schemeを取得したい場合、PlayerInput.currentControlSchemeプロパティを使います。

public string currentControlScheme { get; }

結果は現在のControl Schemeの名前です。

参考:Class PlayerInput | Input System | 1.5.1

サンプルスクリプト

GetPlayerSchemeExample.cs
using UnityEngine;
using UnityEngine.InputSystem;

public class GetPlayerSchemeExample : MonoBehaviour
{
    [SerializeField] private PlayerInput _playerInput;

    private void Start()
    {
        if (_playerInput == null) return;

        // プレイヤーはアクティブかどうかチェック
        if (!_playerInput.user.valid)
        {
            Debug.Log("アクティブなプレイヤーではありません");
            return;
        }

        // プレイヤー番号をログ出力
        Debug.Log($"===== プレイヤー#{_playerInput.user.index} =====");

        // 現在のControl Schemeをログ出力
        Debug.Log($"Control Scheme: {_playerInput.currentControlScheme}");
    }
}

上記をGetPlayerSchemeExample.csという名前でUnityプロジェクトに保存し、適当なゲームオブジェクトにアタッチし、インスペクターよりPlayerInputインスタンスを指定します。

実行結果

プレイヤー毎のControl Scheme名がログ出力されます。

メモ

得られるControl Scheme名は、以下のInput Action Assetで設定されている名前です。

スクリプトの説明

現在のControl Schemeをログ出力する部分は以下です。

// 現在のControl Schemeをログ出力
Debug.Log($"Control Scheme: {_playerInput.currentControlScheme}");

デバイス一覧とは異なり、Control Schemeはただ一つです。

例えば、Keyboard&Mouseはキーボードとマウスの2つのデバイスを使いますが、Control Schemeはまとめて一つとして扱うことが可能です。 [1]

さいごに

現在接続されているデバイス一覧は、システム全体かプレイヤー毎かで取得方法が異なります。

基本的に、プレイヤー毎のデバイス一覧を取得するほうがローカルマルチに移行する時に管理しやすいメリットがあります。

両者の特性を理解した上で使い分けるとより良いでしょう。

関連記事

参考サイト

スポンサーリンク