Kinectをマウス、キーボード、タッチの変わりに使う - その1

Kinectをマウスやキーボード、タッチの変わりに使う方法の1番目を紹介します。多分これが一番正統なんだろうなぁ…

https://msdn.microsoft.com/ja-jp/library/ff708696.aspx のページで解説してあるとおり、WPFやSliverlightのアプリケーションも含めて、全て、”ウィンドウ”でできている事は皆さんご存知ですよね?さらに、Windows OSが管理するメッセージキューを介して、キーボードの情報を取得している事も。だから、あるアプリケーションにキーボード入力(簡単の為カーソルキーとエンターキーだけを考える)をしたかったら、そのアプリケーションのウィンドウハンドルを取得して、そのウィンドウに「キーボード入力されたよ」というメッセージを送ればよいのです。

Kinectで(例えば右手の)座標をウォッチして、上下左右の動きを検出(実は結構難しいけど)し、それをアプリケーションに送るという流れになります。
VC++ Nativeコードの場合は、PostMessage()関数で、WM_KEYDOWN、WM_KEYUPを送信、その際にどのキーが押されたかを示すためにVK_RETURNとかVK_UP、VK_RIGHTとかを引数で渡せばそれでOK。Windowの取得は、EnumWindow()関数をコールすれば、取得できます。

C#などのManagedの場合は、PostMessageやEnumWindowをCOM Interop機能を使ってコールすれば使うことができるので、それを使ってください。ちなみに、以下の様な感じでC#のクラスの中で定義すればWin32 APIは簡単にC#コードから利用できます。

         [DllImport("user32.dll")]
        private static extern int GetWindowText(int hWnd, StringBuilder title, int size);
        [DllImport("user32.dll")]
        private static extern int EnumWindows(EnumWindowsProc enumWindowsProc, int lParam);
        [DllImport("user32.dll")]
        private static extern bool IsWindowVisible(int hWnd);
        [DllImport("user32.dll", SetLastError = true)]
        static extern uint GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);

他には、マウスやキーボードはWindows Vistaからは、UMDF(User Mode Driver Framework)に従ったHIDというクラスのユーザーモードのデバイスドライバーがあれば、マウスやキーボードをKinectでエミュレートすれば普通に使える(それが使いや水かどうかは別としてw)はずです。パワーユーザーの方は、https://msdn.microsoft.com/ja-jp/library/ff560456(v=VS.85).aspx を参考にトライしてみてくださいまし。ちなみに、ユーザーモードのドライバーはカーネルモードのドライバーとは異なり、通常のアプリと同様、ネットワークやプロセス、ファイルなどを操作するAPIが利用できるので、論理センサーを作る場合にも大活躍です。

ただ一点、Kinectをマウスやキーボードで置き換えるには非常に難しいハードルがあります。それは、Kinectが人(例えば右手)の座標を常に取得し続けている点にあります。マウスなら動かして手を離してしまえば、同じ場所に留まっていますが、Kinectは人が例えば右に手を動かしたら右に、動かし終えた右手を左に自然に戻したらそれも通知してきてしまうのですね。マウスの動きでいえば、折角右に動いたのに、その後直ぐ左に戻ってしまう。PCは人間の意図には鈍感なので、ここを何とか工夫する、というのが、一番の課題になるわけです。多分色んな方法があると思うので、皆さんも考えてみてください。

次のポストでは、その解決策のアイデアを一つ説明します。