Page 1 of 1

Wiimote Witheboard(Virtual Touch Screen)

Posted: Sat Apr 30, 2011 5:45 pm
by nequito
This is a tutorial that you can connect your wiimote and with a infrared pen used like if your screen
were touch,That with an infrared pen emulate that its a touch screen and the cursor goes where the infrared pen goes because the wiimote locates the cordenades of the infraredpen and sendit by bluetooth to the computer and makes the cursor goes to the location.

you will need:

1)Infrared pen(Bellow i will show you how to do your own)
2)Wiimote controller
3)PC With bluetooth
4)Wiimote Lib Pack(http://www.fileden.com/files/2009/6/29/ ... %20Lib.zip)





How to make your infrared pen
you can Buy it in Radioshack but also you can do it
You will Need
1.Infrared led
2.Push Switch
3.Batery Holder
4.Wire
Here to make your own infra red pen:
Image








How to do the Software

2 forms
Form 1 name =Form1
Form 2 Name = CalibrationForm





First you need in form1:
3 Pictureboxes(1.Calibrate the Ir pen,3.Restart form to search wiimote it have to be at big as the form, 2.Close app)
1 Check box
1 Progressbar
1 Label
Image
Image




Form2:
1 Picturebox (named "pbCalibrate")
Image








Code for Form 1 (This go ON TOP of all Code)
Code: Select all
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;//for firing keyboard and mouse events (optional)
using System.IO;//for saving the reading the calibration data


using WiimoteLib;




Form1 All code
Code: Select all
 //instance of the wii remote
		Wiimote wm = new Wiimote();


        bool cursorControl = false;

        int screenWidth = 1024;//defaults, gets replaced by actual screen size
        int screenHeight = 768;

        int calibrationState = 0;
        float calibrationMargin = .1f;

        CalibrationForm cf = null;

        Warper warper = new Warper();
        float[] srcX = new float[4];
        float[] srcY = new float[4];
        float[] dstX = new float[4];
        float[] dstY = new float[4];

        
        //declare consts for mouse messages
        public const int MOUSEEVENTF_MOVE = 0x01;
        public const int MOUSEEVENTF_LEFTDOWN = 0x02;
        public const int MOUSEEVENTF_LEFTUP = 0x04;
        public const int MOUSEEVENTF_RIGHTDOWN = 0x08;
        public const int MOUSEEVENTF_RIGHTUP = 0x10;
        public const int MOUSEEVENTF_MIDDLEDOWN = 0x20;
        public const int MOUSEEVENTF_MIDDLEUP = 0x40;
        public const int MOUSEEVENTF_ABSOLUTE = 0x8000;

        //declare consts for key scan codes
        public const byte VK_TAB = 0x09;
        public const byte VK_MENU = 0x12; // VK_MENU is Microsoft talk for the ALT key

        public const byte VK_LEFT  =0x25;
        public const byte VK_UP 	=0x26;
        public const byte VK_RIGHT 	=0x27;
        public const byte VK_DOWN 	=0x28;
        public const int KEYEVENTF_EXTENDEDKEY = 0x01;
        public const int KEYEVENTF_KEYUP = 0x02;

        //for firing mouse and keyboard events

        //imports mouse_event function from user32.dll

        [DllImport("user32.dll")]
        private static extern void mouse_event(
        long dwFlags, // motion and click options
        long dx, // horizontal position or change
        long dy, // vertical position or change
        long dwData, // wheel movement
        long dwExtraInfo // application-defined information
        );


        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetCursorPos(int X, int Y);

        //imports keybd_event function from user32.dll
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern void keybd_event(byte bVk, byte bScan, long dwFlags, long dwExtraInfo);
        WiimoteState lastWiiState = new WiimoteState();//helps with event firing

        //end keyboard and mouse input emulation variables----------------------------------------

        Mutex mut = new Mutex();

		public Form1()
		{
            screenWidth = Screen.GetBounds(this).Width;
            screenHeight = Screen.GetBounds(this).Height;
            InitializeComponent();
		}

		private void Form1_Load(object sender, EventArgs e)
		{
            //add event listeners to changes in the wiiremote
            //fired for every input report - usually 100 times per second if acclerometer is enabled
			wm.OnWiimoteChanged += new WiimoteChangedEventHandler(wm_OnWiimoteChanged); 
            //fired when the extension is attached on unplugged
			wm.OnWiimoteExtensionChanged += new WiimoteExtensionChanged(wm_OnWiimoteExtensionChanged);
            pictureBox2.Hide();
            
            try
            {
                //connect to wii remote
                wm.Connect();

                //set what features you want to enable for the remote, look at Wiimote.InputReport for options
                wm.SetReportType(Wiimote.InputReport.IRAccel, true);
                
                //read the battery
                wm.GetBatteryLevel();

                
                //set wiiremote LEDs with this enumerated ID
                int count = wm.GetNumConnectRemotes();
                switch (count)
                {
                    case 1:
                        wm.SetLEDs(true, false, false, false);
                        break;
                    case 2:
                        wm.SetLEDs(false, true, false, false);
                        break;
                    case 3:
                        wm.SetLEDs(false, false, true, false);
                        break;
                    case 4:
                        wm.SetLEDs(false, false, false, true);
                        break;
                    case 5:
                        wm.SetLEDs(true, false, false, true);
                        break;
                    case 6:
                        wm.SetLEDs(false, true, false, true);
                        break;
                    case 7:
                        wm.SetLEDs(false, false, true, true);
                        break;
                    case 8:
                        wm.SetLEDs(true, false, true, true);
                        break;
                    case 9:
                        wm.SetLEDs(false, true, true, true);
                        break;
                    case 10:
                        wm.SetLEDs(true, true, true, true);
                        break;
                    default:
                        wm.SetLEDs(false, false, false, false);
                        break;
                }
            }
            catch (Exception x)
            {
                MessageBox.Show("Exception: " + x.Message);


                pictureBox2.Show();


            }
            loadCalibrationData();
		}

		void wm_OnWiimoteExtensionChanged(object sender, WiimoteExtensionChangedEventArgs args)
		{

            //if extension attached, enable it
			if(args.Inserted)
				wm.SetReportType(Wiimote.InputReport.IRExtensionAccel, true);
			else
				wm.SetReportType(Wiimote.InputReport.IRAccel, true);
		}

		void wm_OnWiimoteChanged(object sender, WiimoteChangedEventArgs args)
		{
            mut.WaitOne();

            //extract the wiimote state
            WiimoteState ws = args.WiimoteState;

            if (ws.IRState.Found1)//move cursor
            {
                int x = ws.IRState.RawX1;
                int y = ws.IRState.RawY1;
                float warpedX = x;
                float warpedY = y;
                warper.warp(x, y, ref warpedX, ref warpedY);
                if ((x != lastWiiState.IRState.RawX1) || (y != lastWiiState.IRState.RawY1))
                {
//                        Cursor.Position = new Point((int)warpedX, (int)warpedY);
//                        mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, 64*x, 64*y, 0, 0);
                    if (cursorControl)
                            SetCursorPos((int)warpedX, (int)warpedY);
                }
                if (!lastWiiState.IRState.Found1)
                {//mouse down
                    lastWiiState.IRState.Found1 = ws.IRState.Found1;
                    //need to wait for the cursor move event to be processed before doing mouse down
                    //it would be better to insert it properly in the event queue,but i couldn't get it working right
                    Thread.Sleep(25);

                    if (cursorControl)
                        mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
                    switch (calibrationState)
                    {
                        case 1:
                            srcX[calibrationState - 1] = x;
                            srcY[calibrationState - 1] = y;
                            calibrationState = 2;
                            doCalibration();
                            break;
                        case 2:
                            srcX[calibrationState - 1] = x;
                            srcY[calibrationState - 1] = y;
                            calibrationState = 3;
                            doCalibration();
                            break;
                        case 3:
                            srcX[calibrationState - 1] = x;
                            srcY[calibrationState - 1] = y;
                            calibrationState = 4;
                            doCalibration();
                            break;
                        case 4:
                            srcX[calibrationState - 1] = x;
                            srcY[calibrationState - 1] = y;
                            calibrationState = 5;
                            doCalibration();
                            break;
                        default:
                            break;
                    }
                }
            }
            else
            {
                if (lastWiiState.IRState.Found1)//mouse up
                {
                    lastWiiState.IRState.Found1 = ws.IRState.Found1;
                    if (cursorControl)
                        mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
                }
            }


            if (!lastWiiState.ButtonState.A && ws.ButtonState.A)
            {
                BeginInvoke((MethodInvoker)delegate() { btnCalibrate.PerformClick(); });
            }
            lastWiiState.ButtonState.A = ws.ButtonState.A;

            if (!lastWiiState.ButtonState.Up && ws.ButtonState.Up)
                keybd_event(VK_UP, 0x45, 0, 0);
            if (lastWiiState.ButtonState.Up && !ws.ButtonState.Up)
                keybd_event(VK_UP, 0x45, KEYEVENTF_KEYUP, 0);
            lastWiiState.ButtonState.Up = ws.ButtonState.Up;

            if (!lastWiiState.ButtonState.Down && ws.ButtonState.Down)
                keybd_event(VK_DOWN, 0x45, 0, 0);
            if (lastWiiState.ButtonState.Down && !ws.ButtonState.Down)
                keybd_event(VK_DOWN, 0x45, KEYEVENTF_KEYUP, 0);
            lastWiiState.ButtonState.Down = ws.ButtonState.Down;

            if (!lastWiiState.ButtonState.Left && ws.ButtonState.Left)
                keybd_event(VK_LEFT, 0x45, 0, 0);
            if (lastWiiState.ButtonState.Left && !ws.ButtonState.Left)
                keybd_event(VK_LEFT, 0x45, KEYEVENTF_KEYUP, 0);
            lastWiiState.ButtonState.Left = ws.ButtonState.Left;

            if (!lastWiiState.ButtonState.Right && ws.ButtonState.Right)
                keybd_event(VK_RIGHT, 0x45, 0, 0);
            if (lastWiiState.ButtonState.Right && !ws.ButtonState.Right)
                keybd_event(VK_RIGHT, 0x45, KEYEVENTF_KEYUP, 0);
            lastWiiState.ButtonState.Right = ws.ButtonState.Right;


            lastWiiState.IRState.Found1 = ws.IRState.Found1;
            lastWiiState.IRState.RawX1 = ws.IRState.RawX1;
            lastWiiState.IRState.RawY1 = ws.IRState.RawY1;
            lastWiiState.IRState.Found2 = ws.IRState.Found2;
            lastWiiState.IRState.RawX2 = ws.IRState.RawX2;
            lastWiiState.IRState.RawY2 = ws.IRState.RawY2;
            lastWiiState.IRState.Found3 = ws.IRState.Found3;
            lastWiiState.IRState.RawX3 = ws.IRState.RawX3;
            lastWiiState.IRState.RawY3 = ws.IRState.RawY3;
            lastWiiState.IRState.Found4 = ws.IRState.Found4;
            lastWiiState.IRState.RawX4 = ws.IRState.RawX4;
            lastWiiState.IRState.RawY4 = ws.IRState.RawY4;


            //draw battery value on GUI
            BeginInvoke((MethodInvoker)delegate() { pbBattery.Value = (ws.Battery > 0xc8 ? 0xc8 : (int)ws.Battery); });
            float f = (((100.0f * 48.0f * (float)(ws.Battery / 48.0f))) / 192.0f);
            BeginInvoke((MethodInvoker)delegate() { lblBattery.Text = f.ToString("F"); });

            //check the GUI check boxes if the IR dots are visible
            String irstatus = "Visible IR dots: ";
            if (ws.IRState.Found1)
                irstatus += "1 ";
            if (ws.IRState.Found2)
                irstatus += "2 ";
            if (ws.IRState.Found3)
                irstatus += "3 ";
            if (ws.IRState.Found4)
                irstatus += "4 ";

            BeginInvoke((MethodInvoker)delegate() { lblIRvisible.Text = irstatus; });

            mut.ReleaseMutex();        
        }


        public void loadCalibrationData()
        {
            // create reader & open file
            try
            {
                TextReader tr = new StreamReader("calibration.dat");
                for (int i = 0; i < 4; i++)
                {
                    srcX[i] = float.Parse(tr.ReadLine());
                    srcY[i] = float.Parse(tr.ReadLine());
                }

                // close the stream
                tr.Close();
            }
            catch (System.IO.FileNotFoundException)
            {
                //no prexsting calibration
                return;
            }

            warper.setDestination(  screenWidth * calibrationMargin,
                                    screenHeight * calibrationMargin,
                                    screenWidth * (1.0f-calibrationMargin),
                                    screenHeight * calibrationMargin,
                                    screenWidth * calibrationMargin,
                                    screenHeight * (1.0f - calibrationMargin),
                                    screenWidth * (1.0f - calibrationMargin),
                                    screenHeight * (1.0f - calibrationMargin));
            warper.setSource(srcX[0], srcY[0], srcX[1], srcY[1], srcX[2], srcY[2], srcX[3], srcY[3]);

            warper.computeWarp();
            cursorControl = true;
            BeginInvoke((MethodInvoker)delegate() { cbCursorControl.Checked = cursorControl; });

        }

        public void saveCalibrationData()
        {
            TextWriter tw = new StreamWriter("calibration.dat");

            // write a line of text to the file
            for (int i = 0; i < 4; i++)
            {
                tw.WriteLine(srcX[i]);
                tw.WriteLine(srcY[i]);
            }
            // close the stream
            tw.Close();
        }

        public void doCalibration(){
            if (cf == null)
                return;
            int x = 0;
            int y = 0;
            int size = 25;
            Pen p = new Pen(Color.Red);
            switch (calibrationState)
            {
                case 1:
                    x = (int)(screenWidth * calibrationMargin);
                    y = (int)(screenHeight * calibrationMargin);
                    cf.showCalibration(x, y, size, p);
                    dstX[calibrationState - 1] = x;
                    dstY[calibrationState - 1] = y;
                    break;
                case 2:
                    x = screenWidth - (int)(screenWidth * calibrationMargin);
                    y = (int)(screenHeight * calibrationMargin);
                    cf.showCalibration(x, y, size, p);
                    dstX[calibrationState - 1] = x;
                    dstY[calibrationState - 1] = y;
                    break;
                case 3:
                    x = (int)(screenWidth * calibrationMargin);
                    y = screenHeight -(int)(screenHeight * calibrationMargin);
                    cf.showCalibration(x, y, size, p);
                    dstX[calibrationState - 1] = x;
                    dstY[calibrationState - 1] = y;
                    break;
                case 4:
                    x = screenWidth - (int)(screenWidth * calibrationMargin);
                    y = screenHeight -(int)(screenHeight * calibrationMargin);
                    cf.showCalibration(x, y, size, p);
                    dstX[calibrationState - 1] = x;
                    dstY[calibrationState - 1] = y;
                    break;
                case 5:
                    //compute warp
                    warper.setDestination(dstX[0], dstY[0], dstX[1], dstY[1], dstX[2], dstY[2], dstX[3], dstY[3]);
                    warper.setSource(srcX[0], srcY[0], srcX[1], srcY[1], srcX[2], srcY[2], srcX[3], srcY[3]);
                    warper.computeWarp();
                    cf.Dispose();
                    cf = null;
                    calibrationState = 0;
                    cursorControl = true;
                    BeginInvoke((MethodInvoker)delegate() { cbCursorControl.Checked = cursorControl; });
                    saveCalibrationData();
                    break;
                default:
                    break;
            }

        }

		private void Form1_FormClosed(object sender, FormClosedEventArgs e)
		{
            //disconnect the wiimote
			wm.Disconnect();
		}

       

        private void cbCursorControl_CheckedChanged(object sender, EventArgs e)
        {
            cursorControl = cbCursorControl.Checked;
        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {
            if (cf == null)
            {
                cf = new CalibrationForm();
                cf.Show();
            }
            if (cf.IsDisposed)
            {
                cf = new CalibrationForm();
                cf.Show();
            }
            calibrationState = 1;
            doCalibration();
        }

        private void cb_CheckedChanged(object sender, EventArgs e)
        {
            cursorControl = cbCursorControl.Checked;
        }

        private void pictureBox2_Click(object sender, EventArgs e)
        {
            Application.Restart();

        }

        private void pictureBox3_Click(object sender, EventArgs e)
        {
            this.Close();
        }
	}
}







Code of Form2(Calibrationform(This Go ON THE TOP of the code))
Code: Select all
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;



Form 2 (Calibrationform) All code
Code: Select all
 Bitmap bCalibration;
        Graphics gCalibration;

        int screenWidth = 1024;//defaults
        int screenHeight = 768;
        
        public CalibrationForm()
        {
            Rectangle rect = new Rectangle();
            rect = Screen.GetWorkingArea(this);

            InitializeComponent();
            this.FormBorderStyle = FormBorderStyle.None;
            this.Left = 0;
            this.Top = 0;
            this.Size = new Size(rect.Width, rect.Height);
            this.Text = "Calibration - Working area:" + Screen.GetWorkingArea(this).ToString() + " || Real area: " + Screen.GetBounds(this).ToString();

            this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.OnKeyPress);

            
            screenHeight = rect.Height;
            screenWidth = rect.Width;

            bCalibration = new Bitmap(screenWidth, screenHeight, PixelFormat.Format24bppRgb);
            gCalibration = Graphics.FromImage(bCalibration);
            pbCalibrate.Left = 0;
            pbCalibrate.Top = 0;
            pbCalibrate.Size = new Size(rect.Width, rect.Height);
            
            gCalibration.Clear(Color.White);

            BeginInvoke((MethodInvoker)delegate() { pbCalibrate.Image = bCalibration; });
        }

        private void OnKeyPress(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            if ((int)(byte)e.KeyCode == (int)Keys.Escape)
            {
                this.Dispose(); // Esc was pressed
                return;
            }
        }

        public void drawCrosshair(int x, int y, int size, Pen p, Graphics g){
            g.DrawEllipse(p, x - size / 2, y - size / 2, size, size);
            g.DrawLine(p, x-size, y, x+size, y);
            g.DrawLine(p, x, y-size, x, y+size);
        }

        public void showCalibration(int x, int y, int size, Pen p){
            gCalibration.Clear(Color.White);
            drawCrosshair(x,y,size, p, gCalibration);
            BeginInvoke((MethodInvoker)delegate() { pbCalibrate.Image = bCalibration; });

        }

        private void CalibrationForm_Load(object sender, EventArgs e)
        {

        }
    }
}


Here I let you The EXE

This file is hosted off-site.


Here I let you the Source Code

This file is hosted off-site.

Re: Wiimote Witheboard(Virtual Touch Screen)

Posted: Sat Apr 30, 2011 5:48 pm
by nequito
In a few houers I will Upload A video So you can see how it works

Re: Wiimote Witheboard(Virtual Touch Screen)

Posted: Sat Apr 30, 2011 6:15 pm
by mandai
You can get most of that source code here: http://cwiimote.googlecode.com/svn/!svn ... imoteTest/

Also what wavelength does the IR diode have to be at?

Re: Wiimote Witheboard(Virtual Touch Screen)

Posted: Sat Apr 30, 2011 6:23 pm
by Napster1488
Awesome!

Re: Wiimote Witheboard(Virtual Touch Screen)

Posted: Sat Apr 30, 2011 8:59 pm
by Cheatmasterbw
Nicely done! My class needed to make the IR pens for a project in school last year.

And mandai, i think any wavelength works, as long as it is IR

Re: Wiimote Witheboard(Virtual Touch Screen)

Posted: Sat Apr 30, 2011 9:19 pm
by nequito
Yes it any wavelength works i have tested with 3 of them but the best is the IR383