用Reactive Extensions快速实现鼠标手势功能

用Reactive Extensions快速实现鼠标手势功能

http://www.cnblogs.com/TianFang/archive/2011/08/12/2135633.html

鼠标手势非常方便,在很多程序中得到了广泛应用。在这里我要介绍一种通过用Reactive Extensions快速实现鼠标手势功能的方法,以供有需要的朋友参考。

一般用的那些只有上下左右的鼠标手势的识别原理并不复杂,只需要对鼠标轨迹进行定点采集,根据偏移的角度进行降噪处理,折换成上下左右四个方向即可。具体代码可以参考下文中的GetDirection方法(这个函数不是我写的,以前在网上找的,原始出处不记得了)。通过用Reactive extensions可以非常容易的实现这一过程。具体代码如下: 

复制代码
public partial class Form1 : Form {     public Form1()     {         InitializeComponent();
        Process();     }
    private void Process()     {         var mouseDown = Observable.FromEventPattern<MouseEventArgs>(this"MouseDown");         var mouseMove = Observable.FromEventPattern<MouseEventArgs>(this"MouseMove");         var mouseUp = Observable.FromEventPattern<MouseEventArgs>(this"MouseUp");
        var mousePath = mouseMove.SkipUntil(mouseDown).TakeUntil(mouseUp).Select(i => i.EventArgs.Location);
        mousePath.Take(1).Subscribe(_ => { }, () => label1.Text = "waitting for mouse up...");         ProcessMouseGesture(mousePath);     }
    void ProcessMouseGesture(IObservable<Point> mousePath)     {         //这里只是取0.1秒间隔作为采集点,不是很合适,还要把距离拿来一起算可能更精确一些         var points = mousePath.Sample(TimeSpan.FromSeconds(0.1));
        var directions = (from direction in points.Zip(points.Skip(1), (p1, p2) => GetDirection(p1, p2))                             where direction != MouseGestureDirection.Unknown                             select direction).DistinctUntilChanged();
        var directionList = new List<MouseGestureDirection>();         directions.Subscribe(d => directionList.Add(d), () =>             {                 label1.Text = string.Join(",", directionList.ToArray());                 Process();             });     }
    static MouseGestureDirection GetDirection(Point start, Point end)     {         const double maxAngleError = 30;
        int deltaX = end.X - start.X;         int deltaY = end.Y - start.Y;
        double length = Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
        double sin = deltaX / length;         double cos = deltaY / length;
        double angle = Math.Asin(Math.Abs(sin)) * 180 / Math.PI;
        if ((sin >= 0&& (cos < 0))             angle = 180 - angle;         else if ((sin < 0&& (cos < 0))             angle = angle + 180;         else if ((sin < 0&& (cos >= 0))             angle = 360 - angle;
        //direction recognition         if ((angle > 360 - maxAngleError) || (angle < 0 + maxAngleError))             return MouseGestureDirection.Down;         else if ((angle > 90 - maxAngleError) && (angle < 90 + maxAngleError))             return MouseGestureDirection.Right;         else if ((angle > 180 - maxAngleError) && (angle < 180 + maxAngleError))             return MouseGestureDirection.Up;         else if ((angle > 270 - maxAngleError) && (angle < 270 + maxAngleError))             return MouseGestureDirection.Left;         else return MouseGestureDirection.Unknown;     } }
enum MouseGestureDirection {     Unknown,     Up,     Right,     Down,     Left }
复制代码

由于我对Reactive Extensions不熟,只是偶尔有空的时候看了看,目前还属于管中窥豹阶段,上述代码并非最佳实践,本文这里只是给出了一种思路和方法,如果谁有更合适的实现,欢迎留言指正。

posted @ 2017-05-04 18:39  sky20080101  阅读(108)  评论(0)    收藏  举报