Introduction: Detect Gesture in C# and Control IoT

About: Green hand in arduino

Since touchscreen has been used widely, we can play computer easily without keyboard and mouse. I want to make the best use of the touchscreen and my LattePanda (A SBC with Win10 system) to realize a new way of interaction. (Maybe this is the world first demo to control the Arduino GPIO with touchscreen gesture :p )

A LattePanda is a complete Windows 10 single board computer. It's much more powerful than Repberry Pi. This $89 SBC can run Win10 with no lags. And it can also run Ubuntu. Any peripherals that work on your PC will work on a LattePanda. It includes an integrated Arduino compatible co-processor, using hundreds of mature development platforms such as Johnny Five and Cylon, you can easily used it to control and sense the physical world!

Step 1: What You Need:

Step 2: Demo 1: Detect Mouse Position and Click Event

Let's do the project step by step. First thing of all, try to detect if the mouse is pressed or not. So we can detect the double click and triple click according to the interval.

It's a simple Windows Form Application. The textbox will show you the X axis and Y axis of the mouse. You can play this demo on your PC.


How to play Demo 1:
Run the .exe and move your mouse, the software will automatically detect the position of the mouse. If you press the left button of the mouse, the textbox will show the event.


You can see the code below or download the demo here. If you want to DIY this demo, you need to download Visual Studio here. Open.sln file and then you can make it your own.

Demo 1 Code:

using System;
using System.Drawing; using System.Windows.Forms; using System.Runtime.InteropServices;

namespace Demo_mousehook_csdn { public partial class Form1 : Form { public Form1() { InitializeComponent(); }

MouseHook mh;

private void Form1_Load(object sender, EventArgs e) { mh = new MouseHook(); mh.SetHook(); mh.MouseMoveEvent += mh_MouseMoveEvent; mh.MouseClickEvent += mh_MouseClickEvent; mh.MouseDownEvent += mh_MouseDownEvent; mh.MouseUpEvent += mh_MouseUpEvent; } private void mh_MouseDownEvent(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { richTextBox1.AppendText("Left Button Press\n"); } if (e.Button == MouseButtons.Right) { richTextBox1.AppendText("Right Button Press\n"); } } private void mh_MouseUpEvent(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { richTextBox1.AppendText("Left Button Release\n"); } if (e.Button == MouseButtons.Right) { richTextBox1.AppendText("Right Button Release\n"); } } private void mh_MouseClickEvent(object sender, MouseEventArgs e) { //MessageBox.Show(e.X + "-" + e.Y); if (e.Button == MouseButtons.Left) { string sText = "(" + e.X.ToString() + "," + e.Y.ToString() + ")"; label1.Text = sText; } }

private void mh_MouseMoveEvent(object sender, MouseEventArgs e) { int x = e.Location.X; int y = e.Location.Y; textBox1.Text = x + ""; textBox2.Text = y + ""; } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { mh.UnHook(); }

private void Form1_FormClosed_1(object sender, FormClosedEventArgs e) { mh.UnHook(); }

private void richTextBox1_TextChanged(object sender, EventArgs e) {

} }

public class Win32Api { [StructLayout(LayoutKind.Sequential)] public class POINT { public int x; public int y; } [StructLayout(LayoutKind.Sequential)] public class MouseHookStruct { public POINT pt; public int hwnd; public int wHitTestCode; public int dwExtraInfo; } public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern bool UnhookWindowsHookEx(int idHook); [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam); }

public class MouseHook { private Point point; private Point Point { get { return point; } set { if (point != value) { point = value; if (MouseMoveEvent != null) { var e = new MouseEventArgs(MouseButtons.None, 0, point.X, point.Y, 0); MouseMoveEvent(this, e); } } } } private int hHook; private const int WM_MOUSEMOVE = 0x200; private const int WM_LBUTTONDOWN = 0x201; private const int WM_RBUTTONDOWN = 0x204; private const int WM_MBUTTONDOWN = 0x207; private const int WM_LBUTTONUP = 0x202; private const int WM_RBUTTONUP = 0x205; private const int WM_MBUTTONUP = 0x208; private const int WM_LBUTTONDBLCLK = 0x203; private const int WM_RBUTTONDBLCLK = 0x206; private const int WM_MBUTTONDBLCLK = 0x209; public const int WH_MOUSE_LL = 14; public Win32Api.HookProc hProc; public MouseHook() { this.Point = new Point(); } public int SetHook() { hProc = new Win32Api.HookProc(MouseHookProc); hHook = Win32Api.SetWindowsHookEx(WH_MOUSE_LL, hProc, IntPtr.Zero, 0); return hHook; } public void UnHook() { Win32Api.UnhookWindowsHookEx(hHook); } private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam) { Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct)); if (nCode < 0) { return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam); } else { if (MouseClickEvent != null) { MouseButtons button = MouseButtons.None; int clickCount = 0; switch ((Int32)wParam) { case WM_LBUTTONDOWN: button = MouseButtons.Left; clickCount = 1; MouseDownEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0)); break; case WM_RBUTTONDOWN: button = MouseButtons.Right; clickCount = 1; MouseDownEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0)); break; case WM_MBUTTONDOWN: button = MouseButtons.Middle; clickCount = 1; MouseDownEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0)); break; case WM_LBUTTONUP: button = MouseButtons.Left; clickCount = 1; MouseUpEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0)); break; case WM_RBUTTONUP: button = MouseButtons.Right; clickCount = 1; MouseUpEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0)); break; case WM_MBUTTONUP: button = MouseButtons.Middle; clickCount = 1; MouseUpEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0)); break; }

var e = new MouseEventArgs(button, clickCount, point.X, point.Y, 0); MouseClickEvent(this, e); } this.Point = new Point(MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y); return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam); } }

public delegate void MouseMoveHandler(object sender, MouseEventArgs e); public event MouseMoveHandler MouseMoveEvent;

public delegate void MouseClickHandler(object sender, MouseEventArgs e); public event MouseClickHandler MouseClickEvent;

public delegate void MouseDownHandler(object sender, MouseEventArgs e); public event MouseDownHandler MouseDownEvent;

public delegate void MouseUpHandler(object sender, MouseEventArgs e); public event MouseUpHandler MouseUpEvent;

} }

If you have any questions, please let me know!

Step 3: Demo 2: Detect Double-Click and Control the LED

See the picture above. To prevent a wrong trigger, I set the right 1/5 of the screen area to detect the double-click of the mouse.

In this demo, you will know how to detect the double-click (Just calculate the interval of two clicks) and control the LED by Arduino Leonardo.

This demo involved C# and Arduino serial communication (communication between PC and Arduino). If you want to know this part of knowledge, see the tutorial here.

How to play DEMO 2:
Double-Click on the right 1/5 side of the screen, then you will enter the GPIO control mode, the LED will be turned on. Click on the left 4/5 side of the screen, the LED will be turned off.


You can see the code in the attachments or download the demo here. If you minimize the window, the function still working. It's cool, isn't it?

Demo 2 Code:

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 System.Runtime.InteropServices; using System.Globalization; using LattePanda.Firmata;

namespace Demo_mousehook_csdn { public partial class Form1 : Form { static Arduino arduino = new Arduino(); static DateTime localDate = DateTime.Now; double click_time; int click_count = 0; bool tri_click_flag = false; public Form1() { InitializeComponent(); arduino.pinMode(13, Arduino.OUTPUT);// }

MouseHook mh;

private void Form1_Load(object sender, EventArgs e) { mh = new MouseHook(); mh.SetHook(); mh.MouseMoveEvent += mh_MouseMoveEvent; mh.MouseClickEvent += mh_MouseClickEvent; }

private void mh_MouseClickEvent(object sender, MouseEventArgs e) { //MessageBox.Show(e.X + "-" + e.Y); if (e.Button == MouseButtons.Left) { string sText = "(" + e.X.ToString() + "," + e.Y.ToString() + ")"; label1.Text = sText; click_time = (DateTime.Now - localDate).TotalSeconds;

localDate = DateTime.Now; if (e.X > (Screen.PrimaryScreen.Bounds.Width / 5 * 4)) {

if (click_time <= 0.5) { click_count += 1; if (click_count > 0) { click_count = 1; tri_click_flag = true; } else { tri_click_flag = false; } } else { } if (click_count <=1 && click_time > 0.5) click_count = 0;

} else { click_count = 0; tri_click_flag = false; }

if (tri_click_flag == true) { textBox6.Text = "1"; arduino.digitalWrite(13, Arduino.HIGH); } else { textBox6.Text = "0"; arduino.digitalWrite(13, Arduino.LOW); }

} }

private void mh_MouseMoveEvent(object sender, MouseEventArgs e) { int x = e.Location.X; int y = e.Location.Y; textBox1.Text = x + ""; textBox2.Text = y + ""; textBox3.Text = Screen.PrimaryScreen.Bounds.Height.ToString(); textBox4.Text = Screen.PrimaryScreen.Bounds.Width.ToString();

}

private void Form1_FormClosed(object sender, FormClosedEventArgs e) { mh.UnHook(); }

private void Form1_FormClosed_1(object sender, FormClosedEventArgs e) { mh.UnHook(); }

private void textBox1_TextChanged(object sender, EventArgs e) {

}

private void textBox2_TextChanged(object sender, EventArgs e) {

}

private void label1_Click(object sender, EventArgs e) {

}

private void textBox3_TextChanged(object sender, EventArgs e) {

}

private void textBox4_TextChanged(object sender, EventArgs e) {

}

private void label2_Click(object sender, EventArgs e) {

}

private void label3_Click(object sender, EventArgs e) {

}

private void textBox5_TextChanged(object sender, EventArgs e) {

}

private void textBox6_TextChanged(object sender, EventArgs e) {

} }

public class Win32Api { [StructLayout(LayoutKind.Sequential)] public class POINT { public int x; public int y; } [StructLayout(LayoutKind.Sequential)] public class MouseHookStruct { public POINT pt; public int hwnd; public int wHitTestCode; public int dwExtraInfo; } public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam); //安装钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); //卸载钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern bool UnhookWindowsHookEx(int idHook); //调用下一个钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam); }

public class MouseHook { private Point point; private Point Point { get { return point; } set { if (point != value) { point = value; if (MouseMoveEvent != null) { var e = new MouseEventArgs(MouseButtons.None, 0, point.X, point.Y, 0); MouseMoveEvent(this, e); } } } } private int hHook; private const int WM_LBUTTONDOWN = 0x201; public const int WH_MOUSE_LL = 14; public Win32Api.HookProc hProc; public MouseHook() { this.Point = new Point(); } public int SetHook() { hProc = new Win32Api.HookProc(MouseHookProc); hHook = Win32Api.SetWindowsHookEx(WH_MOUSE_LL, hProc, IntPtr.Zero, 0); return hHook; } public void UnHook() { Win32Api.UnhookWindowsHookEx(hHook); } private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam) { Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct)); if (nCode < 0) { return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam); } else { if (MouseClickEvent != null) { MouseButtons button = MouseButtons.None; int clickCount = 0; switch ((Int32)wParam) { case WM_LBUTTONDOWN: button = MouseButtons.Left; clickCount = 1; break; }

var e = new MouseEventArgs(button, clickCount, point.X, point.Y, 0); MouseClickEvent(this, e); } this.Point = new Point(MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y); return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam); } }

public delegate void MouseMoveHandler(object sender, MouseEventArgs e); public event MouseMoveHandler MouseMoveEvent;

public delegate void MouseClickHandler(object sender, MouseEventArgs e); public event MouseClickHandler MouseClickEvent; } }

It's a new method to do a interaction project. It can also used in home automation control system. Use your PC to control the air-conditioner, light, TV, etc.

Step 4: Demo 3: Detect Triple-Click and Control the Screen Background Light

In this demo, you will get the position of your mouse and send the real-time value to your PC. Then your PC can change the background light according to the value. You can also play this demo on your PC.

This demo involved use C# to control the background light of the screen. If you want to know this part of knowledge, you can see the tutorial here.

How to play DEMO 3:
Triple-click on the right 1/5 side of the screen, then you will enter the GPIO control mode, move your finger up or down, the background light of your screen will turn ligher or darker.


This function is a little similar to the one of your iPhone. You can see the code in the attachments or download the demo here.

Method 1:

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 System.Runtime.InteropServices; using System.Globalization;

namespace Demo_mousehook_csdn { public partial class Form1 : Form { [DllImport("gdi32.dll")] private unsafe static extern bool SetDeviceGammaRamp(Int32 hdc, void* ramp); private static bool initialized = false; private static Int32 hdc; private static int a; static DateTime localDate = DateTime.Now; double click_time; int click_count = 0; bool tri_click_flag = false; static string sText=""; static int IncreaseData = 0; static int ClickPositionY = 0; public Form1() { InitializeComponent(); }

MouseHook mh; // protected override void SetVisibleCore(bool value) // { // base.SetVisibleCore(false); // } private void Form1_Load(object sender, EventArgs e) { mh = new MouseHook(); mh.SetHook(); mh.MouseMoveEvent += mh_MouseMoveEvent; mh.MouseClickEvent += mh_MouseClickEvent; mh.MouseDownEvent += mh_MouseDownEvent; mh.MouseUpEvent += mh_MouseUpEvent; } private static void InitializeClass() { if (initialized) return;

//Get the hardware device context of the screen, we can do //this by getting the graphics object of null (IntPtr.Zero) //then getting the HDC and converting that to an Int32. hdc = Graphics.FromHwnd(IntPtr.Zero).GetHdc().ToInt32();

initialized = false; } public static unsafe bool SetBrightness(int brightness) { InitializeClass();

if (brightness > 255) brightness = 255;

if (brightness < 0) brightness = 0;

short* gArray = stackalloc short[3 * 256]; short* idx = gArray;

for (int j = 0; j < 3; j++) { for (int i = 0; i < 256; i++) { int arrayVal = i * (brightness + 128);

if (arrayVal > 65535) arrayVal = 65535;

*idx = (short)arrayVal; idx++; } }

//For some reason, this always returns false? bool retVal = SetDeviceGammaRamp(hdc, gArray);

//Memory allocated through stackalloc is automatically free'd //by the CLR.

return retVal; }

private void mh_MouseClickEvent(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { ClickPositionY = e.X; sText = "(" + e.X.ToString() + "," + e.Y.ToString() + ")"; label1.Text = sText; click_time = (DateTime.Now - localDate).TotalSeconds;

localDate = DateTime.Now; if (e.X > (Screen.PrimaryScreen.Bounds.Width / 5 * 4)) {

if (click_time <= 0.5) { click_count += 1; label3.Text = "1"; if (click_count > 1) { click_count = 2; label2.Text = "1"; tri_click_flag = true; } else { label2.Text = "0"; tri_click_flag = false; }

textBox5.Text = click_count.ToString(); } else { textBox5.Text = click_count.ToString(); } if (click_count <=1 && click_time > 0.5) click_count = 0;

} else { label3.Text = "0"; click_count = 0; textBox5.Text = click_count.ToString(); label2.Text = "0"; tri_click_flag = false; } } }

private void mh_MouseMoveEvent(object sender, MouseEventArgs e) { int x = e.Location.X; int y = e.Location.Y; int LedData = 0; LedData = (Screen.PrimaryScreen.Bounds.Height - y)*140/ Screen.PrimaryScreen.Bounds.Height; if (LedData <= 0) LedData = 0; if (e.X > (Screen.PrimaryScreen.Bounds.Width / 5 * 4)) { if (tri_click_flag == true) { textBox6.Text = "1"; SetBrightness(LedData); label15.Text = LedData.ToString(); } else { textBox6.Text = "0"; } } textBox1.Text = x + ""; textBox2.Text = y + ""; textBox3.Text = Screen.PrimaryScreen.Bounds.Height.ToString(); textBox4.Text = Screen.PrimaryScreen.Bounds.Width.ToString(); }

private void Form1_FormClosed(object sender, FormClosedEventArgs e) { mh.UnHook(); }

private void Form1_FormClosed_1(object sender, FormClosedEventArgs e) { mh.UnHook(); }

private void textBox1_TextChanged(object sender, EventArgs e) {

}

private void textBox2_TextChanged(object sender, EventArgs e) {

}

private void label1_Click(object sender, EventArgs e) {

}

private void textBox3_TextChanged(object sender, EventArgs e) {

}

private void textBox4_TextChanged(object sender, EventArgs e) {

}

private void label2_Click(object sender, EventArgs e) {

}

private void label3_Click(object sender, EventArgs e) {

}

private void textBox5_TextChanged(object sender, EventArgs e) {

}

private void textBox6_TextChanged(object sender, EventArgs e) {

}

private void mh_MouseDownEvent(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { richTextBox1.AppendText("按下了左键\n"); } }

private void mh_MouseUpEvent(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { richTextBox1.AppendText("松开了左键\n"); } }

private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e) {

}

private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) {

}

private void exitToolStripMenuItem_Click(object sender, EventArgs e) { Application.ExitThread(); Environment.Exit(0); }

private void label13_Click(object sender, EventArgs e) {

}

private void label14_Click(object sender, EventArgs e) {

}

private void label15_Click(object sender, EventArgs e) {

}

private void richTextBox1_TextChanged(object sender, EventArgs e) {

} }

public class Win32Api { [StructLayout(LayoutKind.Sequential)] public class POINT { public int x; public int y; } [StructLayout(LayoutKind.Sequential)] public class MouseHookStruct { public POINT pt; public int hwnd; public int wHitTestCode; public int dwExtraInfo; } public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam); //安装钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); //卸载钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern bool UnhookWindowsHookEx(int idHook); //调用下一个钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam); }

public class MouseHook { private Point point; private Point Point { get { return point; } set { if (point != value) { point = value; if (MouseMoveEvent != null) { var e = new MouseEventArgs(MouseButtons.None, 0, point.X, point.Y, 0); MouseMoveEvent(this, e); } } } } private int hHook; private const int WM_LBUTTONDOWN = 0x201; private const int WM_LBUTTONUP = 0x202; public const int WH_MOUSE_LL = 14; public Win32Api.HookProc hProc; public MouseHook() { this.Point = new Point(); } public int SetHook() { hProc = new Win32Api.HookProc(MouseHookProc); hHook = Win32Api.SetWindowsHookEx(WH_MOUSE_LL, hProc, IntPtr.Zero, 0); return hHook; } public void UnHook() { Win32Api.UnhookWindowsHookEx(hHook); } private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam) { Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct)); if (nCode < 0) { return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam); } else { if (MouseClickEvent != null) { MouseButtons button = MouseButtons.None; int clickCount = 0; switch ((Int32)wParam) { case WM_LBUTTONDOWN: button = MouseButtons.Left; clickCount = 1; break; case WM_LBUTTONUP: button = MouseButtons.Left; clickCount = 1; break; }

var e = new MouseEventArgs(button, clickCount, point.X, point.Y, 0); MouseClickEvent(this, e); } this.Point = new Point(MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y); return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam); } }

public delegate void MouseMoveHandler(object sender, MouseEventArgs e); public event MouseMoveHandler MouseMoveEvent;

public delegate void MouseClickHandler(object sender, MouseEventArgs e); public event MouseClickHandler MouseClickEvent;

public delegate void MouseDownHandler(object sender, MouseEventArgs e); public event MouseDownHandler MouseDownEvent;

public delegate void MouseUpHandler(object sender, MouseEventArgs e); public event MouseUpHandler MouseUpEvent; } }

Method 2:

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 System.Runtime.InteropServices; using System.Globalization; //using LattePanda.Firmata;

namespace Demo_mousehook_csdn { public partial class Form1 : Form { //static Arduino arduino = new Arduino(); static DateTime localDate = DateTime.Now; double click_time; int click_count = 0; bool tri_click_flag = false; bool mouse_down_flag = false; static string sText="";

static int ClickPositionY = 0; static int LedData = 0;//需要发送的LED亮度值 static int LedIncreaseData = 0; //Data增量 static int LedLastData = 0;//Led的最后一次亮度 static int LedStoreData = 0;//Led需要储藏的数值,备用

[DllImport("gdi32.dll")] private unsafe static extern bool SetDeviceGammaRamp(Int32 hdc, void* ramp);

private static bool initialized = false; private static Int32 hdc;

private static void InitializeClass() { if (initialized) return;

//Get the hardware device context of the screen, we can do //this by getting the graphics object of null (IntPtr.Zero) //then getting the HDC and converting that to an Int32. hdc = Graphics.FromHwnd(IntPtr.Zero).GetHdc().ToInt32();

initialized = false; } public static unsafe bool SetBrightness(int brightness) { InitializeClass();

if (brightness > 255) brightness = 255;

if (brightness < 0) brightness = 0;

short* gArray = stackalloc short[3 * 256]; short* idx = gArray;

for (int j = 0; j < 3; j++) { for (int i = 0; i < 256; i++) { int arrayVal = i * (brightness + 128);

if (arrayVal > 65535) arrayVal = 65535;

*idx = (short)arrayVal; idx++; } }

//For some reason, this always returns false? bool retVal = SetDeviceGammaRamp(hdc, gArray);

//Memory allocated through stackalloc is automatically free'd //by the CLR.

return retVal; }

public Form1() { InitializeComponent();

// arduino.pinMode(13, Arduino.OUTPUT);// }

MouseHook mh; // protected override void SetVisibleCore(bool value) // { // base.SetVisibleCore(false); // } private void Form1_Load(object sender, EventArgs e) { mh = new MouseHook(); mh.SetHook(); mh.MouseMoveEvent += mh_MouseMoveEvent; mh.MouseClickEvent += mh_MouseClickEvent; mh.MouseUpEvent += mh_MouseUpEvent; mh.MouseDownEvent += mh_MouseDownEvent; } private void mh_MouseUpEvent(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { LedLastData = LedData; mouse_down_flag = false; richTextBox1.AppendText("Released\n"); } } private void mh_MouseDownEvent(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { mouse_down_flag = true; click_time = (DateTime.Now - localDate).TotalSeconds; localDate = DateTime.Now; label13.Text = click_time.ToString(); richTextBox1.AppendText("Pressed\n"); if (e.X > (Screen.PrimaryScreen.Bounds.Width / 5 * 4)) { ClickPositionY= e.Location.Y;

if (click_time <= 0.5) {

click_count += 1; label3.Text = "1"; if (click_count > 1) { click_count = 2; label2.Text = "1"; tri_click_flag = true; } else { label2.Text = "0"; tri_click_flag = false; }

textBox5.Text = click_count.ToString(); }

else { textBox5.Text = click_count.ToString(); } if (click_count <= 1 && click_time > 0.5) click_count = 0;

} else { label3.Text = "0"; click_count = 0; textBox5.Text = click_count.ToString(); label2.Text = "0"; tri_click_flag = false; } } } private void mh_MouseClickEvent(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { sText = "(" + e.X.ToString() + "," + e.Y.ToString() + ")"; label1.Text = sText; } }

private void mh_MouseMoveEvent(object sender, MouseEventArgs e) { int x = e.Location.X; int y = e.Location.Y; if (e.X > (Screen.PrimaryScreen.Bounds.Width / 5 * 4)) { if (tri_click_flag == true) { textBox6.Text = "1"; if(mouse_down_flag==true) { LedIncreaseData = (ClickPositionY - y) * 140 / 1080;

LedData = LedStoreData + LedIncreaseData; if(LedData<0) { LedData = 0; } if (LedData > 140) { LedData = 140; } SetBrightness(LedData); } if(mouse_down_flag==false) { LedStoreData = LedLastData; } } else { textBox6.Text = "0"; }

}

label19.Text = LedStoreData.ToString(); label20.Text = LedData.ToString(); label15.Text = LedIncreaseData.ToString(); textBox1.Text = x + ""; textBox2.Text = y + ""; textBox3.Text = Screen.PrimaryScreen.Bounds.Height.ToString(); textBox4.Text = Screen.PrimaryScreen.Bounds.Width.ToString(); }

private void Form1_FormClosed(object sender, FormClosedEventArgs e) { mh.UnHook(); }

private void Form1_FormClosed_1(object sender, FormClosedEventArgs e) { mh.UnHook(); }

private void textBox1_TextChanged(object sender, EventArgs e) {

}

private void textBox2_TextChanged(object sender, EventArgs e) {

}

private void label1_Click(object sender, EventArgs e) {

}

private void textBox3_TextChanged(object sender, EventArgs e) {

}

private void textBox4_TextChanged(object sender, EventArgs e) {

}

private void label2_Click(object sender, EventArgs e) {

}

private void label3_Click(object sender, EventArgs e) {

}

private void textBox5_TextChanged(object sender, EventArgs e) {

}

private void textBox6_TextChanged(object sender, EventArgs e) { }

private void Form1_MouseDown(object sender, MouseEventArgs e) {

}

private void Form1_MouseUp(object sender, MouseEventArgs e) { }

private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e) {

}

private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) {

}

private void exitToolStripMenuItem_Click(object sender, EventArgs e) { Application.ExitThread(); Environment.Exit(0); }

private void label13_Click(object sender, EventArgs e) {

}

private void label14_Click(object sender, EventArgs e) {

}

private void label15_Click(object sender, EventArgs e) {

}

private void richTextBox1_TextChanged(object sender, EventArgs e) {

}

private void label19_Click(object sender, EventArgs e) {

}

private void label20_Click(object sender, EventArgs e) {

} }

public class Win32Api { [StructLayout(LayoutKind.Sequential)] public class POINT { public int x; public int y; } [StructLayout(LayoutKind.Sequential)] public class MouseHookStruct { public POINT pt; public int hwnd; public int wHitTestCode; public int dwExtraInfo; } public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam); //安装钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); //卸载钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern bool UnhookWindowsHookEx(int idHook); //调用下一个钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam); }

public class MouseHook { private Point point; private Point Point { get { return point; } set { if (point != value) { point = value; if (MouseMoveEvent != null) { var e = new MouseEventArgs(MouseButtons.None, 0, point.X, point.Y, 0); MouseMoveEvent(this, e); } } } } private int hHook; private const int WM_LBUTTONDOWN = 0x201; private const int WM_LBUTTONUP = 0x202; public const int WH_MOUSE_LL = 14; public Win32Api.HookProc hProc; public MouseHook() { this.Point = new Point(); } public int SetHook() { hProc = new Win32Api.HookProc(MouseHookProc); hHook = Win32Api.SetWindowsHookEx(WH_MOUSE_LL, hProc, IntPtr.Zero, 0); return hHook; } public void UnHook() { Win32Api.UnhookWindowsHookEx(hHook); } private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam) { Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct)); if (nCode < 0) { return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam); } else { if (MouseClickEvent != null) { MouseButtons button = MouseButtons.None; int clickCount = 0; switch ((Int32)wParam) { case WM_LBUTTONDOWN: button = MouseButtons.Left; clickCount = 1; MouseDownEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0)); break; case WM_LBUTTONUP: button = MouseButtons.Left; clickCount = 1; MouseUpEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0)); break; }

var e = new MouseEventArgs(button, clickCount, point.X, point.Y, 0); MouseClickEvent(this, e); } this.Point = new Point(MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y); return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam); } }

public delegate void MouseMoveHandler(object sender, MouseEventArgs e); public event MouseMoveHandler MouseMoveEvent;

public delegate void MouseClickHandler(object sender, MouseEventArgs e); public event MouseClickHandler MouseClickEvent;

public delegate void MouseUpHandler(object sender, MouseEventArgs e); public event MouseUpHandler MouseUpEvent;

public delegate void MouseDownHandler(object sender, MouseEventArgs e); public event MouseDownHandler MouseDownEvent; } }

Have fun!

So far so good? If you have any questions, please let me know!

Step 5: Demo 4: Detect Triple-Click and Control the LED Light

In this demo, you will get the position of your mouse and send the real-time value to your Arduino. Then your Arduino can control the LED according to the value.

How to play DEMO 4:
Triple-click on the right 1/5 side of the screen, then you will enter the GPIO control mode, move your finger up or down, the LED(D13) will turn ligher or darker.

This demo involved communication between PC and Arduino (Arduino and C# communication). If you want to know this part of knowledge, see the tutorial here.

You can see the code in the attachments or download the demo here.

Demo 4 code:

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 System.Runtime.InteropServices; using System.Globalization; using LattePanda.Firmata;

namespace Demo_mousehook_csdn { public partial class Form1 : Form { static Arduino arduino = new Arduino(); static DateTime localDate = DateTime.Now; double click_time; int click_count = 0; bool tri_click_flag = false; bool mouse_down_flag = false; static string sText="";

static int ClickPositionY = 0; static int LedData = 0;//需要发送的LED亮度值 static int LedIncreaseData = 0; //Data增量 static int LedLastData = 0;//Led的最后一次亮度 static int LedStoreData = 0;//Led需要储藏的数值,备用

public Form1() { InitializeComponent();

arduino.pinMode(13, Arduino.PWM);// }

MouseHook mh; private void Form1_Load(object sender, EventArgs e) { mh = new MouseHook(); mh.SetHook(); mh.MouseMoveEvent += mh_MouseMoveEvent; mh.MouseClickEvent += mh_MouseClickEvent; mh.MouseUpEvent += mh_MouseUpEvent; mh.MouseDownEvent += mh_MouseDownEvent; } private void mh_MouseUpEvent(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { LedLastData = LedData; mouse_down_flag = false; richTextBox1.AppendText("Released\n"); } } private void mh_MouseDownEvent(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { mouse_down_flag = true; click_time = (DateTime.Now - localDate).TotalSeconds; localDate = DateTime.Now; label13.Text = click_time.ToString(); richTextBox1.AppendText("Pressed\n"); if (e.X > (Screen.PrimaryScreen.Bounds.Width / 5 * 4)) { ClickPositionY= e.Location.Y;

if (click_time <= 0.5) {

click_count += 1; label3.Text = "1"; if (click_count > 1) { click_count = 2; label2.Text = "1"; tri_click_flag = true; } else { label2.Text = "0"; tri_click_flag = false; }

textBox5.Text = click_count.ToString(); }

else { textBox5.Text = click_count.ToString(); } if (click_count <= 1 && click_time > 0.5) click_count = 0;

} else { label3.Text = "0"; click_count = 0; textBox5.Text = click_count.ToString(); label2.Text = "0"; tri_click_flag = false; } } } private void mh_MouseClickEvent(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { sText = "(" + e.X.ToString() + "," + e.Y.ToString() + ")"; label1.Text = sText; } }

private void mh_MouseMoveEvent(object sender, MouseEventArgs e) { int x = e.Location.X; int y = e.Location.Y; if (e.X > (Screen.PrimaryScreen.Bounds.Width / 5 * 4)) { if (tri_click_flag == true) { textBox6.Text = "1"; if(mouse_down_flag==true) { LedIncreaseData = (ClickPositionY - y) * 140 / 1080;

LedData = LedStoreData + LedIncreaseData; if(LedData<0) { LedData = 0; } if (LedData > 140) { LedData = 140; } arduino.analogWrite(13,LedData); } if(mouse_down_flag==false) { LedStoreData = LedLastData; } } else { textBox6.Text = "0"; }

}

label19.Text = LedStoreData.ToString(); label20.Text = LedData.ToString(); label15.Text = LedIncreaseData.ToString(); textBox1.Text = x + ""; textBox2.Text = y + ""; textBox3.Text = Screen.PrimaryScreen.Bounds.Height.ToString(); textBox4.Text = Screen.PrimaryScreen.Bounds.Width.ToString(); }

private void Form1_FormClosed(object sender, FormClosedEventArgs e) { mh.UnHook(); }

private void Form1_FormClosed_1(object sender, FormClosedEventArgs e) { mh.UnHook(); }

private void textBox1_TextChanged(object sender, EventArgs e) {

}

private void textBox2_TextChanged(object sender, EventArgs e) {

}

private void label1_Click(object sender, EventArgs e) {

}

private void textBox3_TextChanged(object sender, EventArgs e) {

}

private void textBox4_TextChanged(object sender, EventArgs e) {

}

private void label2_Click(object sender, EventArgs e) {

}

private void label3_Click(object sender, EventArgs e) {

}

private void textBox5_TextChanged(object sender, EventArgs e) {

}

private void textBox6_TextChanged(object sender, EventArgs e) { }

private void Form1_MouseDown(object sender, MouseEventArgs e) {

}

private void Form1_MouseUp(object sender, MouseEventArgs e) { }

private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e) {

}

private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) {

}

private void exitToolStripMenuItem_Click(object sender, EventArgs e) { Application.ExitThread(); Environment.Exit(0); }

private void label13_Click(object sender, EventArgs e) {

}

private void label14_Click(object sender, EventArgs e) {

}

private void label15_Click(object sender, EventArgs e) {

}

private void richTextBox1_TextChanged(object sender, EventArgs e) {

}

private void label19_Click(object sender, EventArgs e) {

}

private void label20_Click(object sender, EventArgs e) {

} }

public class Win32Api { [StructLayout(LayoutKind.Sequential)] public class POINT { public int x; public int y; } [StructLayout(LayoutKind.Sequential)] public class MouseHookStruct { public POINT pt; public int hwnd; public int wHitTestCode; public int dwExtraInfo; } public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam); //安装钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); //卸载钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern bool UnhookWindowsHookEx(int idHook); //调用下一个钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam); }

public class MouseHook { private Point point; private Point Point { get { return point; } set { if (point != value) { point = value; if (MouseMoveEvent != null) { var e = new MouseEventArgs(MouseButtons.None, 0, point.X, point.Y, 0); MouseMoveEvent(this, e); } } } } private int hHook; private const int WM_LBUTTONDOWN = 0x201; private const int WM_LBUTTONUP = 0x202; public const int WH_MOUSE_LL = 14; public Win32Api.HookProc hProc; public MouseHook() { this.Point = new Point(); } public int SetHook() { hProc = new Win32Api.HookProc(MouseHookProc); hHook = Win32Api.SetWindowsHookEx(WH_MOUSE_LL, hProc, IntPtr.Zero, 0); return hHook; } public void UnHook() { Win32Api.UnhookWindowsHookEx(hHook); } private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam) { Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct)); if (nCode < 0) { return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam); } else { if (MouseClickEvent != null) { MouseButtons button = MouseButtons.None; int clickCount = 0; switch ((Int32)wParam) { case WM_LBUTTONDOWN: button = MouseButtons.Left; clickCount = 1; MouseDownEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0)); break; case WM_LBUTTONUP: button = MouseButtons.Left; clickCount = 1; MouseUpEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0)); break; }

var e = new MouseEventArgs(button, clickCount, point.X, point.Y, 0); MouseClickEvent(this, e); } this.Point = new Point(MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y); return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam); } }

public delegate void MouseMoveHandler(object sender, MouseEventArgs e); public event MouseMoveHandler MouseMoveEvent;

public delegate void MouseClickHandler(object sender, MouseEventArgs e); public event MouseClickHandler MouseClickEvent;

public delegate void MouseUpHandler(object sender, MouseEventArgs e); public event MouseUpHandler MouseUpEvent;

public delegate void MouseDownHandler(object sender, MouseEventArgs e); public event MouseDownHandler MouseDownEvent; } }

If you have any questions, please let me know!

Step 6: Summary:

You get what you pay! I can't endure the lag when I run Win10 on Respberry Pi. LattePanda is a nice choice for you when you need to do a big project on SBC and it's x64 based processor. The CPU of LattePanda can perfectly handle big projects. It can also run Ubuntu perfectly. For me, LattePanda is a good platform to train my coding ability. Since it run Win10 system, I can use Visual Studio to do many projects in C++, C#, Python and so on. More importantly, it also has Arduino Leonardo on the board. I can easily control the physical world on my PC.