用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
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