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

 

相关文章:

  • 2022-01-27
  • 2022-12-23
  • 2021-10-29
  • 2021-08-31
  • 2021-07-14
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-01-25
  • 2021-07-31
  • 2022-01-27
  • 2022-12-23
相关资源
相似解决方案