Click here to Skip to main content
15,895,799 members
Articles / Web Development / HTML

Mouse Gestures for Internet Explorer

Rate me:
Please Sign up or sign in to vote.
4.84/5 (99 votes)
21 Sep 200514 min read 1.3M   13.4K   235  
Adding mouse gesture recognition to Internet Explorer.
///////////////////////////////////////////////////////////////
//
// InternetExplorerSink.h
//
// Created: 12/07/2003
// Copyright (c) 2003 Ralph Hare (ralph.hare@ysgyfarnog.co.uk)
// All rights reserved.
//
// The code and information is provided "as-is" without
// warranty of any kind, either expressed or implied.
//
///////////////////////////////////////////////////////////////

#ifndef __INTERNETEXPLORERSINK_H_F2026BFC_F70F_46B5_A50E_896E4E022F83_
#define __INTERNETEXPLORERSINK_H_F2026BFC_F70F_46B5_A50E_896E4E022F83_

#include "Gesture.h"
#include <memory>

class MouseTrail;

/**
 * @brief Class to intercept mouse movements within a given window and
 *        inform an observer of these movements.
 *
 * The MouseTracker class subclasses a window. The classes message pump
 * intercepts all mouse messages and forwards these to the watcher.
 * 
 * Clients of the MouseTracker can disable mouse tracking by using the
 * Suspend RAII class. Each Suspend object sets the m_isSuspended flag
 * to true for its lifetime, and resets the flag to false when its
 * destroyed. When this flag is set the message handlers ignore
 * the current message by setting bHandled to FALSE and returning
 * 1 (denoting that the message hasn't been processed).
 *
 * We can't simply temporarily unsubclass the (subclassed) Window. If
 * we've got multiple ATL CWindowImpl derived objects subclassing a window
 * (as we do in the MouseGestures app if (for example) the Google toolbar
 * is installed), then there's no guarantee that we're the last object
 * in the message chain. Unsubclass can fail (the top-most message proc
 * will be different from the static WndProc function for this class),
 * resulting in recursion (and ultimately a stack overflow) if we send
 * our own messages to the subclassed window.
 **/

class MouseTracker : public CWindowImpl< MouseTracker >
{
public:
    struct Watcher
    {
        virtual ~Watcher() {}

    //
    // return true if we want to pass the message onto the subclassed window
    // or false if we want to swallow the message and start tracking the mouse
    //
        virtual bool OnLeftButtonDown( HWND hWnd, const POINT &pt, DWORD flags ) { return true; }
        virtual bool OnRightButtonDown( HWND hWnd, const POINT &pt, DWORD flags ) { return true; }

    //
    // if the user (i.e. the class that derives from Watcher) returns true from
    // either OnLeftButtonDown or OnRightButtonDown then we fire the OnLeftButtonUp
    // or OnRightButtonUp events respectively, with the (cracked) WPARAM and LPARAM
    // of the mouse message.
    //
        virtual bool OnLeftButtonUp( HWND hWnd, const POINT &pt, DWORD flags ) { return true; }
        virtual bool OnRightButtonUp( HWND hWnd, const POINT &pt, DWORD flags ) { return true; }

    //
    // if the user (i.e. the class that derives from Watcher) returns false from
    // either OnLeftButtonDown or OnRightButtonDown then we fire the OnLeftButtonUp
    // or OnRightButtonUp events respectively, with the path of the mouse
    // between the two events. There's no return value as we always swallow 
    // the windows message
    //
        virtual void OnLeftButtonUp( HWND hWnd, const Path &path ) {}
        virtual void OnRightButtonUp( HWND hWnd, const Path &path ) {}

    //
    // Mouse Wheel
    //
        virtual bool OnMouseWheel( HWND hWnd, WORD flags, WORD delta, const POINT &pt ) { return true; }
    };

public:
    MouseTracker();
    ~MouseTracker();

// Not implemented
private:
    MouseTracker( const MouseTracker &rhs );

public:
    BEGIN_MSG_MAP( MouseTracker )
        MESSAGE_HANDLER( WM_MOUSEMOVE, OnMouseMove )
        MESSAGE_HANDLER( WM_RBUTTONDOWN, OnRightButtonDown )
        MESSAGE_HANDLER( WM_RBUTTONUP, OnRightButtonUp )
        MESSAGE_HANDLER( WM_LBUTTONDOWN, OnLeftButtonDown )
        MESSAGE_HANDLER( WM_LBUTTONUP, OnLeftButtonUp )
        MESSAGE_HANDLER( WM_MOUSEWHEEL, OnMouseWheel )
        MESSAGE_HANDLER( WM_DESTROY, OnDestroy )
        MESSAGE_HANDLER( WM_SETFOCUS, OnSetFocus )
        MESSAGE_HANDLER( WM_KILLFOCUS, OnKillFocus )
    END_MSG_MAP()

private:
    LRESULT OnMouseWheel( UINT, WPARAM, LPARAM, BOOL & );
    LRESULT OnMouseMove( UINT, WPARAM, LPARAM, BOOL & );
    LRESULT OnRightButtonDown( UINT, WPARAM, LPARAM, BOOL & );
    LRESULT OnRightButtonUp( UINT, WPARAM, LPARAM, BOOL & );
    LRESULT OnLeftButtonDown( UINT, WPARAM, LPARAM, BOOL & );
    LRESULT OnLeftButtonUp( UINT, WPARAM, LPARAM, BOOL & );
    LRESULT OnDestroy( UINT, WPARAM, LPARAM, BOOL & );
    LRESULT OnSetFocus( UINT, WPARAM, LPARAM, BOOL & );
    LRESULT OnKillFocus( UINT, WPARAM, LPARAM, BOOL & );

public:
    HRESULT Advise( HWND hWnd, Watcher *pWatcher );
    HRESULT Unadvise();

/**
 * Call reset if you want to stop tracking the mouse in response
 * to a mouse event (e.g. a left-right click)
 **/
    void Reset();

private:
    struct ButtonRec
    {
        Path    path;
        bool    isTracking;

        ButtonRec() :
            path(),
            isTracking( false )
        {
        }
    };

    enum
    {
        Left  = 0,
        Right = 1,

        REC_COUNT
    };

public:
/**
 * RAII class to toggle the m_isSuspended flag. When the
 * Suspend object is constructed, m_isSuspended is set to true.
 * When the Suspend object is destroyed, m_isSuspened is set to
 * false.
 * The current state of the m_isSuspended is ignored, so Suspend 
 * objects shouldn't be used simultaneously.
 **/
    class Suspend
    {
    public:
        Suspend( MouseTracker &mouseTracker );
        ~Suspend();

    // not defined
    private:
        Suspend( const Suspend & );
        Suspend & operator = ( const Suspend & );

    private:
        bool    &isSuspended;
    };

    friend class Suspend;

private:
    void SetCapture();
    void ReleaseCapture();

    virtual MouseTrail * GetTrail();

private:
    ButtonRec   m_buttonRecs[ REC_COUNT ];
    bool        m_isBound;                  /// < are we bound to a subclassed window
    Watcher     *m_pWatcher;                /// < the object watching the mouse
    bool        m_isSuspended;              /// < is tracking suspended?
    bool        m_hasCapture;               /// < have we captured the mouse?
};

#endif // __INTERNETEXPLORERSINK_H_F2026BFC_F70F_46B5_A50E_896E4E022F83_

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


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

Comments and Discussions