前回に引き続きWiiリモコンの赤外線カメラを用いたマウスの応用プログラミングを行っていきます。
今回は、マウスの座標が反転していた点を改良し、左クリックと右クリックを実装します。
1.Wii赤外線マウスプログラム2
Form1.csに以下の部分を追加する。using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using WiimoteLib; //WimoteLibの宣言 using System.Runtime.InteropServices ; //DllImportを使うための宣言 namespace WiimoteLib_Sample { public partial class Form1 : Form { //DLL読み込み用 [DllImport("user32.dll")] extern static uint SendInput( uint nInputs, INPUT[] pInputs, int cbSize ); //DLL読み込み用 [StructLayout(LayoutKind.Sequential)] struct INPUT { public int type; public MOUSEINPUT mi; } //DLL読み込み用 [StructLayout(LayoutKind.Sequential)] struct MOUSEINPUT { public int dx; public int dy; public int mouseData; public int dwFlags; public int time; public IntPtr dwExtraInfo; } Boolean isADown = false; //Aボタンが押されたか判定フラグ Boolean isBDown = false; //Bボタンが押されたか判定フラグ Wiimote wm = new Wiimote(); //Wiimoteの宣言 System.Drawing.Point ScreenSize; //画面サイズを格納 public Form1() { InitializeComponent(); this.ScreenSize.X = Screen.PrimaryScreen.Bounds.Width; //画面ザイズの横幅を取得 this.ScreenSize.Y = Screen.PrimaryScreen.Bounds.Height; //画面ザイズの立幅を取得 //他スレッドからのコントロール呼び出し許可 Control.CheckForIllegalCrossThreadCalls = false; } //接続ボタンが押されたら private void button1_Click(object sender, EventArgs e) { this.wm.Connect(); //Wiimoteの接続 this.wm.WiimoteChanged += wm_WiimoteChanged; //イベント関数の登録 this.wm.SetReportType(InputReport.IRExtensionAccel, true);//レポートタイプの設定 } //切断ボタンが押されたら private void button2_Click(object sender, EventArgs e) { this.wm.Disconnect(); //Wiimote切断 } //Wiiリモコンの値が変化する度に呼ばれる void wm_WiimoteChanged(object sender, WiimoteChangedEventArgs args){ WiimoteState ws = args.WiimoteState; //WiimoteStateの値を取得 this.DrawForms(ws); //フォーム描写関数へ } //フォーム描写関数 public void DrawForms(WiimoteState ws) { INPUT[] input = new INPUT[1]; //マウスイベントを格納 Graphics g = this.pictureBox1.CreateGraphics(); //グラフィックスを取得 g.Clear(Color.Black); //画面を黒色にクリア //もし赤外線を1つ発見したら if (ws.IRState.IRSensors[0].Found) { //赤色でマーカを描写 g.FillEllipse( Brushes.Red, ws.IRState.IRSensors[0].Position.X * 200 , ws.IRState.IRSensors[0].Position.Y * 200 , 10 , 10 ); //赤外線座標(0.0~1.0)を画面サイズと掛け合わせる int px = (int)(ws.IRState.IRSensors[0].Position.X * this.ScreenSize.X); int py = (int)(ws.IRState.IRSensors[0].Position.Y * this.ScreenSize.Y); //X座標を反転させる px = this.ScreenSize.X - px; //マウスカーソルを指定位置へ移動 System.Windows.Forms.Cursor.Position = new System.Drawing.Point(px, py); } //Aボタン処理 if (ws.ButtonState.A == true) { //もしAボタンが押されたら if (this.isADown == false) { Console.WriteLine("Aおされた"); input[0].mi.dwFlags = 0x0002; //左マウスダウン SendInput(1, input, Marshal.SizeOf(input[0])); //マウスイベントを送信 this.isADown = true; } } else { if (this.isADown == true) { //もしAボタンが押されていて離されたら Console.WriteLine("Aはなされた"); this.isADown = false; input[0].mi.dwFlags = 0x0004; //左マウスアップ SendInput(1, input, Marshal.SizeOf(input[0])); //マウスイベントを送信 } } //Bボタン処理 if (ws.ButtonState.B == true) { //もしBボタンが押されたら if (this.isBDown == false) { Console.WriteLine("Bおされた"); input[0].mi.dwFlags = 0x0008; //右マウスダウン SendInput(1, input, Marshal.SizeOf(input[0])); //マウスイベントを送信 this.isBDown = true; } } else { if (this.isBDown == true) { //もしBボタンが押されていて離されたら Console.WriteLine("Bはなされた"); this.isBDown = false; input[0].mi.dwFlags = 0x0010; //右マウスアップ SendInput(1, input, Marshal.SizeOf(input[0])); //マウスイベントを送信 } } g.Dispose(); //グラフィックスを開放 } } }実行
1.WiiRemoteを接続してください。
2.F5キーを押して実行してください。
3.接続ボタンをクリックしてください。
※もしエラーが発生する場合はWiiRemoteが正しく接続されているか確認してください。
4.WiiリモコンをWiiセンサーバーに向けてください。
赤外線が1つ検出されると図のように赤い点が表示され、マウスカーソルが移動します。赤外線を検出している間にマウスカーソルを動かそうとしても思い通りに動きません。
マウスカーソルの動きが激しすぎる場合は、Wiiとセンサーバーとの距離を2m~3mまで離してください。距離が長いほど安定した動きを行うことができます。
※センサーバーがない場合は、赤外線が発生するもの(太陽、ロウソクの火、テレビのリモコン、携帯電話の赤外線通信 など)に向けてください。
5.WiiリモコンのAボタンBボタンをクリック
WiiリモコンのAボタンで左クリック、Bボタンで右クリックを行います。環境によっては若干マウス動作が遅くなるかと思います。ドラック動作を行う場合は、ゆっくりAボタンを押し続けて行うと良いです。
終了する場合は
終了する場合は、赤外線を検出しないようにすると、マウスの制御が戻ります。切断ボタンを押してから終了させてください。
解説
Wiiリモコンの赤外線カメラの値を取得して、マウスカーソルの座標を制御し、Wiiリモコンのボタン制御をマウス制御として出力しています。
//DLL読み込み用 [DllImport("user32.dll")] extern static uint SendInput( uint nInputs, INPUT[] pInputs, int cbSize ); //DLL読み込み用 [StructLayout(LayoutKind.Sequential)] struct INPUT { public int type; public MOUSEINPUT mi; } //DLL読み込み用 [StructLayout(LayoutKind.Sequential)] struct MOUSEINPUT { public int dx; public int dy; public int mouseData; public int dwFlags; public int time; public IntPtr dwExtraInfo; }マウスの制御を行うために、user32.dllのSendInputを呼び出すための命令です。読み出しにDllimportを用いているのでunsing System.Runtime.InteropServicesを宣言しています。ここでは詳しく説明しませんので各自調べてみてください。
//X座標を反転させる px = this.ScreenSize.X - px;前回のプログラムではX軸に関してはWiiリモコンの動作の反対の動きをしていました。右にWiiリモコンを振ると、マウスカーソルが左に動いたかと思います。画面解像度の幅から赤外線検出位置のX座標を引くことで、反転し、Wiiリモコンの動作と連動することができます。
INPUT[] input = new INPUT[1]; //マウスイベントを格納 input[0].mi.dwFlags = 0x0002; //左マウスダウン SendInput(1, input, Marshal.SizeOf(input[0])); //マウスイベントを送信Wiiリモコンのボタン動作を、マウス動作イベントとして送信しています。input[0].mi.dwFlagsにマウス動作を代入して送信しています。表に各イベントの値を示す。
動作 意味 値 MOUSEEVENTF_MOVE マウスが移動 0x0001 MOUSEEVENTF_LEFTDOWN 左ボタンが押された 0x0002 MOUSEEVENTF_LEFTUP 左ボタンが離された 0x0004 MOUSEEVENTF_RIGHTDOWN 右ボタンが押された 0x0008 MOUSEEVENTF_RIGHTUP 右ボタンが離された 0x0010 MOUSEEVENTF_MIDDLEDOWN 中央ボタンが押された 0x0020 MOUSEEVENTF_MIDDLEUP 中央ボタンが離された 0x0040 MOUSEEVENTF_ABSOLUTE 正規化された絶対座標 0x8000
前回のプログラムと比べるとコード数が長くなりましたが、行っていることは非常に単純です。Wiiリモコンのボタン動作をマウス動作として出力を行っています。マウスのクリック動作を見てみると、ボタンをクリック(DOWN)し、ボタンを離す(UP)。この2つの動作が行われます。この2つの動作を検出し制御を行っています。



