Pages

Sunday 30 October 2011

MOUSE GESTURES IMPLEMENTATION USING MESSAGE LOOPS

About Mouse gestures
        In recent times the use of mouse gestures to control the application is becoming increasingly common. For example, in smart phone, the user is asked to do some predefined finger movement to unlock the phone or to open an application. And similarly there are couple of computer applications which make use of mouse gestures.
        "Gestures" is a wide topic, some of which uses neural network as well. But please note that this blog talks only about mouse gestures and a sample code which implements that.
        As said earlier, an application can take inputs through either Mouse or Keyboard or through gestures. But when an application demands the input through mouse gestures, how exactly to provide that? Its very simple, click and hold the mouse (either left button or the right button depending on the application demand) and draw a predefined picture that the application recognizes and release the mouse click. This movement is interpreted as a "gesture". Simple isn't it? With that said, obviously it is possible to have unlimited number of gestures of varying complexity. However it is the application which defines the gestures to which user has to adhere. Following are some of the gestures that user find easy to use and aren't really difficult to recognize for an application.
   -> , <-, ^, | and etc. And some of the applications accept english alphabets as gesture.
               |  v

 
How to implement in .NET platform?
        There are multiple ways to implement mouse gestures. Basically, the mouse movements need to be captured when the gesture is made. And as you can expect, it can be done in multiple ways. But here I am going to discuss about Windows message loops for achieving the same (Read more about message loops here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644927(v=vs.85).aspx.
Fundamentally, Windows-based applications are event driven, they wait for system to send input to them. The system provides the input to the applications in the form of a message. System generates a message for every input event such as mouse clicks, mouse movement, key press and others. And therefore message loop become very handy for us to implement mouse gestures. With this infomation, let us dig and see how can message loops be used in .NET platform.

 
Working with Message Loops
        The .NET platform provides an inteface called "IMessageFilter" which allows an application to capture the message from the system. This interface provides a method called "PreFilterMessage" which helps in filtering out a message before it is dispatched. In other words, this method gives you the last message received in the message loop. Return value of this method is a boolean. Return true to filter the message and stop it being dispatched to the form or false to allow the message to flow to the form.

Usual procedure followed by the for developing an application that supports mouse gestures:
  1. Identify the gestures that you want to support.
  2. Create a message filter that looks for mouse click event (either left or right click depending on the requirement).
  3. Track for the mouse movements till the mouse click is released.
  4. Analyse the tracked mouse movement to identify the gesture and take the appropriate action.

Following is a sample application written C#.net which uses message loops to identify the mouse gestures.
This application is configured to identify four basic gestures.....
The application assumes mouse movements between left click of the mouse and release as the gesture.

//Code starts here...
namespace Sample
{
    //This application tries to identify following gestures.
    public enum gestureType : int
    {
        up = 0,
        down = 1,
        left = 2,
        right = 3,
        unidentified = 4
    }
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            //Add the message filter here
            MyFilter filt = new MyFilter();
            Application.AddMessageFilter(filt);
        }
    }
    public class MyFilter : IMessageFilter
    {
        //Some of the constants are defined.
        //All these values can be seen in: http://www.autohotkey.com/docs/misc/SendMessageList.htm
        private const int WM_MOUSEMOVE = 0x0200;
        private const int WM_LBUTTONDOWN = 0x0201;
        private const int WM_LBUTTONUP = 0x0202;
       
        //Have an arraylist for storing the mouse movements.
        private ArrayList mouseMoves = new ArrayList();
        Boolean bCaptureMouseMove = false;
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public bool PreFilterMessage(ref Message m)
        {
            if (bCaptureMouseMove == true)
            {
                if (m.Msg == WM_MOUSEMOVE)
                {
                    //add the mouse position into the arraylist
                    mouseMoves.Add(Cursor.Position);
                    return true;
                }
            }
            if (m.Msg == WM_LBUTTONDOWN)
            {
                //start capturing mouse moves.
                bCaptureMouseMove = true;
                mouseMoves.Add(Cursor.Position);
            }
            if (m.Msg == WM_LBUTTONUP)
            {
                //stop capturing mouse moves.
                bCaptureMouseMove = false;
                mouseMoves.Add(Cursor.Position);
                //Try to identify the gesture.
                identifyGesture();
            }
            return false;
        }

        private void identifyGesture()
        {
            gestureType direction = gestureType.unidentified;
            Point clickPos = (Point)mouseMoves[0];
            Point clickReleasePos = (Point)mouseMoves[mouseMoves.Count - 1];
            Point difference = new Point();
            difference.X = clickPos.X - clickReleasePos.X;
            difference.Y = clickPos.Y - clickReleasePos.Y;
            if (Math.Abs(difference.X) > Math.Abs(difference.Y))
            {
                if (difference.X > 0)
                {
                    direction = gestureType.left;
                    MessageBox.Show("Left");
                }
                else
                {
                    direction = gestureType.right;
                    MessageBox.Show("Right");
                }
            }
            else if (Math.Abs(difference.Y) > Math.Abs(difference.X))
            {
                if (difference.Y > 0)
                {
                    direction = gestureType.up;
                    MessageBox.Show("Up");
                }
                else
                {
                    direction = gestureType.down;
                    MessageBox.Show("Down");
                }
            }
            else
            {
                direction = gestureType.unidentified;
                MessageBox.Show("Not identified");
            }
        }
    }
}