fc2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム » Unity »【Unity】【C#】InputSystem の displayName や control path から Key (キーコード) を取得(変換)する

【Unity】【C#】InputSystem の displayName や control path から Key (キーコード) を取得(変換)する  


 InputSystem も Verified (正式版) となり、(旧)InputManager との混在も可能でもあるが、いずれ InputSystem の方法を中心として使いたいので調査中。

 「InputSystem.Key と実際の(日本語)キーボードとの対応を調べた」にも少し書いたが、InputSystem のキーは物理配列に依存し、基本的に英語キーボードが enum の名前となっているので、日本語キーボードだと特に記号系が使いにくい。

 (旧)KeyCode でも記号は使いづらかったが、幸いなことに InputSystem では現在のキーボードレイアウトから Key を逆引きできるようだ。これを使えば、日本語キーボード英語キーボード等に依存することなく、ある程度は記号も使えるかも知れない(といっても、101 キーボードなど、無いキーはどうにもならないだろうが…)。

(参考)
キーボード。日本語配列と英語配列。
101/104/109…キーボード配列、種類、構造についての解説と一覧
キー配列


(※) Unity 2019.4.11f1 / InputSystem 1.0.0 / Windows10(x64) で確認



■displayName と control path の簡単なテスト

 とりあえずの簡単な実験用コードなので、書き方とかは気にしないで欲しい(笑)。

 なお、[A]~[Z] などは特記することもないので、ここでは、記号系のキーのみでやっている。

using UnityEngine;

#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
#endif

public class KeyboardDisplayNameTest : MonoBehaviour
{
#if ENABLE_INPUT_SYSTEM
private void Start()
{
KeyboardDisplayNameCheck();
}

void KeyboardDisplayNameCheck()
{
{
var keyControlFromLayout = Keyboard.current.FindKeyOnCurrentKeyboardLayout("\\");
Debug.Log("[\\] from keyboard layout : " + keyControlFromLayout.keyCode);
var keyControlFromPath = (KeyControl)Keyboard.current["#(\\\\)"];
Debug.Log("[\\] from control path : " + keyControlFromPath.keyCode);
}
{
var keyControlFromLayout = Keyboard.current.FindKeyOnCurrentKeyboardLayout("^");
Debug.Log("[^] from keyboard layout : " + keyControlFromLayout.keyCode);
var keyControlFromPath = (KeyControl)Keyboard.current["#(^)"];
Debug.Log("[^] from control path : " + keyControlFromPath.keyCode);
}
{
var keyControlFromLayout = Keyboard.current.FindKeyOnCurrentKeyboardLayout("-");
Debug.Log("[-] from keyboard layout : " + keyControlFromLayout.keyCode);
var keyControlFromPath = (KeyControl)Keyboard.current["#(-)"];
Debug.Log("[-] from control path : " + keyControlFromPath.keyCode);
}
{
var keyControlFromLayout = Keyboard.current.FindKeyOnCurrentKeyboardLayout("@");
Debug.Log("[@] from keyboard layout : " + keyControlFromLayout.keyCode);
var keyControlFromPath = (KeyControl)Keyboard.current["#(@)"];
Debug.Log("[@] from control path : " + keyControlFromPath.keyCode);
}
{
var keyControlFromLayout = Keyboard.current.FindKeyOnCurrentKeyboardLayout("[");
Debug.Log("[[] from keyboard layout : " + keyControlFromLayout.keyCode);
var keyControlFromPath = (KeyControl)Keyboard.current["#([)"];
Debug.Log("[[] from control path : " + keyControlFromPath.keyCode);
}
{
var keyControlFromLayout = Keyboard.current.FindKeyOnCurrentKeyboardLayout("]");
Debug.Log("[]] from keyboard layout : " + keyControlFromLayout.keyCode);
var keyControlFromPath = (KeyControl)Keyboard.current["#(])"];
Debug.Log("[]] from control path : " + keyControlFromPath.keyCode);
}
{
var keyControlFromLayout = Keyboard.current.FindKeyOnCurrentKeyboardLayout(":");
Debug.Log("[:] from keyboard layout : " + keyControlFromLayout.keyCode);
var keyControlFromPath = (KeyControl)Keyboard.current["#(:)"];
Debug.Log("[:] from control path : " + keyControlFromPath.keyCode);
}
{
var keyControlFromLayout = Keyboard.current.FindKeyOnCurrentKeyboardLayout(";");
Debug.Log("[;] from keyboard layout : " + keyControlFromLayout.keyCode);
var keyControlFromPath = (KeyControl)Keyboard.current["#(;)"];
Debug.Log("[;] from control path : " + keyControlFromPath.keyCode);
}
{
var keyControlFromLayout = Keyboard.current.FindKeyOnCurrentKeyboardLayout(",");
Debug.Log("[,] from keyboard layout : " + keyControlFromLayout.keyCode);
var keyControlFromPath = (KeyControl)Keyboard.current["#(,)"];
Debug.Log("[,] from control path : " + keyControlFromPath.keyCode);
}
{
var keyControlFromLayout = Keyboard.current.FindKeyOnCurrentKeyboardLayout(".");
Debug.Log("[.] from keyboard layout : " + keyControlFromLayout.keyCode);
var keyControlFromPath = (KeyControl)Keyboard.current["#(.)"];
Debug.Log("[.] from control path : " + keyControlFromPath.keyCode);
}
{
var keyControlFromLayout = Keyboard.current.FindKeyOnCurrentKeyboardLayout("/");
Debug.Log("[/] from keyboard layout : " + keyControlFromLayout.keyCode);
var keyControlFromPath = (KeyControl)Keyboard.current["#(\\/)"];
Debug.Log("[/] from control path : " + keyControlFromPath.keyCode);
}
}
#endif
}

[\] from keyboard layout : OEM2
[\] from control path : OEM2
[^] from keyboard layout : Equals
[^] from control path : Equals
[-] from keyboard layout : Minus
[-] from control path : Minus
[@] from keyboard layout : LeftBracket
[@] from control path : LeftBracket
[[] from keyboard layout : RightBracket
[[] from control path : RightBracket
[]] from keyboard layout : Backslash
[]] from control path : Backslash
[:] from keyboard layout : Quote
[:] from control path : Quote
[;] from keyboard layout : Semicolon
[;] from control path : Semicolon
[,] from keyboard layout : Comma
[,] from control path : Comma
[.] from keyboard layout : Period
[.] from control path : Period
[/] from keyboard layout : Slash
[/] from control path : Slash

 [-]キーと Minus, [;]キーと Semicolon, [,]キーと Comma, [.]キーと Period, [/]キーと Slash は日本語キーボードとも合っているが、それ以外は英語キーボードの物理位置になっていることがわかる。海外でも対応できるアプリを作るなら、記号の利用は注意が必要かも知れない。

 その中でも少し特異なのが、バックスラッシュ(日本語では"\"でもある)だけは「OEM2」となっていることだ。この「OEM~」はどうやら、104, 106, … キーボードのように数が違うとき、追加されたキーになるらしい(英語キーボード日本語キーボードを比較してみるとわかるが、英語配列には日本語配列の [\_][\|] の物理位置に、キーが存在しない)。なので、キーボードによってはあったりなかったりするのかも知れない(※未確認)。

 余談だが、コードで中括弧で囲む表記 "{"~"}" を多用しているが、中括弧はローカル変数のスコープを限定できるので、同じ変数名を1つのメソッド内で使うのに有効な手段になったりする。以前、仕事のコードレビューで「条件文ないのに中括弧があるよ」と指摘された(コードがおかしいと言われた)ことがあるが、このテクニックは初期の C言語の時代(80年代)から存在するswitch 文で使うとかなり便利。1つのメソッドに大量に変数名を書くよりわかりやすい利点もある。なぜかこの使い方をベテランでも知らない人が多い?実は割と基本中の基本である ← 私は仕事で人から教わるより、独学が多いためか、学生時代に超初心者向けのC言語の本で学んだことをハッキリと覚えている)。



■displayName や control path から Key (キーコード) を取得する

 簡単なテストでわかったように、displayName や control path("#(a)" のような書き方)を使えば KeyControl を取得できる(ちなみに KeyControl (InputControl) をそのまま ToString() すれば、フルパス(?正式な名称ではないが、長いパス名)が見れる)。

 プロパティ:KeyControl.keyCode から Key が取得できるので、displayName や control path から InputSystem.Key を取得するメソッドを定義してみよう。

●displayName や control path → InputSystem.Key 取得メソッド
using UnityEngine;

#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
#endif

#if ENABLE_INPUT_SYSTEM
/// <summary>
/// displayName から Key (enum) を取得する.
/// ※失敗は None になる。None 自体は取得できない。
/// https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Controls.html#control-paths
/// http://fantom1x.blog130.fc2.com/blog-entry-370.html
/// </summary>
/// <param name="displayName">例: "a", "/", "\\" 等</param>
/// <returns></returns>
public static Key GetKeyFromDisplayName(string displayName)
{
try
{
var control = Keyboard.current.FindKeyOnCurrentKeyboardLayout(displayName);
return control.keyCode;
}
catch (Exception e)
{
#if UNITY_EDITOR
Debug.LogError($"displayName = {displayName} : {e.Message}");
#endif
}
return Key.None; //失敗
}

/// <summary>
/// control path から Key (enum) を取得する.
/// ※失敗は None になる。None 自体は取得できない。
/// https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Controls.html#control-paths
/// http://fantom1x.blog130.fc2.com/blog-entry-370.html
/// </summary>
/// <param name="controlPath">例: "#(a)", "#(\\/)", "#(\\\\)" 等</param>
/// <returns>成功 = None 以外 / 失敗 = None</returns>
public static Key GetKeyFromControlPath(string controlPath)
{
try
{
var control = (KeyControl)Keyboard.current[controlPath];
return control.keyCode;
}
catch (Exception e)
{
#if UNITY_EDITOR
Debug.LogError($"controlPath = {controlPath} : {e.Message}");
#endif
}
return Key.None; //失敗
}
#endif


//使い方
var backslashKey = GetKeyFromDisplayName("\\"); //OEM2
var aKey = GetKeyFromControlPath("#(a)"); //A

 引数は文字列であり、1文字間違えただけでもエラーとなるので、try-catch で囲んでおいた。

 また、取得失敗時には Key.None を返すようにしておいた。ちなみに Input 系メソッドで KeyCode.None を使ってもエラーにならないが、InputSystem では Keyboard.current[Key.None] のように使うとエラーとなるので注意しよう。

 実際に使用するときは、毎回取得させるより、結果をキャッシュして使いまわした方がパフォーマンスが良いだろう。

 もし、キーボードの種類に依存しないでキーが取得できるなら、かえって KeyCode より使い勝手が良くなるかも知れない。ただ現バージョン(1.0.0)では漢字変換キーや CapsLock を使おうとすると不具合を起こしたりするので、使うなら気をつけないといけないかも(← Unity公式にバグレポートとして出したが、「問題を確認できず」と返信が来た。もしかしたら、使っているキーボードによるのかも知れない:Windows日本語106キーボードとか、Shiftを押してCapsLockをするタイプのみとか、メーカーとか、ハードウェア依存がある?)。まだまだ仕様なのか不具合なのか、よくわからない事も多いので、色々試してみる必要がありそうだ(笑)。



 マニュアルを見てると、「No corresponding API yet.」(まだ対応するものがない)というのがいくつもあるので、全て新旧一致できるわけではないようだが、よく使われる機能なら完全互換でいけそうなものも多いね。

 ただ、今まで使っていた (旧)InputManager のコード(※主に Input) は全て書き換えないとならないので、大変な労力がいるのが難点。なので、しばらくは一部機能だけ使う感じになるだろう。

 いずれ、スワイプ, ピンチ, 長押しなどのライブラリも InputSystem に対応しようと思っているが、ラッパー関数でも作らないと、旧新互換で作るのは骨が折れるね(笑)。



スワイプ, ピンチ, 長押しなども同梱されている多機能 Android プラグイン







(関連記事)
【Unity】【C#】(旧)KeyCode と InputSystem.Key の対応
【Unity】【C#】InputSystem.Key をリアルタイムで調べる / Windows 日本語キーボードでの Key 一覧
【Unity】【C#】KeyCode をリアルタイムで調べる / Windows 日本語キーボードでの記号の KeyCode 一覧
【Unity】【C#】InputSystem の Keyboard クラスと (旧)Input.GetKey の対応
【Unity】【C#】InputSystem の Mouse クラスと(旧)Input.GetMouseButton の対応
【Unity】【C#】InputSystem でマウスのホイール(scroll)取得と (旧)Input との対応
【Unity】【C#】InputSystem.TouchPhase の IsActive(), IsEndedOrCanceled() [拡張メソッド] の具体値
【Unity】5ボタンマウスの KeyCode 図解


関連記事
スポンサーサイト



category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityリファレンス  Unityライブラリ  InputSystem 
tb: 0   cm: --


トラックバック

トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/370-7406bc32
この記事にトラックバックする(FC2ブログユーザー)

プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR

▲ Pagetop