| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- // -----------------------------------------------------------------------
- // <copyright file="MouseDevice.cs" company="Steven Kirk">
- // Copyright 2014 MIT Licence. See licence.md for more information.
- // </copyright>
- // -----------------------------------------------------------------------
- namespace Perspex.Input
- {
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reactive.Linq;
- using Perspex.Input.Raw;
- using Perspex.Interactivity;
- using Perspex.Platform;
- using Perspex.VisualTree;
- using Splat;
- public abstract class MouseDevice : IMouseDevice
- {
- private int clickCount;
- private Rect lastClickRect;
- private uint lastClickTime;
- private List<IInputElement> pointerOvers = new List<IInputElement>();
- public MouseDevice()
- {
- this.InputManager.RawEventReceived
- .OfType<RawMouseEventArgs>()
- .Where(x => x.Device == this)
- .Subscribe(this.ProcessRawEvent);
- }
- public static IMouseDevice Instance
- {
- get { return Locator.Current.GetService<IMouseDevice>(); }
- }
- public IInputElement Captured
- {
- get;
- protected set;
- }
- public IInputManager InputManager
- {
- get { return Locator.Current.GetService<IInputManager>(); }
- }
- public Point Position
- {
- get;
- protected set;
- }
- public virtual void Capture(IInputElement control)
- {
- this.Captured = control;
- }
- public Point GetPosition(IVisual relativeTo)
- {
- Point p = this.Position;
- IVisual v = relativeTo;
- while (v != null)
- {
- p -= v.Bounds.Position;
- v = v.VisualParent;
- }
- return p;
- }
- private void ProcessRawEvent(RawMouseEventArgs e)
- {
- var mouse = (IMouseDevice)e.Device;
- this.Position = e.Position;
- switch (e.Type)
- {
- case RawMouseEventType.LeaveWindow:
- this.LeaveWindow(mouse, e.Root);
- break;
- case RawMouseEventType.LeftButtonDown:
- this.MouseDown(mouse, e.Timestamp, e.Root, e.Position);
- break;
- case RawMouseEventType.LeftButtonUp:
- this.MouseUp(mouse, e.Root, e.Position);
- break;
- case RawMouseEventType.Move:
- this.MouseMove(mouse, e.Root, e.Position);
- break;
- case RawMouseEventType.Wheel:
- this.MouseWheel(mouse, e.Root, e.Position, ((RawMouseWheelEventArgs)e).Delta);
- break;
- }
- }
- private void LeaveWindow(IMouseDevice device, IInputElement root)
- {
- this.ClearPointerOver(this);
- }
- private void MouseDown(IMouseDevice device, uint timestamp, IInputElement root, Point p)
- {
- var hit = this.HitTest(root, p);
- if (hit != null)
- {
- IInteractive source = this.GetSource(hit);
- if (source != null)
- {
- var settings = Locator.Current.GetService<IPlatformSettings>();
- var doubleClickTime = settings.DoubleClickTime.TotalMilliseconds;
- if (!this.lastClickRect.Contains(p) || timestamp - this.lastClickTime > doubleClickTime)
- {
- this.clickCount = 0;
- }
- ++this.clickCount;
- this.lastClickTime = timestamp;
- this.lastClickRect = new Rect(p, new Size())
- .Inflate(new Thickness(settings.DoubleClickSize.Width / 2, settings.DoubleClickSize.Height / 2));
- var e = new PointerPressEventArgs
- {
- Device = this,
- RoutedEvent = InputElement.PointerPressedEvent,
- Source = source,
- ClickCount = this.clickCount,
- };
- source.RaiseEvent(e);
- }
- }
- }
- private void MouseMove(IMouseDevice device, IInputElement root, Point p)
- {
- IInteractive source;
- if (this.Captured == null)
- {
- this.SetPointerOver(this, root, p);
- source = root as IInteractive;
- }
- else
- {
- Point offset = new Point();
- foreach (IVisual ancestor in this.Captured.GetVisualAncestors())
- {
- offset += ancestor.Bounds.Position;
- }
- this.SetPointerOver(this, this.Captured, p - offset);
- source = this.Captured as IInteractive;
- }
- if (source != null)
- {
- source.RaiseEvent(new PointerEventArgs
- {
- Device = this,
- RoutedEvent = InputElement.PointerMovedEvent,
- Source = source,
- });
- }
- }
- private void MouseUp(IMouseDevice device, IInputElement root, Point p)
- {
- var hit = this.HitTest(root, p);
- if (hit != null)
- {
- IInteractive source = this.GetSource(hit);
- if (source != null)
- {
- source.RaiseEvent(new PointerEventArgs
- {
- Device = this,
- RoutedEvent = InputElement.PointerReleasedEvent,
- Source = source,
- });
- }
- }
- }
- private void MouseWheel(IMouseDevice device, IInputElement root, Point p, Vector delta)
- {
- var hit = this.HitTest(root, p);
- if (hit != null)
- {
- IInteractive source = this.GetSource(hit);
- if (source != null)
- {
- source.RaiseEvent(new PointerWheelEventArgs
- {
- Device = this,
- RoutedEvent = InputElement.PointerWheelChangedEvent,
- Source = source,
- Delta = delta,
- });
- }
- }
- }
- private IInteractive GetSource(IVisual hit)
- {
- return this.Captured ??
- (hit as IInteractive) ??
- hit.GetSelfAndVisualAncestors().OfType<IInteractive>().FirstOrDefault();
- }
- private IInputElement HitTest(IInputElement root, Point p)
- {
- return this.Captured ?? root.InputHitTest(p);
- }
- private void ClearPointerOver(IPointerDevice device)
- {
- foreach (var control in this.pointerOvers.ToList())
- {
- PointerEventArgs e = new PointerEventArgs
- {
- RoutedEvent = InputElement.PointerLeaveEvent,
- Device = device,
- Source = control,
- };
- this.pointerOvers.Remove(control);
- control.RaiseEvent(e);
- }
- }
- private void SetPointerOver(IPointerDevice device, IInputElement element, Point p)
- {
- IEnumerable<IInputElement> hits = element.GetInputElementsAt(p);
- foreach (var control in this.pointerOvers.Except(hits).ToList())
- {
- PointerEventArgs e = new PointerEventArgs
- {
- RoutedEvent = InputElement.PointerLeaveEvent,
- Device = device,
- Source = control,
- };
- this.pointerOvers.Remove(control);
- control.RaiseEvent(e);
- }
- foreach (var control in hits.Except(this.pointerOvers))
- {
- PointerEventArgs e = new PointerEventArgs
- {
- RoutedEvent = InputElement.PointerEnterEvent,
- Device = device,
- Source = control,
- };
- this.pointerOvers.Add(control);
- control.RaiseEvent(e);
- }
- }
- }
- }
|