kenichiro246’s blog

主にC#での仕事をしてます。今はXamarinに飛び込みハマり中。基本的に作ることが好き。

UIKeyCommandを使ってバーコードリーダーの入力を受け取る(Xamarin版)

BluetoothiOSバイスに接続されているHIDプロファイルのキーボード入力値を取得し、画面に表示させる方法です。
通常は「Bluetooth LE Plugin for Xamarin」などのプラグインなどを使用し、バーコードなどの入力値を取得することになりますが、ここではiOSのUIKeyCommandを利用し、取得する方法を纏めました。
(とはいうものの、「Bluetooth LE Plugin for Xamarin」は全然触れておらず現在勉強中)

本来ならばSPPで値をとるのだろうけど、iOSに限ってはUIKeyCommandのAPIがあるので、これを使用し、キーボードの値を取得してみます。

参考

以下のサイトを元にしています。
細かい用途や考え方などが纏まっており、大変勉強になります。
* UIKeyCommandを使ってバーコードリーダーの入力を受け取る
* UIKeyCommandでバーコードリーダーの入力を受けとる(Swift版)

実装概要

  1. PCL側にバーコードリーダーで取得した際に呼び出されるメソッドを追記する。
  2. iOSプロジェクトにPageRendererを追加する。
  3. PageRendererにてキーボード入力を取得するためのUIKeyCommandを実装する。
  4. キーボード入力を取得後、1で作成したメソッドを呼び出す。

サンプルコード

GitHubに保存しています。
https://github.com/kenichiro246/KeyCommandSample

サンプルコードの実行イメージ

※準備中。(MacBookのOS再インストールが必要になり、イメージ画が作れず・・・)

実装

以下の通り実装することで取得したバーコードの情報を画面に表示できます。

PCL

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="KeyCommandSample.Page1">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness" iOS="0,20,0,0" />
    </ContentPage.Padding>
    <ContentPage.Content>
        <Label
            x:Name="Label1"
            Text="Welcome to Xamarin Forms!" 
            VerticalOptions="Center" 
            HorizontalOptions="Center"
            />
    </ContentPage.Content>
</ContentPage>
namespace KeyCommandSample
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class Page1 : ContentPage
    {
        public Page1()
        {
            InitializeComponent();
        }

        // iOSから呼び出される
        public void SetKeyboardValue(string value)
        {
            Label1.Text = value;
        }
    }
}

iOS

[assembly: ExportRenderer(typeof(KeyCommandSample.Page1), typeof(Page1Renderer))]
namespace KeyCommandSample.iOS
{
    public class Page1Renderer : PageRenderer
    {
        private string _RecvValue = string.Empty;

        public override bool CanBecomeFirstResponder
        {
            get { return true; }
        }

        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);
            string key = string.Empty;
            var selector = new Selector("KeyRecv:");
            for (int i = 0; i <= 127; i++)
            {
                key = ((char)i).ToString();
                UIKeyCommand accelerator1 = UIKeyCommand.Create((NSString)key, 0, selector);
                AddKeyCommand(accelerator1);
                UIKeyCommand acceleratorShift = UIKeyCommand.Create((NSString)key, UIKeyModifierFlags.Shift, selector);
                AddKeyCommand(acceleratorShift);
            }
            UIKeyCommand accelerator2 = UIKeyCommand.Create((NSString)"\n", 0, selector);
            AddKeyCommand(accelerator2);
            UIKeyCommand accelerator3 = UIKeyCommand.Create((NSString)"\r", 0, selector);
            AddKeyCommand(accelerator3);
        }

        [Export("KeyRecv:")]
        public void KeyRecv(UIKeyCommand cmd)
        {
            if (cmd == null)
                return;
            var inputValue = cmd.Input;
            if (inputValue == "\n" || inputValue == "\r")
            {
                SetKeyboardValue(_RecvValue);
                _RecvValue = string.Empty;
            }
            else
            {
                _RecvValue += inputValue;
            }
        }
        public void SetKeyboardValue(string value)
        {
            ((KeyCommandSample.Page1)Element)?.SetKeyboardValue(value);
        }
    }
}

まとめ

今回の作り方では、ページが破棄された時のロジックが未実装であり、そのあたりはもう少し工夫して作りこみたいとは思っています。 また、今回はiOSのみですが、次回はSPPでiOSAndroidも情報を取得できるようにしたいなぁなんて。