10月 142017
 

UnityのInputManagerで指定できるボタン名とKeyCodeの相互変換を試みます。

その前にいくらか前提を説明します。

Inputは設定が面倒

Unityでユーザの操作入力を取り扱うにはInputクラスを使います。

押しているかどうかboolで判断するButton系の取得と、どれぐらいの強さで入力されているか[-1, 1]範囲のfloatを返すAxis系があります。

ここで入力値を得るために指定する名前は、入力設定(InputManager)で設定した仮想軸の名前になります。デフォルトではHorizontal、Vertical、Fire1、Fire2、Fire3、Jump、Submit、Cancelなどが設定されているはずです。定義した仮想軸はButtonとしてもAxisとしても使用できます。良い感じに補間するための設定がInputManagerにあります。

任意の名前をつけた仮想軸を定義できるのは良いのですが、ゲーム中に設定を差し替えることができなかったり、割り当てるボタンを指定するフォーマットに統一性がなかったりと、そのまま使おうとするのは無理があると思います。どうしてこうなった。

Inputにラッパーかぶせるとかするにしても、InputManagerの設定は無視できないところです。しかし、InputManagerをスクリプトから操作するAPIが公開されていません。うわぁ、めんどくせぇ。

とはいえ、これを手で設定するのはあり得ないでしょう。

どうせYAMLで書き出せばテキスト処理でどうとでもなると思い、昔はYAMLを書き出すスクリプトを書いたこともありましたが、もっと良い方法がありました。

上の記事では、SerializedPropertyを通してInputManager.assetを編集する試みをしています。フォーマットがYAMLかどうかにも依存しないし、一番まともっぽいアプローチ。

ただ、割り当てるボタンを文字列で指定するところが面倒です。これ結局KeyCodeを指定することと同義なのですが、ドロップダウンリストで指定するわけでもなく、独自フォーマットの名前を直接入力しないといけません。

ボタン名の大まかなルールは上記ドキュメントにまとまっていますが、正しい名前を手で打ち込むのもバカらしいですし、そもそも正解がよくわかりません。

というわけで、前置きが長くなりましたが、KeyCodeとボタン名の相互変換を試みます。このボタン名は仮想軸の割り当てに使ってもらってもいいし、Input.GetKey()に直接指定しても使えます。後者の場合、普通にKeyCodeを指定する方が当然便利です。

InputManagerの自動生成については先に紹介した記事を参考にしてください。私はもう少し都合よく整理していますが、基礎は同じなので割愛。

実装

KeyCodeとして定義されたenumの名前変換テーブルを作ってやればOKです。

以前に書いたキャメルケースの分割を利用します(今回のために実装した副産物を別の記事にしただけ)。

public static class KeyCodeUtil
{
    private static readonly Dictionary<KeyCode, string> specifiedNames = new Dictionary<KeyCode, string> {
        { KeyCode.Exclaim, "!" },
        { KeyCode.DoubleQuote, "\"" },
        { KeyCode.Hash, "#" },
        { KeyCode.Dollar, "$" },
        { KeyCode.Ampersand, "&" },
        { KeyCode.Quote, "'" },
        { KeyCode.LeftParen, "(" },
        { KeyCode.RightParen, ")" },
        { KeyCode.Asterisk, "*" },
        { KeyCode.Plus, "+" },
        { KeyCode.Comma, "," },
        { KeyCode.Minus, "-" },
        { KeyCode.Period, "." },
        { KeyCode.Slash, "/" },
        { KeyCode.Colon, ":" },
        { KeyCode.Semicolon, ";" },
        { KeyCode.Less, "<" },
        { KeyCode.Equals, "=" },
        { KeyCode.Greater, ">" },
        { KeyCode.Question, "?" },
        { KeyCode.At, "@" },
        { KeyCode.LeftBracket, "[" },
        { KeyCode.Backslash, "\\" },
        { KeyCode.RightBracket, "]" },
        { KeyCode.Caret, "^" },
        { KeyCode.Underscore, "_" },
        { KeyCode.BackQuote, "`" },
        { KeyCode.KeypadPeriod, "[.]" },
        { KeyCode.KeypadDivide, "[/]" },
        { KeyCode.KeypadMultiply, "[*]" },
        { KeyCode.KeypadMinus, "[-]" },
        { KeyCode.KeypadPlus, "[+]" },
        { KeyCode.KeypadEnter, "enter" },
        { KeyCode.KeypadEquals, "equals" },
        { KeyCode.Print, "print screen" },
    };

    private static readonly HashSet<string> ignoredNames = new HashSet<string> {
        "LeftApple",
        "RightApple",
    };

    private static readonly HashSet<KeyCode> ignoredCodes = new HashSet<KeyCode> {
        KeyCode.None,
    };

    public static KeyCode toCode(string name)
    {
        KeyCode code;
        if(_str2code.TryGetValue(name, out code)) {
            return code;
        }
        return KeyCode.None;
    }

    public static string toName(this KeyCode code)
    {
        string name;
        if(_code2str.TryGetValue(code, out name)) {
            return name;
        }
        return "";
    }

    public static KeyCode mouse(int button)
    {
        if(button < 0 || button >= 7) return KeyCode.None;

        var code = KeyCode.Mouse0 + button;
        return code;
    }

    public static KeyCode joystick(int button)
    {
        if(button < 0 || button >= 20) return KeyCode.None;

        var code = KeyCode.JoystickButton0 + button;
        return code;
    }

    public static KeyCode joystick(int num, int button)
    {
        if(button < 0 || button >= 20) return KeyCode.None;

        var code = KeyCode.None;
        switch(num) {
        case 1:
            code = KeyCode.Joystick1Button0;
            break;
        case 2:
            code = KeyCode.Joystick2Button0;
            break;
        case 3:
            code = KeyCode.Joystick3Button0;
            break;
        case 4:
            code = KeyCode.Joystick4Button0;
            break;
        default:
            return KeyCode.None;
        }

        code += button;
        return code;
    }

    static KeyCodeUtil()
    {
        foreach(var pair in specifiedNames) {
            assign(pair.Key, pair.Value);
        }

        foreach(var name in Enum.GetNames(typeof(KeyCode))) {
            assign(name);
        }
    }

    private static void assign(string name)
    {
        if(ignoredNames.Contains(name)) return;

        var code = (KeyCode)Enum.Parse(typeof(KeyCode), name);
        if(ignoredCodes.Contains(code)) return;

        if(_code2str.ContainsKey(code)) return;

        var parts = splitName(name);

        switch(parts[0]) {
        case "alpha":
            assign(code, parts[1]);
            return;
        case "f":
            assign(code, name.ToLowerInvariant());
            return;
        case "keypad":
            parts = parts.slice(1);
            name = "[{0}]".format(string.Join(" ", parts.ToArray()));
            assign(code, name);
            return;
        }

        switch(parts.last()) {
        case "arrow":
            parts.RemoveAt(parts.Count - 1);
            break;
        case "control":
            parts[parts.Count - 1] = "ctrl";
            break;
        case "command":
            parts[parts.Count - 1] = "cmd";
            break;
        case "super":
            parts[parts.Count - 1] = "super";
            break;
        }

        assign(code, string.Join(" ", parts.ToArray()));
    }

    private static void assign(KeyCode code, string name)
    {
        _str2code[name] = code;
        _code2str[code] = name;
    }

    private static List<string> splitName(string name)
    {
        var parts = name.splitCamelCase();
        for(var i = 0; i < parts.Count; ++i) {
            parts[i] = parts[i].ToLowerInvariant();
        }
        return parts;
    }

    private static readonly Dictionary<string, KeyCode> _str2code = new Dictionary<string, KeyCode>();
    private static readonly Dictionary<KeyCode, string> _code2str = new Dictionary<KeyCode, string>();
}

一応、ほぼすべてのKeyCodeが正しく指定できているか確認したつもりです。名前が不正だと、強制的に空欄にされるので、念のため確認してみてください。

=equalsとか、どっちがキーパッドだよって感じですが、イコールキーの存在するキーボード持ってなかったので、動作確認はしていなくて、調査して出てきた結果を採用しています。キーパッドなら他と命名規則を統一して[equals]あるいは[=]のようにしてくれれば混乱しないのに。

Windowsキーはsuper系で名前がまとめられています。その名称をLinux文化に合わせるなら、KeyCodeの方もSuperにしておいてほしい・・・未定義なのかと思った・・・。

面倒なことにLeftApple、RightAppleはそれぞれLeftCommand、RightCommandと同じ値が割り当てられていて、区別不可能です(enumの内部表現は整数しか持ちません)。名前指定の存在するCommandキーとしてAppleキーをまとめるため、Enum.GetNames()からEnum.Parse()するという回りくどい対応になっています。そうしないとAppleキーの方で名前取得してしまうことがあるためです。良い子のみんなはenumの重複定義はやめようね。

対応表

せっかくなので、KeyCodeとボタン名の対応表も作りました。公式はこの表を用意してくれれば良かったんだ。

先にも述べたとおり、AppleキーはCommandキーと区別つかないので、同じボタン名が割り当てられています。

KeyCode ボタン名
None 未定義
Backspace backspace
Tab tab
Clear clear
Return return
Pause pause
Escape escape
Space space
Exclaim !
DoubleQuote
Hash #
Dollar $
Ampersand &
Quote
LeftParen (
RightParen )
Asterisk *
Plus +
Comma ,
Minus
Period .
Slash /
Alpha0 0
Alpha1 1
Alpha2 2
Alpha3 3
Alpha4 4
Alpha5 5
Alpha6 6
Alpha7 7
Alpha8 8
Alpha9 9
Colon :
Semicolon ;
Less <
Equals =
Greater >
Question ?
At @
LeftBracket [
Backslash \
RightBracket ]
Caret ^
Underscore _
BackQuote `
A a
B b
C c
D d
E e
F f
G g
H h
I i
J j
K k
L l
M m
N n
O o
P p
Q q
R r
S s
T t
U u
V v
W w
X x
Y y
Z z
Delete delete
Keypad0 [0]
Keypad1 [1]
Keypad2 [2]
Keypad3 [3]
Keypad4 [4]
Keypad5 [5]
Keypad6 [6]
Keypad7 [7]
Keypad8 [8]
Keypad9 [9]
KeypadPeriod [.]
KeypadDivide [/]
KeypadMultiply [*]
KeypadMinus [-]
KeypadPlus [+]
KeypadEnter enter
KeypadEquals equals
UpArrow up
DownArrow down
RightArrow right
LeftArrow left
Insert insert
Home home
End end
PageUp page up
PageDown page down
F1 f1
F2 f2
F3 f3
F4 f4
F5 f5
F6 f6
F7 f7
F8 f8
F9 f9
F10 f10
F11 f11
F12 f12
F13 f13
F14 f14
F15 f15
Numlock numlock
CapsLock caps lock
ScrollLock scroll lock
RightShift right shift
LeftShift left shift
RightControl right ctrl
LeftControl left ctrl
RightAlt right alt
LeftAlt left alt
RightApple right cmd
RightCommand right cmd
LeftCommand left cmd
LeftApple left cmd
LeftWindows left super
RightWindows right super
AltGr alt gr
Help help
Print print screen
SysReq sys req
Break break
Menu menu
Mouse0 mouse 0
Mouse1 mouse 1
Mouse2 mouse 2
Mouse3 mouse 3
Mouse4 mouse 4
Mouse5 mouse 5
Mouse6 mouse 6
JoystickButton0 joystick button 0
JoystickButton1 joystick button 1
JoystickButton2 joystick button 2
JoystickButton3 joystick button 3
JoystickButton4 joystick button 4
JoystickButton5 joystick button 5
JoystickButton6 joystick button 6
JoystickButton7 joystick button 7
JoystickButton8 joystick button 8
JoystickButton9 joystick button 9
JoystickButton10 joystick button 10
JoystickButton11 joystick button 11
JoystickButton12 joystick button 12
JoystickButton13 joystick button 13
JoystickButton14 joystick button 14
JoystickButton15 joystick button 15
JoystickButton16 joystick button 16
JoystickButton17 joystick button 17
JoystickButton18 joystick button 18
JoystickButton19 joystick button 19
Joystick1Button0 joystick 1 button 0
Joystick1Button1 joystick 1 button 1
Joystick1Button2 joystick 1 button 2
Joystick1Button3 joystick 1 button 3
Joystick1Button4 joystick 1 button 4
Joystick1Button5 joystick 1 button 5
Joystick1Button6 joystick 1 button 6
Joystick1Button7 joystick 1 button 7
Joystick1Button8 joystick 1 button 8
Joystick1Button9 joystick 1 button 9
Joystick1Button10 joystick 1 button 10
Joystick1Button11 joystick 1 button 11
Joystick1Button12 joystick 1 button 12
Joystick1Button13 joystick 1 button 13
Joystick1Button14 joystick 1 button 14
Joystick1Button15 joystick 1 button 15
Joystick1Button16 joystick 1 button 16
Joystick1Button17 joystick 1 button 17
Joystick1Button18 joystick 1 button 18
Joystick1Button19 joystick 1 button 19
Joystick2Button0 joystick 2 button 0
Joystick2Button1 joystick 2 button 1
Joystick2Button2 joystick 2 button 2
Joystick2Button3 joystick 2 button 3
Joystick2Button4 joystick 2 button 4
Joystick2Button5 joystick 2 button 5
Joystick2Button6 joystick 2 button 6
Joystick2Button7 joystick 2 button 7
Joystick2Button8 joystick 2 button 8
Joystick2Button9 joystick 2 button 9
Joystick2Button10 joystick 2 button 10
Joystick2Button11 joystick 2 button 11
Joystick2Button12 joystick 2 button 12
Joystick2Button13 joystick 2 button 13
Joystick2Button14 joystick 2 button 14
Joystick2Button15 joystick 2 button 15
Joystick2Button16 joystick 2 button 16
Joystick2Button17 joystick 2 button 17
Joystick2Button18 joystick 2 button 18
Joystick2Button19 joystick 2 button 19
Joystick3Button0 joystick 3 button 0
Joystick3Button1 joystick 3 button 1
Joystick3Button2 joystick 3 button 2
Joystick3Button3 joystick 3 button 3
Joystick3Button4 joystick 3 button 4
Joystick3Button5 joystick 3 button 5
Joystick3Button6 joystick 3 button 6
Joystick3Button7 joystick 3 button 7
Joystick3Button8 joystick 3 button 8
Joystick3Button9 joystick 3 button 9
Joystick3Button10 joystick 3 button 10
Joystick3Button11 joystick 3 button 11
Joystick3Button12 joystick 3 button 12
Joystick3Button13 joystick 3 button 13
Joystick3Button14 joystick 3 button 14
Joystick3Button15 joystick 3 button 15
Joystick3Button16 joystick 3 button 16
Joystick3Button17 joystick 3 button 17
Joystick3Button18 joystick 3 button 18
Joystick3Button19 joystick 3 button 19
Joystick4Button0 joystick 4 button 0
Joystick4Button1 joystick 4 button 1
Joystick4Button2 joystick 4 button 2
Joystick4Button3 joystick 4 button 3
Joystick4Button4 joystick 4 button 4
Joystick4Button5 joystick 4 button 5
Joystick4Button6 joystick 4 button 6
Joystick4Button7 joystick 4 button 7
Joystick4Button8 joystick 4 button 8
Joystick4Button9 joystick 4 button 9
Joystick4Button10 joystick 4 button 10
Joystick4Button11 joystick 4 button 11
Joystick4Button12 joystick 4 button 12
Joystick4Button13 joystick 4 button 13
Joystick4Button14 joystick 4 button 14
Joystick4Button15 joystick 4 button 15
Joystick4Button16 joystick 4 button 16
Joystick4Button17 joystick 4 button 17
Joystick4Button18 joystick 4 button 18
Joystick4Button19 joystick 4 button 19
Joystick5Button0 joystick 5 button 0
Joystick5Button1 joystick 5 button 1
Joystick5Button2 joystick 5 button 2
Joystick5Button3 joystick 5 button 3
Joystick5Button4 joystick 5 button 4
Joystick5Button5 joystick 5 button 5
Joystick5Button6 joystick 5 button 6
Joystick5Button7 joystick 5 button 7
Joystick5Button8 joystick 5 button 8
Joystick5Button9 joystick 5 button 9
Joystick5Button10 joystick 5 button 10
Joystick5Button11 joystick 5 button 11
Joystick5Button12 joystick 5 button 12
Joystick5Button13 joystick 5 button 13
Joystick5Button14 joystick 5 button 14
Joystick5Button15 joystick 5 button 15
Joystick5Button16 joystick 5 button 16
Joystick5Button17 joystick 5 button 17
Joystick5Button18 joystick 5 button 18
Joystick5Button19 joystick 5 button 19
Joystick6Button0 joystick 6 button 0
Joystick6Button1 joystick 6 button 1
Joystick6Button2 joystick 6 button 2
Joystick6Button3 joystick 6 button 3
Joystick6Button4 joystick 6 button 4
Joystick6Button5 joystick 6 button 5
Joystick6Button6 joystick 6 button 6
Joystick6Button7 joystick 6 button 7
Joystick6Button8 joystick 6 button 8
Joystick6Button9 joystick 6 button 9
Joystick6Button10 joystick 6 button 10
Joystick6Button11 joystick 6 button 11
Joystick6Button12 joystick 6 button 12
Joystick6Button13 joystick 6 button 13
Joystick6Button14 joystick 6 button 14
Joystick6Button15 joystick 6 button 15
Joystick6Button16 joystick 6 button 16
Joystick6Button17 joystick 6 button 17
Joystick6Button18 joystick 6 button 18
Joystick6Button19 joystick 6 button 19
Joystick7Button0 joystick 7 button 0
Joystick7Button1 joystick 7 button 1
Joystick7Button2 joystick 7 button 2
Joystick7Button3 joystick 7 button 3
Joystick7Button4 joystick 7 button 4
Joystick7Button5 joystick 7 button 5
Joystick7Button6 joystick 7 button 6
Joystick7Button7 joystick 7 button 7
Joystick7Button8 joystick 7 button 8
Joystick7Button9 joystick 7 button 9
Joystick7Button10 joystick 7 button 10
Joystick7Button11 joystick 7 button 11
Joystick7Button12 joystick 7 button 12
Joystick7Button13 joystick 7 button 13
Joystick7Button14 joystick 7 button 14
Joystick7Button15 joystick 7 button 15
Joystick7Button16 joystick 7 button 16
Joystick7Button17 joystick 7 button 17
Joystick7Button18 joystick 7 button 18
Joystick7Button19 joystick 7 button 19
Joystick8Button0 joystick 8 button 0
Joystick8Button1 joystick 8 button 1
Joystick8Button2 joystick 8 button 2
Joystick8Button3 joystick 8 button 3
Joystick8Button4 joystick 8 button 4
Joystick8Button5 joystick 8 button 5
Joystick8Button6 joystick 8 button 6
Joystick8Button7 joystick 8 button 7
Joystick8Button8 joystick 8 button 8
Joystick8Button9 joystick 8 button 9
Joystick8Button10 joystick 8 button 10
Joystick8Button11 joystick 8 button 11
Joystick8Button12 joystick 8 button 12
Joystick8Button13 joystick 8 button 13
Joystick8Button14 joystick 8 button 14
Joystick8Button15 joystick 8 button 15
Joystick8Button16 joystick 8 button 16
Joystick8Button17 joystick 8 button 17
Joystick8Button18 joystick 8 button 18
Joystick8Button19 joystick 8 button 19

上記リンク先は今回の変換処理をすべて配列で持つ実装をしたものですが、そこでの定義によると、KeyCodeに定義はなくても名前指定のできるものが存在します。廃止されたとかなんでしょうか。調べてもよくわかりませんでした。

  • world 0world 95
  • compose
  • power
  • euro
  • undo
  • Joystick 9~11系

コメントを残す

Top