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

鼠标手势非常方便,在很多程序中得到了广泛应用。在这里我要介绍一种通过用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不熟,只是偶尔有空的时候看了看,目前还属于管中窥豹阶段,上述代码并非最佳实践,本文这里只是给出了一种思路和方法,如果谁有更合适的实现,欢迎留言指正。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值