Introduction
In a project I am currently working on I had the need for the ability to handle simple mouse gestures. I wanted to be able to do stuff like change the current selection in a combo box by simply moving the mouse up or down, and not having to switch the input focus from where I was working to the combo box and back again. I found a C++ article here[^] on The Code Project about mouse gestures, but it seemed to be more of an intellectual treatise on using neural networks to recognize predetermined mouse gestures rather than a ready to use class library that could be plugged into any project others might be working on (or maybe I am just too dense to figure it out ). As I am not one who likes to spend hours searching all over the web trying to find something that may or may not be there, I decided that the best way to get exactly what I wanted was to write it myself. This class and the article are the results of my efforts. Enjoy .
The idea (or how it works)
My idea on how to get this thing to work is actually quite simple. First of all, it involves setting up a mouse hook to track what the user is doing with the mouse. When the user presses one of the mouse buttons down, I start the mouse gesture by setting up a bounding square around the point where the mouse is located. If the user moves the mouse over the edge of the square I have a mouse gesture. The idea is to move the square along with the mouse, keeping track of which edge the mouse moves over. Every time the mouse moves over a different edge I get a new direction in the gesture.
Sequence for mouse gesture 'right and down'
You can get visual feedback of the mouse tracks and the bounding square in action if you download and build the demonstration application in DEBUG mode. You can turn the visual feedback off by commenting out line number 55 in the MouseGesture.cpp file.
# define _SHOW_GESTURE
Using the CMouseGesture class
The CMouseGesture
class is a simple class that you can plug into any C++ Windows code so that you too can have mouse gesture recognition in your applications. It is really quite simple. Just add the class files, MouseGesture.cpp and MouseGesture.h, to your project. Declare a CMouseGesture
object, tell it which window to watch for mouse gestures, and what gestures to watch for. When the CMouseGesture
object recognizes a mouse gesture it posts a registered message to the window it's watching, passing the ID of the gesture. To create the ID of the registered message pass the MOUSE_GESTURE_MESSAGE_STRING
to the RegisterWindowMessage()
function. The WPARAM
parameter of the registered message will be the identification number of the gesture recognized, and the LPARAM
parameter will be a pointer to the CMouseGesture
object that posted the message.
The following code snippet sets up the CMouseGesture
object to watch for a mouse gesture where the user presses the right mouse button, then moves the mouse to the right, then down, and then lets up the right mouse button again:
#include "MouseGesture.h"
#define ID_GESTURE_RIGHT_DOWN 1001
const UINT WMU_MOUSEGESTURE =
RegisterWindowMessage(MOUSE_GESTURE_MESSAGE_STRING);
.
.
.
CMouseGesture MyMouseGesture;
MyMouseGesture.Attach(GetSafeHwnd());
CMouseGesture::Motion WatchFor[] = { CMouseGesture::RightButton,
CMouseGesture::Right,
CMouseGesture::Down };
MyMouseGesture.AddGesture(ID_GESTURE_RIGHT_DOWN, WatchFor, 3);
.
.
.
LRESULT CMyWindowClass::OnMouseGesture(WPARAM wp, LPARAM lp)
{
UINT GestureID = (UINT)wp;
CMouseGesture *pMouseGesture = (CMouseGesture *)lp;
if (GestureID == ID_GESTURE_RIGHT_DOWN)
{
}
}
CMouseGesture class members
CMouseGesture::CMouseGesture()
CMouseGesture class constructor
Initializes all the internal variables.
Parameters:
None
Returns:
Nothing
CMouseGesture::~CMouseGesture()
CMouseGesture class destructor
Cleans up the class and removes the mouse hook if it is no longer needed.
Parameters:
None
Returns:
Nothing
bool CMouseGesture::Attach(HWND hWnd,
UINT Distance )
CMouseGesture::Attach
Initializes the CMouseGesture
object, attaching it to the supplied window handle and starting the mouse hook.
Parameters:
hWnd
The window handle of the window that this CMouseGesture
is to watch. The CMouseGesture
object will post a registered message to this window whenever it recognizes a mouse gesture.
Distance
The minimum distance in pixels that the mouse has to move before a mouse motion is registered. This parameter is optional and defaults to 25 pixels.
Returns:
true
, if successful.
false
, if not successful.
void CMouseGesture::Detach()
CMouseGesture::Detach
Detaches the CMouseGesture
object from the window it was attached to in the Attach
function. Stops the mouse hook if it is no longer needed.
Parameters:
None
Returns:
Nothing
bool CMouseGesture::RemoveGesture(UINT nID)
CMouseGesture::RemoveGesture
Removes the gesture with the supplied nID
from the CMouseGesture
object.
Parameters:
Returns:
true
, if the gesture with the identification number was found and removed.
false
, if the gesture with the identification number was not found.
int CMouseGesture::AddGesture(UINT nID,
const CMouseGesture::Motion* Motions,
size_t count)
int CMouseGesture::AddGesture(UINT nID,
const CMouseGesture::Gesture& rGesture)
CMouseGesture::AddGesture
Use these overloaded functions to add mouse gesture patterns to the CMouseGesture
object.
Parameters:
nID
The identification number of the gesture pattern. This number has to be unique to this CMouseGesture
object. (A different CMouseGesture
object can use the same ID.) This is the number that is passed back to the window when the gesture is recognized.
Motions
A pointer to an array of Motion
s. The Motion
type is an enum
defined in the CMouseGesture
class.
count
The number of Motion
elements in the Motions
array.
rGesture
A reference to a Gesture
vector containing an array of Motion
s.
Returns:
- -2
The supplied mouse gesture has already been added.
- -1
The supplied ID number is already in use.
- 0
The supplied mouse gesture has an invalid format or nID
is zero.
- >0
The gesture was successfully added, and the return value is the number of gestures in the CMouseGesture
object.
Note: The CMouseGesture::Motion
type is an enum
, and the CMouseGesture::Gesture
type is a typedef std::vector<Motion>
.
enum Motion { None = 0x0000,
Up = 0x0001,
Down = 0x0002,
Left = 0x0003,
Right = 0x0004,
Shift = 0x0005,
Control = 0x0006,
LeftButton = 0x0100,
MiddleButton = 0x0200,
RightButton = 0x0400
};
typedef std::vector<Motion> Gesture;
When you build the array (or vector) of Motion
s to pass to the AddGesture
function you must make sure that the array has the following format:
MouseButton [Shift] [Control] Motion ...
The mouse button that is pressed down to start the mouse gesture must be the first element in the array. It can be one of LeftButton
, MiddleButton
, or RightButton
. Following the mouse button can be the optional Shift
and/or Control
flags. Use Shift
if the gesture requires the SHIFT key on the keyboard to be pressed. Use Control
if the CTRL key is supposed to be pressed. If you want to use both, then Shift
has to be first, and Control
has to be second. After that comes one or more direction (Up
, Down
, Left
, or Right
) motions. You can not use the same direction motion twice immediately together.