PowerPointでLeap Motionを使ってみる

VSTO
スポンサーリンク

PowerPointのアドインを開発する方法を書きました

VSTOでのPowerPointアドイン開発手順
パワポでのVSTOアドイン開発 VSTOでPowerPointアドインを開発していく方法を見ていきます。基本は、以前に示したようなOutlook, Excelと変わりません。 今回はリボンのボタンから、UserCon...

そこで、プロジェクト名等でわかった方もおられるかと思いますが、現在VSTO(Word, Excel, Outlook)上でLeap Motionを使ってみるテストをおこなっています。で、ちょっとショックことがわかったので、先に書いておきます。

スポンサーリンク

LeapMotionでショックだったこと

Gestureが使えない!!!
Gestureが使えない!!!
Gestureが使えない!!!
Toolも使えない!!!

そうです、PowerPointアドインとかだからではく、デフォルトで使用できなくなってるんです。Leap公式ページより。

Notice Gestures are deprecated in version 3.0 and may not behave the same as they did in earlier versions.

Gesture(ジェスチャー)はver 3.0から廃止される可能性があり、以前バージョンと同様にはふるまわないかもしれません。(意訳)

Tools are deprecated in version 3.0.

(Toolのページ)

Tool(ツール)はver 3.0から廃止される。(意訳)

オイ、まじか。。。deprecated = “廃止される”だけは勉強になりました。

すみません、取り乱しました。記事にまとめるために、ゴリゴリとサンプルコードを弄っていて、Gestureが反応しないなぁ、と思っていたんです。Toolも反応しないけど、コードの書き方が悪いのかなぁと思っていたんです。公式のサンプルでも動かないので、いろいろと調べて、2日分程度工数を無駄にしました。ふて寝して、起きて公式をよく見たらそんなこと書いてるし。Build InsiderさんのC# Leap関連記事とかその他の記事だけを見て、公式を注意深く見てなかったのが良くなかった。。公式をよく見ろが正解ですね。
思うに、Gesture,Toolsの機能としての反応が良くなかったのか、Gesture,Tools自体があまり使われてなかったのか。

気をとりなおして

C#, Leap Motionを使用する方法を少しずつ、追っていきます。ここではPowerPointアドインで使えるようにしていきたいと思います。
その他、参考にさせてもらったきじとしましては、先ほど挙げさせていただいた、Build InsiderさんのC# Leap関連記事とかが、参考になります。

Leap motion SDKのダウンロード

開発を始める前にLeapとデバイスドライバー等はインストールしておいてください。

  1. Leap Developerのページから, V2 Desktop SDKのページへ移動。(Win10ユーザはOrion v4 SDK使ってってなってるけど、スルー。)
  2. Leap Motion SDK v2.3.1をクリック
  3. アカウントを登録して、ダウンロードしてください。
  4. .zipを開いてください。
  5. このなかのSample.csと、libフォルダにあるLeap.dll,LeapCSharp.dll,LeapCSharp.NET4.0.dllを使いまわしていきます。
  6. Sample.csと、Leap.dll,LeapCSharp.dll,LeapCSharp.NET4.0.dllだけで、よく参考として作られているコマンドラインのサンプルも作成できるので、先にすすむ前に作ってみても良いかもしれません。(よく見るサンプル画面です。ただし見にくい。。)

組み込んでみる

VSTOでのPowerPointアドイン開発手順
パワポでのVSTOアドイン開発 VSTOでPowerPointアドインを開発していく方法を見ていきます。基本は、以前に示したようなOutlook, Excelと変わりません。 今回はリボンのボタンから、UserCon...

の中にくみこんで、行ってみたいと思います。

UserControlへの組み込み

UserControlの中を以下のサンプルのように書き加えてください。コード上のコメントで説明を追加しています。①~⑬を参照して下さい。


//① usingへの追加と参照へのLeapSharp.Net4.0を忘れずに
using Leap;


 public partial class UserControl_LeapTest : UserControl
 {
     //② リスナーとコントローラの追加
     SampleListener listener;
     Controller controller;

     //③ lisnerからデータを取り出すために追加します。
     FrameData _frameData = new FrameData();

     public UserControl_LeapTest()
     {
         InitializeComponent();

         //④初期化時点でリスナ追加
         listener = new SampleListener(_frameData);
         listener.SetTextBox(textBox1);
         controller = new Controller();

         // Have the sample listener receive events from the controller
         controller.AddListener(listener);

     }

     private void UserControl_LeapTest_Load(object sender, EventArgs e)
     {
         //⑤ timer1はツールボックスからUserContorlのデザイナ上で追加しておいてください。 
         timer1.Interval = 20;
         timer1.Start();
     }

     // ⑥ThisAddin側から終了させるために、追加しておきます。
     public void FinalizingLeap()
     {
         timer1.Stop();

         controller.RemoveListener(listener);
         controller.Dispose();

         listener = null;
         
     }

     //⑦ 後ほど出てきますが、SafeWriteLine()で表示するものは見にくいので、追加しました。
     private void timer1_Tick(object sender, EventArgs e)
     {
         if (controller.IsConnected)
         {

             label1.Text = "Id:" + _frameData.Id.ToString("D10")
                           + " TimeStamp:" + _frameData.Timestamp.ToString("D15")
                           + " HandsCount:" + _frameData.handsCount.ToString("D2");
         }
         else
         {
             label1.Text = "controller is not connected.";
         }
     }

 }

//⑦データを取り出すためのクラス
 public class FrameData
 {
     public long Timestamp { get; set; }
     public long Id { get; set;}
     public long handsCount { get; set;}
 }

//⑧ Sample.csにいろいろと追加しています。
public class SampleListener : Listener
 {
     private Object thisLock = new Object();

     //⑨ 追加-1 データを取り出すためのクラスとコンストラクタ追加
     FrameData _frameData;

     public SampleListener(FrameData frameData)
     {
         _frameData = frameData;
     }

     //⑩ SafeWriteLine()を上書きしてください。
     private void SafeWriteLine(String line)
     {
         lock (thisLock)
         {
             if (_tbx == null) return;

             // コントロールが破棄されているならば、何もしない
             if (_tbx.IsDisposed) return;

             // 呼び出し元のコントロールのスレッドと異なるかを確認する
             if (_tbx.InvokeRequired)
             {
                 _tbx.BeginInvoke(new SetTextCallback(SetText), _tbx, line);
             }
             else
             {
                 // コントロールを直接呼び出す
                 _tbx.Text = line;
             }

         }
     }

     //⑪ 追加-2 SafeWriteLine()をスレッドセーフに書き込むための関数群とデリゲート
     delegate void SetTextCallback2(TextBox textBox);

     private void SetText(TextBox textBox)
     {
         textBox.Clear();
     }


     delegate void SetTextCallback(TextBox textBox, string text);

     private void SetText(TextBox textBox, string text)
     {
         textBox.Text = text;
     }

     private TextBox _tbx;

     public void SetTextBox(TextBox tbx)
     {
         _tbx = tbx;
     }

     public override void OnInit(Controller controller)
     {
         SafeWriteLine("Initialized");
     }

     public override void OnConnect(Controller controller)
     {
         SafeWriteLine("Connected");
     }

     public override void OnDisconnect(Controller controller)
     {
         //Note: not dispatched when running in a debugger.
         SafeWriteLine("Disconnected");
     }

     public override void OnExit(Controller controller)
     {
         SafeWriteLine("Exited");
     }

     public override void OnFrame(Controller controller)
     {
         // Get the most recent frame and report some basic information
         Frame frame = controller.Frame();

         SafeWriteLine("Frame id: " + frame.Id
                     + ", timestamp: " + frame.Timestamp
                     + ", hands: " + frame.Hands.Count
                     + ", fingers: " + frame.Fingers.Count
                     + ", tools: " + frame.Tools.Count
                     + ", gestures: " + frame.Gestures().Count);

         //⑬ 追加-3 内部からデータを取り出すために、以下のように追加します。
         lock (thisLock)
         {
             try
             {
                 if (_frameData != null)
                 {

                     _frameData.Id = frame.Id;
                     _frameData.Timestamp = frame.Timestamp;

                     if (frame.Hands != null)
                     {
                         _frameData.handsCount = frame.Hands.Count;
                     }
                     else
                     {
                         _frameData.handsCount = 0;
                     }
                 }
             }
             catch (Exception ex)
             {
                 string str = ex.ToString();
             }
         }

         if (!frame.Hands.IsEmpty || !frame.Gestures().IsEmpty)
         {
             SafeWriteLine("");
         }
     }
 }

UserControlのデザインへの組み込み

上から”textBox1”, “label1”, “timer1″をツールボックスから追加してください。

ThisAddinへの組み込み

⑭でも書いていますが、この関数を呼び出さないと、コントローラ等の解放がうまくいかない可能性があります。


public Microsoft.Office.Tools.CustomTaskPane myPane;

public UserControl_LeapTest myLeapControl = null;

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
    myLeapControl = new UserControl_LeapTest();

    myPane = this.CustomTaskPanes.Add(myLeapControl, "Leap Motion Test");
}

public void ShowPanel()
{
    myPane.Visible = true;
    myPane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionBottom;
    myPane.Height = 450;
}


private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
    //⑭ 先ほど追加した関数をここで呼び出します。こうしておかないと解放がうまくいかない可能性があります。
    myLeapControl.FinalizingLeap();
}

結果

以下のようになります。
起動で、Connectがうまくいかなかったり、解放がどこかでうまくいってないのか、何度か立ち上げなおさなかったりいけなかったりと、まだもう少し工夫が必要みたいです。

まとめて

  • v2からGesture,Toolが使えない
  • PowerPoint等のAddinから使えなくもないが、もう少し工夫が必要。
  • 公式の解説・仕様を読むこと
  • v4のSDK(C++)の使用も考えたほうがよいのかもしれない。
タイトルとURLをコピーしました