MouseDevice.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reactive.Linq;
  5. using Avalonia.Input.Raw;
  6. using Avalonia.Interactivity;
  7. using Avalonia.Platform;
  8. using Avalonia.Utilities;
  9. using Avalonia.VisualTree;
  10. namespace Avalonia.Input
  11. {
  12. /// <summary>
  13. /// Represents a mouse device.
  14. /// </summary>
  15. public class MouseDevice : IMouseDevice, IDisposable
  16. {
  17. private int _clickCount;
  18. private Rect _lastClickRect;
  19. private ulong _lastClickTime;
  20. private readonly Pointer _pointer;
  21. private bool _disposed;
  22. private MouseButton _lastMouseDownButton;
  23. public MouseDevice(Pointer? pointer = null)
  24. {
  25. _pointer = pointer ?? new Pointer(Pointer.GetNextFreeId(), PointerType.Mouse, true);
  26. }
  27. public void ProcessRawEvent(RawInputEventArgs e)
  28. {
  29. if (!e.Handled && e is RawPointerEventArgs margs)
  30. ProcessRawEvent(margs);
  31. }
  32. int ButtonCount(PointerPointProperties props)
  33. {
  34. var rv = 0;
  35. if (props.IsLeftButtonPressed)
  36. rv++;
  37. if (props.IsMiddleButtonPressed)
  38. rv++;
  39. if (props.IsRightButtonPressed)
  40. rv++;
  41. if (props.IsXButton1Pressed)
  42. rv++;
  43. if (props.IsXButton2Pressed)
  44. rv++;
  45. return rv;
  46. }
  47. private void ProcessRawEvent(RawPointerEventArgs e)
  48. {
  49. e = e ?? throw new ArgumentNullException(nameof(e));
  50. var mouse = (MouseDevice)e.Device;
  51. if(mouse._disposed)
  52. return;
  53. var props = CreateProperties(e);
  54. var keyModifiers = e.InputModifiers.ToKeyModifiers();
  55. switch (e.Type)
  56. {
  57. case RawPointerEventType.LeaveWindow:
  58. case RawPointerEventType.NonClientLeftButtonDown:
  59. LeaveWindow();
  60. break;
  61. case RawPointerEventType.LeftButtonDown:
  62. case RawPointerEventType.RightButtonDown:
  63. case RawPointerEventType.MiddleButtonDown:
  64. case RawPointerEventType.XButton1Down:
  65. case RawPointerEventType.XButton2Down:
  66. if (ButtonCount(props) > 1)
  67. e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.IntermediatePoints, e.InputHitTestResult);
  68. else
  69. e.Handled = MouseDown(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult);
  70. break;
  71. case RawPointerEventType.LeftButtonUp:
  72. case RawPointerEventType.RightButtonUp:
  73. case RawPointerEventType.MiddleButtonUp:
  74. case RawPointerEventType.XButton1Up:
  75. case RawPointerEventType.XButton2Up:
  76. if (ButtonCount(props) != 0)
  77. e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.IntermediatePoints, e.InputHitTestResult);
  78. else
  79. e.Handled = MouseUp(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult);
  80. break;
  81. case RawPointerEventType.Move:
  82. e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.IntermediatePoints, e.InputHitTestResult);
  83. break;
  84. case RawPointerEventType.Wheel:
  85. e.Handled = MouseWheel(mouse, e.Timestamp, e.Root, e.Position, props, ((RawMouseWheelEventArgs)e).Delta, keyModifiers, e.InputHitTestResult);
  86. break;
  87. case RawPointerEventType.Magnify:
  88. e.Handled = GestureMagnify(mouse, e.Timestamp, e.Root, e.Position, props, ((RawPointerGestureEventArgs)e).Delta, keyModifiers, e.InputHitTestResult);
  89. break;
  90. case RawPointerEventType.Rotate:
  91. e.Handled = GestureRotate(mouse, e.Timestamp, e.Root, e.Position, props, ((RawPointerGestureEventArgs)e).Delta, keyModifiers, e.InputHitTestResult);
  92. break;
  93. case RawPointerEventType.Swipe:
  94. e.Handled = GestureSwipe(mouse, e.Timestamp, e.Root, e.Position, props, ((RawPointerGestureEventArgs)e).Delta, keyModifiers, e.InputHitTestResult);
  95. break;
  96. }
  97. }
  98. private void LeaveWindow()
  99. {
  100. }
  101. PointerPointProperties CreateProperties(RawPointerEventArgs args)
  102. {
  103. return new PointerPointProperties(args.InputModifiers, args.Type.ToUpdateKind());
  104. }
  105. private bool MouseDown(IMouseDevice device, ulong timestamp, IInputElement root, Point p,
  106. PointerPointProperties properties,
  107. KeyModifiers inputModifiers, IInputElement? hitTest)
  108. {
  109. device = device ?? throw new ArgumentNullException(nameof(device));
  110. root = root ?? throw new ArgumentNullException(nameof(root));
  111. var source = _pointer.Captured ?? root.InputHitTest(p);
  112. if (source != null)
  113. {
  114. _pointer.Capture(source);
  115. if (source != null)
  116. {
  117. var settings = AvaloniaLocator.Current.GetRequiredService<IPlatformSettings>();
  118. var doubleClickTime = settings.GetDoubleTapTime(PointerType.Mouse).TotalMilliseconds;
  119. var doubleClickSize = settings.GetDoubleTapSize(PointerType.Mouse);
  120. if (!_lastClickRect.Contains(p) || timestamp - _lastClickTime > doubleClickTime)
  121. {
  122. _clickCount = 0;
  123. }
  124. ++_clickCount;
  125. _lastClickTime = timestamp;
  126. _lastClickRect = new Rect(p, new Size())
  127. .Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2));
  128. _lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton();
  129. var e = new PointerPressedEventArgs(source, _pointer, (Visual)root, p, timestamp, properties, inputModifiers, _clickCount);
  130. source.RaiseEvent(e);
  131. return e.Handled;
  132. }
  133. }
  134. return false;
  135. }
  136. private bool MouseMove(IMouseDevice device, ulong timestamp, IInputRoot root, Point p,
  137. PointerPointProperties properties, KeyModifiers inputModifiers, Lazy<IReadOnlyList<RawPointerPoint>?>? intermediatePoints,
  138. IInputElement? hitTest)
  139. {
  140. device = device ?? throw new ArgumentNullException(nameof(device));
  141. root = root ?? throw new ArgumentNullException(nameof(root));
  142. var source = _pointer.Captured ?? hitTest;
  143. if (source is object)
  144. {
  145. var e = new PointerEventArgs(InputElement.PointerMovedEvent, source, _pointer, (Visual)root,
  146. p, timestamp, properties, inputModifiers, intermediatePoints);
  147. source.RaiseEvent(e);
  148. return e.Handled;
  149. }
  150. return false;
  151. }
  152. private bool MouseUp(IMouseDevice device, ulong timestamp, IInputRoot root, Point p, PointerPointProperties props,
  153. KeyModifiers inputModifiers, IInputElement? hitTest)
  154. {
  155. device = device ?? throw new ArgumentNullException(nameof(device));
  156. root = root ?? throw new ArgumentNullException(nameof(root));
  157. var source = _pointer.Captured ?? hitTest;
  158. if (source is not null)
  159. {
  160. var e = new PointerReleasedEventArgs(source, _pointer, (Visual)root, p, timestamp, props, inputModifiers,
  161. _lastMouseDownButton);
  162. source?.RaiseEvent(e);
  163. _pointer.Capture(null);
  164. return e.Handled;
  165. }
  166. return false;
  167. }
  168. private bool MouseWheel(IMouseDevice device, ulong timestamp, IInputRoot root, Point p,
  169. PointerPointProperties props,
  170. Vector delta, KeyModifiers inputModifiers, IInputElement? hitTest)
  171. {
  172. var rawDelta = delta;
  173. device = device ?? throw new ArgumentNullException(nameof(device));
  174. root = root ?? throw new ArgumentNullException(nameof(root));
  175. var source = _pointer.Captured ?? hitTest;
  176. if (source is not null)
  177. {
  178. var e = new PointerWheelEventArgs(source, _pointer, (Visual)root, p, timestamp, props, inputModifiers, delta);
  179. source?.RaiseEvent(e);
  180. return e.Handled;
  181. }
  182. return false;
  183. }
  184. private bool GestureMagnify(IMouseDevice device, ulong timestamp, IInputRoot root, Point p,
  185. PointerPointProperties props, Vector delta, KeyModifiers inputModifiers, IInputElement? hitTest)
  186. {
  187. device = device ?? throw new ArgumentNullException(nameof(device));
  188. root = root ?? throw new ArgumentNullException(nameof(root));
  189. var source = _pointer.Captured ?? hitTest;
  190. if (source != null)
  191. {
  192. var e = new PointerDeltaEventArgs(Gestures.PointerTouchPadGestureMagnifyEvent, source,
  193. _pointer, (Visual)root, p, timestamp, props, inputModifiers, delta);
  194. source?.RaiseEvent(e);
  195. return e.Handled;
  196. }
  197. return false;
  198. }
  199. private bool GestureRotate(IMouseDevice device, ulong timestamp, IInputRoot root, Point p,
  200. PointerPointProperties props, Vector delta, KeyModifiers inputModifiers, IInputElement? hitTest)
  201. {
  202. device = device ?? throw new ArgumentNullException(nameof(device));
  203. root = root ?? throw new ArgumentNullException(nameof(root));
  204. var source = _pointer.Captured ?? hitTest;
  205. if (source != null)
  206. {
  207. var e = new PointerDeltaEventArgs(Gestures.PointerTouchPadGestureRotateEvent, source,
  208. _pointer, (Visual)root, p, timestamp, props, inputModifiers, delta);
  209. source?.RaiseEvent(e);
  210. return e.Handled;
  211. }
  212. return false;
  213. }
  214. private bool GestureSwipe(IMouseDevice device, ulong timestamp, IInputRoot root, Point p,
  215. PointerPointProperties props, Vector delta, KeyModifiers inputModifiers, IInputElement? hitTest)
  216. {
  217. device = device ?? throw new ArgumentNullException(nameof(device));
  218. root = root ?? throw new ArgumentNullException(nameof(root));
  219. var source = _pointer.Captured ?? hitTest;
  220. if (source != null)
  221. {
  222. var e = new PointerDeltaEventArgs(Gestures.PointerTouchPadGestureSwipeEvent, source,
  223. _pointer, (Visual)root, p, timestamp, props, inputModifiers, delta);
  224. source?.RaiseEvent(e);
  225. return e.Handled;
  226. }
  227. return false;
  228. }
  229. public void Dispose()
  230. {
  231. _disposed = true;
  232. _pointer?.Dispose();
  233. }
  234. public IPointer? TryGetPointer(RawPointerEventArgs ev)
  235. {
  236. return _pointer;
  237. }
  238. }
  239. }