Help us understand the problem. What is going on with this article?

キーボードとして動作するコントローラのUnityのNative Pluginを作る

はじめに

良さげなコントローラのUnityのNative Pluginを作りました。

環境

目的

良さげなコントローラがあったので、Unityで使ってみる
持ちやすくて、操作がしやすそうなコントローラがあったので、Unityで使いたいなと思いました。
という訳で、とりあえずBluetooth接続したら、こう↓でした。

という訳で、今回の目的がこちら
良さげなコントローラがあったので、Unityで使ってみる

UnityのiOSアプリで、キーボードを出さずに、キーボードの入力を受け取る

UnityのiOSアプリで、キーボードを出さずに、キーボードの入力を受け取る

試したこと

TouchScreenKeyboard.hideInput

TouchScreenKeyboard.hideInputを使って、キーボードを非表示にしてキー入力を受け取る
→失敗
※類似APIも期待した動作になりませんでした、、、

UIResponder.keyCommands

UIResponder.keyCommandsにUIKeyCommandを使って、キー入力を受け取る。
→成功

コントローラの入力を解析する

input On Press On Release
JoyStick.up w e
JoyStick.Right d c
JoyStick.Down x z
JoyStick.Left a q
Button.A u f
Button.B h r
Button.C y t
Button.D j n
Trigger.Return l v
Trigger.OK o g

→これらの入力を検出し、通知することで、コントローラとして利用できる

UIResponder.keyCommands

UIResponder.keyCommandsを設定する

キー入力を受け取る度に、keyCommandsが探索され、入力の組み合わせと合致するkeyCommandsを設定したUIKeyCommandのactionに通知されます。
mapを使って文字列からUIKeyCommand配列を作っています。

ViewController.swift
    override var keyCommands: [UIKeyCommand]? {
        return "wedcxzaqufhrytjnlvog".map({ (c: Character) -> UIKeyCommand in
            return UIKeyCommand(input: String(c), modifierFlags: [], action: #selector(handlerKeyInput(command:)))
        })
    }

UIResponderのbecomeFirstResponder()を使って、キー入力が自分に来るようにします。

ViewController.swift
    override func viewDidAppear(_ animated: Bool) {
        _ = self.becomeFirstResponder()
    }

UIResponder.keyCommandsをUnityで利用する。

ネイティブプラグインを作ります。

step.1 指定されたキー入力を受け取り、通知するViewControllerを実装する

KeyboarInputDetectorViewController.swift

step.2 作ったViewControllerをUnityのViewのsubViewに追加する

KeyboarInputDetector.swift
        detectorViewController = KeyboarInputDetectorViewController()
        detectorViewController.view.frame = CGRect(x: 0, y: 0, width: 0, height: 0)
        detectorViewController.view.backgroundColor = .clear
        UnityGetGLViewController().view.addSubviewdetectorViewController.view

step.3 swiftのフレームワークを呼び出すネイティブプラグインを実装する

#import <KeyboarInputDetector/KeyboarInputDetector-Swift.h>

typedef void (*OnKeyboarInputHandler) (const char* input);
extern "C" {
    KeyboarInputDetector* keyboarInputDetector_init();
    void keyboarInputDetector_startDetection(KeyboarInputDetector* detector, unsigned char* str);
    void keyboarInputDetector_stopDetection(KeyboarInputDetector* detector);
    void keyboarInputDetector_registerOnKeyboarInput(KeyboarInputDetector* detector, OnKeyboarInputHandler handler);
    void keyboarInputDetector_release(KeyboarInputDetector* detector);
}

KeyboarInputDetector* keyboarInputDetector_init() {
    KeyboarInputDetector* detector = [KeyboarInputDetector alloc];
    CFRetain((CFTypeRef)detector);
    return detector;
}

void keyboarInputDetector_startDetection(KeyboarInputDetector* detector, unsigned char* str) {
    [detector startDetectionWithUnityView: UnityGetGLViewController().view
                                     keys: @"wedcxzaqufhrytjnlvog"];
}

void keyboarInputDetector_stopDetection(KeyboarInputDetector* detector) {
    [detector stopDetection];
}

void keyboarInputDetector_registerOnKeyboarInput(KeyboarInputDetector* detector, OnKeyboarInputHandler handler) {
    [detector onKeyInputWithHandler: ^(NSString* str) {
        handler([str UTF8String]);
    }];
}

step.4 Unityから呼び出す

namespace KeyboarInputDetector
{
    public class KeyboardInputDetectorIOS : IKeyboardInputDetector
    {

        [DllImport("__Internal")]
        private static extern IntPtr keyboarInputDetector_init();

        [DllImport("__Internal")]
        private static extern void keyboarInputDetector_startDetection(IntPtr detector, string str);

        [DllImport("__Internal")]
        private static extern void keyboarInputDetector_stopDetection(IntPtr detector);

        [DllImport("__Internal")]
        private static extern void keyboarInputDetector_registerOnKeyboarInput(IntPtr detector, OnKeyboarInputHandler handler);

        [DllImport("__Internal")]
        private static extern void keyboarInputDetector_release(IntPtr detector);


        private IntPtr detector;

        public KeyboardInputDetectorIOS()
        {
            detector = keyboarInputDetector_init();
        }

        ~KeyboardInputDetectorIOS()
        {
            keyboarInputDetector_release(detector);
        }

        public void StartDetection(string str)
        {
            keyboarInputDetector_startDetection(detector, str);
            keyboarInputDetector_registerOnKeyboarInput(detector, HandlerOnKeyboardInput);
        }

        public void StopDetection()
        {
            keyboarInputDetector_stopDetection(detector);
        }

        public event OnKeyboardInputDelegate OnKeyboardInput
        {
            add { onKeyboardInput += value; }
            remove  { onKeyboardInput -= value; }
        }
        private static event OnKeyboardInputDelegate onKeyboardInput;

        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        private delegate void OnKeyboarInputHandler(string input);

        [MonoPInvokeCallback(typeof(OnKeyboarInputHandler))]
        private static void HandlerOnKeyboardInput(string input)
        {
            if (onKeyboardInput != null)
                onKeyboardInput(input);
        }
    }
}
fuziki
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした