Click here to Skip to main content
15,892,005 members
Articles / Desktop Programming / Windows Forms

Aero Shake

Rate me:
Please Sign up or sign in to vote.
4.00/5 (3 votes)
9 May 2009CPOL7 min read 45K   691   20  
Implement the Windows 7 Aero Shake feature in .NET WinForms.
//====================================================
//| Downloaded From                                  |
//| Visual C# Kicks - http://www.vcskicks.com/       |
//| License - http://www.vcskicks.com/license.html   |
//====================================================
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace WindowShake
{
    public class ShakeForm : Form
    {
        const int WM_NCMOUSEMOVE = 0xA0;
        const int WM_NCLBUTTONDOWN = 0xA1;
        const int WM_NCRBUTTONDOWN = 0xA4;
        const int WM_WINDOWPOSCHANGED = 0x0047;

        private bool captureMovement;
        private DateTime captureStart;
        private DateTime captureEnd;
        private List<Point> movements;

        public event EventHandler FormShaken;

        protected override void WndProc(ref Message m)
        {
            //Set primary mouse button
            int mouseButton = SystemInformation.MouseButtonsSwapped ? WM_NCRBUTTONDOWN : WM_NCLBUTTONDOWN;

            if (m.Msg == mouseButton) //Mouse Down
            {
                //Start capturing window movements
                captureStart = DateTime.Now;
                captureMovement = true;
            }
            else if (captureMovement && m.Msg == WM_NCMOUSEMOVE) //Left Mouse Up
            {
                //Stop capturing window movements
                captureEnd = DateTime.Now;
                captureMovement = false;

                //Process movement data
                ProcessMovement();
            }

            if (m.Msg == WM_WINDOWPOSCHANGED)
            {
                if (captureMovement)
                {
                    //Initialize movement list
                    if (movements == null)
                        movements = new List<Point>();

                    //Store current position
                    movements.Add(new Point(this.Left, this.Top));
                }
            }

            base.WndProc(ref m);
        }

        private void ProcessMovement()
        {
            if (this.WasShaken() && FormShaken != null)
                FormShaken(this, EventArgs.Empty);

            //Reset Markers
            movements.Clear();
            movements = null;
            captureStart = DateTime.MinValue;
            captureEnd = DateTime.MinValue;
        }

        private bool WasShaken()
        {
            if (movements != null)
            {
                //Calculate average point from all the collected positions
                Point avg = GetAveragePoint(movements);

                //Calculate difference of average point to current position
                Point deltaPoint = new Point();
                deltaPoint.X = this.Left - avg.X;
                deltaPoint.Y = this.Top - avg.Y;

                //Calculate the number of milliseconds that spanned while the window moved
                //Note: Only uses seconds and milliseconds
                TimeSpan movementTime = captureEnd.Subtract(captureStart);
                int msSpan = (movementTime.Seconds * 1000 + movementTime.Milliseconds);

                //If values fall within a certain range, then the window was shaken
                return msSpan <= 600 && //speed of the shake in milliseconds
                       movements.Count >= 30 && //amount of movements in the shake
                       Math.Abs(deltaPoint.X) <= 30 && Math.Abs(deltaPoint.Y) <= 30; //average "size" of shake
            }

            return false;
        }

        private Point GetAveragePoint(List<Point> points)
        {
            Point avg = new Point();
            foreach (Point p in points)
            {
                avg.X += p.X;
                avg.Y += p.Y;
            }

            avg.X /= points.Count;
            avg.Y /= points.Count;

            return avg;
        }
    }
}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Visit Visual C# Kicks for more free C#.NET articles, resources, and downloads at
http://www.vcskicks.com

Comments and Discussions