Click here to Skip to main content
15,891,033 members
Articles / Programming Languages / C#
Tip/Trick

Using Laptop Webcam as a Touch Button

Rate me:
Please Sign up or sign in to vote.
4.60/5 (4 votes)
12 Jul 2014GPL36 min read 17.5K   1.5K   7   6
Now it's time to change the usage scope of your laptop Webcam

Screenshot

Introduction

We have a keyboard which has many function keys which let us perform different functions but what if we can add an extra button for a dedicated action but we cannot change, alter or modify our keyboard but we have a different and more interesting idea to implement we can make use of webcam!

Normally a webcam is used for chatting or just capturing photos but now it will not be limited to this scope. In this build, many features are added to customize the user needs. Of course, further improvements can be made and changes are welcome.

This idea has been developed using the sample program provided for the developers to understand the working and usage of Aforge.Net library so basically it was a sample and I modified it to perform a totally different thing.

Application Specifications

This application can perform different actions when you will touch the cam as it simulates the behaviour of pressing a button on keyboard. The features are as follows:

  • Informs you have touched the cam (for debugging only)
  • Can close any active window (simulates the working or Red cross button on top right)
  • Can start a program, song or any other file you specified on touch
  • Can navigate to a web address specified by you
  • Can block your mouse and keyboard (keyboard will not work cursor will not move)

Background

Basic knowledge is not enough. I assume you know how to create a project, what are GUI components and how to use and refer .dll files in your project. The SDK of Aforge.Net has been used. You can download it from http://www.aforgenet.com/framework/downloads.html. It is used for capturing the stream from camera. Obviously, you can use other SDKs if you know how to use it!

Using the Code

We need to add the following .dll files in our project from the Aforge.Net SDK to capture stream.

  • Aforge.Controls.dll
  • Aforge.dll
  • Aforge.Math.dll
  • Aforge.Imaging.dll
  • Aforge.Video.dll
  • Aforge.Video.Directshow.dll

and the following imports in our form:

using AForge.Video;
using AForge.Video.DirectShow;

We will start from the privileges code because some actions in this project will only work if we give them admin privileges, so it is mess that each time we will right click on app and click on run as admin we will put a code for it so it will automatically demand privileges from user.

This code should be kept in form load event to perform a check for privileges.

C#
if (!IsAdmin())
            {
                MessageBox.Show("Application has no Privileges some Feature may not work!",
                "Warning", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                DialogResult rs = MessageBox.Show("Do you want to Restart in admin mode?",
                "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (rs.Equals(DialogResult.Yes))
                {
                    RestartElevated();
                }
            }

Now there are two methods used; the first is checking whether we have admin privileges. If not, then it warns the user that he should restart under admin privileges and if user presses yes, then the method which is our 2nd one is responsible for restarting under admin mode! The code for both methods are given below.

Following is the code for checking the privileges!

public static bool IsAdmin()
        {
            WindowsIdentity id = WindowsIdentity.GetCurrent();
            WindowsPrincipal p = new WindowsPrincipal(id);
            return p.IsInRole(WindowsBuiltInRole.Administrator);
        }

Following is the method body for restarting the application under admin mode!

public void RestartElevated()
        {
            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.UseShellExecute = true;
            startInfo.CreateNoWindow = true;
            startInfo.WorkingDirectory = Environment.CurrentDirectory;
            startInfo.FileName = System.Windows.Forms.Application.ExecutablePath;
            startInfo.Verb = "runas";
            try
            {
                Process p = Process.Start(startInfo);
            }
            catch
            {

            }

            System.Windows.Forms.Application.Exit();
      }

Now the next step is to gather the list of all capturing devices such as cams present in the laptop or your machine. This code can be placed in form load event as well as after the Initialization method in form constructor! It is the following!

FilterInfoCollection videoDevices;

videoDevices = new FilterInfoCollection( FilterCategory.VideoInputDevice );

if ( videoDevices.Count == 0 )
                {
                    throw new Exception( );
                }

                for ( int i = 1, n = videoDevices.Count; i <= n; i++ )
                {
                    string cameraName = i + " : " + videoDevices[i - 1].Name;
                    camera1Combo.Items.Add( cameraName );
                }

                camera1Combo.SelectedIndex = 0;
            }
            catch
            {
                startButton.Enabled = false;
                camera1Combo.Items.Add( "No cameras found" );
                camera1Combo.SelectedIndex = 0;
                camera1Combo.Enabled = false;
            }

Now, if there is 1 or more than one camera, they will come up into the list and if not we will inform user that no camera is found.

In case user has selected a cam to start the stream, the code for doing this is the following!

private void StartCamera( )
        {
            VideoCaptureDevice videoSource1 = new VideoCaptureDevice
        ( videoDevices[camera1Combo.SelectedIndex].MonikerString );
            videoSource1.DesiredFrameRate = 30;
            videoSourcePlayer1.VideoSource = videoSource1;
            videoSourcePlayer1.Start( );
            this.button1.Enabled = true;
            this.stopButton.Enabled = true;
            this.comboBox1.Enabled = true;
        }

And similarly to stop the same stream when user presses the stop button, it is following!

private void StopCamera( )
        {
            videoSourcePlayer1.SignalToStop();
            videoSourcePlayer1.Stop();
            this.button1.Enabled = false;
            this.stopButton.Enabled = false;
            this.comboBox1.Enabled = false;
        }

Now we have a camera that has been started by user. Now what next? There are two more things. Now first we need to choose the option that what happens when we will touch the cam. Second, we will start monitoring the cam to detect whether user has touched it or not and if yes, then perform the selected option. The list of actions should be loaded in combobox via form load event and the code is as follows:

this.comboBox1.Items.Add("Test Touch Cam 1.3");
this.comboBox1.Items.Add("Start a Program");
this.comboBox1.Items.Add("Close Active Window");
this.comboBox1.Items.Add("Do Navigation");
this.comboBox1.Items.Add("Lock Input!");

And if the monitoring is started, then this should be done by a timer. It will execute a method after the interval that is hardcoded and perform a check assuming the timer has been created. Then code with event handler is as follows:

private void timer1_Tick(object sender, EventArgs e)
        {
            img = null;
            r = g = b = 0;
            img = videoSourcePlayer1.GetCurrentVideoFrame();
            Validate_Colors(img);
            if (!((r + g + b) > 5000000))
            {
                perform();
            }
        }

There are two methods in the timer; one is getting the overall colors value from the image that is acquired recently from the stream of cam! Then the level of color is check this is the actual logic behind this app that is when we touch the cam light is stopped to cam and color is black so that all colors are less. The figure 5000000 is responsible for its sensitivity. You can adjust it according to your need. In case darkness is detected, then a method perform() is responsible to perform the action instantly chosen by user.

block for Validate_Colors()

Int64 r, g, b;
        public void Validate_Colors(Bitmap img)
        {
            BitmapData data = img.LockBits(new Rectangle(0, 0, img.Width, img.Height),
            ImageLockMode.ReadOnly, img.PixelFormat);
            unsafe
            {
                byte* ptrSrc = (byte*)data.Scan0;
                for (int y = 0; y < data.Height/4; ++y)
                {
                    for (int x = 0; x < data.Width/4; ++x)
                    {
                        r =r + ptrSrc[2];
                        g =g + ptrSrc[1];
                        b =b + ptrSrc[0];
                        ptrSrc += 3;
                    }
                }
                img.UnlockBits(data);
            }
        } 

After validating the colors, we have the data about the 3 colors in the frame acquired by cam. Now it's time to perform something if darkness is detected!

public void perform()
        {
            if (choice == 0)
            {
                MessageBox.Show("You Touch the Cam !","Touch Cam 1.3",
                MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else if (choice == 1)
            {
                StreamReader rdr = new StreamReader("App_Path.txt");
                file_name = rdr.ReadLine();
                rdr.Close();
                if (file_name != "" && file_name != null)
                {
                    Process file = new Process();
                    file.StartInfo.FileName = file_name;
                    file.Start();
                }
                else
                {
                    MessageBox.Show("Error No file has been Chosen to Start!",
                    "Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
                    DialogResult rs = MessageBox.Show("Do you want to Chose a File now?",
                    "Confirmation",MessageBoxButtons.YesNo,MessageBoxIcon.Question);
                    if (rs.Equals(DialogResult.Yes))
                    {
                        Chose_File();
                    }
                }
            }
            else if (choice == 2)
            {
                SendKeys.Send("%{F4}");
            }
            else if (choice == 3)
            {
                string temp = Load_Web();
                if (temp == null || temp == "")
                {
                    MessageBox.Show("Cannot Navigate no link has been Specified", 
                    "Error",MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    try
                    {
                        Process file = new Process();
                        file.StartInfo.FileName = temp;
                        file.Start();
                    }
                    catch(Exception ex)
                    {
                        MessageBox.Show(ex.Message,
                        "Oops!",MessageBoxButtons.OK,MessageBoxIcon.Error);
                    }
                }
            }
            else if (choice == 4)
            {
                BlockInputs();
            }
        }

The variable that is chosen is updated when user selects the actions in combobox! Now let's have a look at each action and how it is performed! The first one is just for debugging to ensure that we have touched the cam. The second choice reads a file in app location and fetches another file path that a user needs to start when he touches it. The third choice closes the active window and fourth one loads another file contents which is the address of website that he wants to open whenever the cam is touched! And the last one is to block the inputs so that mouse and keyboard both will not work until we will touch the cam again!

Let's have a look at the Load_Web method for Navigation action.

 private void Load_Web(string address)
        {
            try
            {
                StreamWriter wrt = new StreamWriter("Navigation.txt");
                wrt.WriteLine(address);
                wrt.Close();
            }
            catch
            {
                MessageBox.Show("Error Occured while storing link to the file!", 
            "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

// Overloading

        private string Load_Web()
        {
             try
                {
                    StreamReader rdr = new StreamReader("Navigation.txt");
                    string temp = rdr.ReadLine();
                    rdr.Close();
                    return temp;
                }
                catch
                {
                    MessageBox.Show("An Occured while fetching the link from file!", 
            "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return null;
                }
        }

Here, we are using the overloading to perform two different things. We are fetching the website address and in case we want to change it, then storing the new address with the same method. Don't worry, it is good!

For block input, we will use Win API so to use we need to insert the following class which will take care of all conditions to meet first before using the API we will just invoke the method class as follows:

public partial class NativeMethods
        {

            [DllImportAttribute("user32.dll", EntryPoint = "BlockInput")]
            [return: System.Runtime.InteropServices.MarshalAsAttribute
        (System.Runtime.InteropServices.UnmanagedType.Bool)]
            public static extern bool BlockInput
        ([System.Runtime.InteropServices.MarshalAsAttribute
        (System.Runtime.InteropServices.UnmanagedType.Bool)] bool fBlockIt);
        } 

And finally, the method used to call it and to block the inputs actually is the following!

bool block = false;
        public void BlockInputs()
        {
            if (admin)
            {
                if (block)
                {
                    block = false;
                    NativeMethods.BlockInput(block);
                    notifyIcon1.BalloonTipText = "Your mouse and Keyboard is Un-blocked!";
                    notifyIcon1.ShowBalloonTip(5);
                }
                else
                {
                    block = true;
                    NativeMethods.BlockInput(block);
                    notifyIcon1.BalloonTipText = "Your mouse and Keyboard is blocked!";
                    notifyIcon1.ShowBalloonTip(5);
                }
            }
            else
            {
                MessageBox.Show("This function cannot work without admin Privileges!",
                "Sorry!",MessageBoxButtons.OK,MessageBoxIcon.Information);
            }
        }

For this thing to work, we actually made a check of admin privileges because we need it here.

Points of Interest

Validate_Colors() is a method which checks colors by locking the bits of image in ram but you cannot do this because this is unsafe code which is by default disabled in project properties. So go there, click on build and check the checkbox saying allow Unsafe code!

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Pakistan Pakistan
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionquestion Pin
Mirza Bilal Anees15-Jul-14 1:36
professionalMirza Bilal Anees15-Jul-14 1:36 
AnswerRe: question Pin
Zain Ul Abidin15-Jul-14 2:57
Zain Ul Abidin15-Jul-14 2:57 
GeneralRe: question Pin
Mirza Bilal Anees23-Jul-14 23:37
professionalMirza Bilal Anees23-Jul-14 23:37 
GeneralRe: question Pin
Zain Ul Abidin26-Jul-14 18:11
Zain Ul Abidin26-Jul-14 18:11 
hahahahaha! no dude i have tested it running all time battery is used only when higher processor is used and it is optimized for processor usage hence it does not affect the battery consumption rate in your laptop!
QuestionThank to Zain-ul-Abadin Pin
Abbasi39314-Jul-14 17:22
Abbasi39314-Jul-14 17:22 
GeneralThanks Pin
Sikandar Ali13-Jul-14 23:09
Sikandar Ali13-Jul-14 23:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.