PageRenderTime 41ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/toolkit/Microsoft.Phone.Controls.Toolkit/Input/GestureListenerStatic.cs

https://bitbucket.org/jeremejevs/word-steps
C# | 367 lines | 268 code | 57 blank | 42 comment | 59 complexity | 7d18b10a2fa2a82bbe2e7f73d0ea78bf MD5 | raw file
  1. // (c) Copyright Microsoft Corporation.
  2. // This source is subject to the Microsoft Public License (Ms-PL).
  3. // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  4. // All other rights reserved.
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Windows;
  8. using System.Windows.Controls;
  9. using System.Windows.Input;
  10. using System.Windows.Media;
  11. using System.Windows.Threading;
  12. using Microsoft.Xna.Framework.Input.Touch;
  13. namespace Microsoft.Phone.Controls
  14. {
  15. /// <summary>
  16. /// The GestureListener class raises events similar to those provided by the XNA TouchPanel, but it is designed for
  17. /// Silverlight's event-driven model, rather than XNA's loop/polling model, and it also takes care of the hit testing
  18. /// and event routing.
  19. /// </summary>
  20. public partial class GestureListener
  21. {
  22. private static DispatcherTimer _timer;
  23. private static bool _isInTouch;
  24. private static List<UIElement> _elements;
  25. private static Point _gestureOrigin;
  26. private static bool _gestureOriginChanged;
  27. private static Nullable<Orientation> _gestureOrientation;
  28. private static Point _cumulativeDelta;
  29. private static Point _cumulativeDelta2;
  30. private static Point _finalVelocity;
  31. private static Point _pinchOrigin;
  32. private static Point _pinchOrigin2;
  33. private static Point _lastSamplePosition;
  34. private static Point _lastSamplePosition2;
  35. private static bool _isPinching;
  36. private static bool _flicked;
  37. private static bool _isDragging;
  38. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification="Need static ctor for more than instantiation")]
  39. static GestureListener()
  40. {
  41. Touch.FrameReported += new TouchFrameEventHandler(Touch_FrameReported);
  42. TouchPanel.EnabledGestures =
  43. GestureType.Tap |
  44. GestureType.DoubleTap |
  45. GestureType.Hold |
  46. GestureType.FreeDrag |
  47. GestureType.DragComplete |
  48. GestureType.Flick |
  49. GestureType.Pinch |
  50. GestureType.PinchComplete;
  51. _timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(100) };
  52. _timer.Tick += new EventHandler(OnTimerTick);
  53. }
  54. /// <summary>
  55. /// Handle touch events.
  56. /// </summary>
  57. /// <param name="sender"></param>
  58. /// <param name="e"></param>
  59. private static void Touch_FrameReported(object sender, TouchFrameEventArgs e)
  60. {
  61. bool newIsInTouch = false;
  62. Point gestureOrigin = new Point(0,0);
  63. foreach (TouchPoint point in e.GetTouchPoints(null))
  64. {
  65. if (point.Action != TouchAction.Up)
  66. {
  67. gestureOrigin = point.Position;
  68. newIsInTouch = true;
  69. break;
  70. }
  71. }
  72. if (!_isInTouch && newIsInTouch)
  73. {
  74. // The user was not in the middle of a gesture, but one has started.
  75. _gestureOrigin = gestureOrigin;
  76. TouchStart();
  77. }
  78. else if (_isInTouch && !newIsInTouch)
  79. {
  80. // The user was in the middle of a gesture, but there are no active
  81. // touch points anymore.
  82. TouchComplete();
  83. }
  84. else if (_isInTouch)
  85. {
  86. // The state has not changed, and the user was in the middle of a gesture.
  87. TouchDelta();
  88. }
  89. else
  90. {
  91. // Possible error condition? The user was not in the middle of a
  92. // gesture, but a Touch.FrameReported event was received with no
  93. // active touch points. We should poll the TouchPanel just to be
  94. // safe, but do so in such a way that resets the state.
  95. TouchStart();
  96. }
  97. _isInTouch = newIsInTouch;
  98. }
  99. /// <summary>
  100. /// A touch has started.
  101. /// </summary>
  102. private static void TouchStart()
  103. {
  104. _cumulativeDelta.X = _cumulativeDelta.Y = _cumulativeDelta2.X = _cumulativeDelta2.Y = 0;
  105. _finalVelocity.X = _finalVelocity.Y = 0;
  106. _isDragging = _flicked = false;
  107. _elements = new List<UIElement>(VisualTreeHelper.FindElementsInHostCoordinates(_gestureOrigin, Application.Current.RootVisual));
  108. _gestureOriginChanged = false;
  109. RaiseGestureEvent((helper) => helper.GestureBegin, () => new GestureEventArgs(_gestureOrigin, _gestureOrigin), false);
  110. ProcessTouchPanelEvents();
  111. _timer.Start();
  112. }
  113. /// <summary>
  114. /// A touch is continuing...
  115. /// </summary>
  116. private static void TouchDelta()
  117. {
  118. ProcessTouchPanelEvents();
  119. }
  120. /// <summary>
  121. /// A touch has ended.
  122. /// </summary>
  123. private static void TouchComplete()
  124. {
  125. ProcessTouchPanelEvents();
  126. RaiseGestureEvent((helper) => helper.GestureCompleted, () => new GestureEventArgs(_gestureOrigin, _lastSamplePosition), false);
  127. _elements = null;
  128. _gestureOrientation = null;
  129. _timer.Stop();
  130. }
  131. static void OnTimerTick(object sender, EventArgs e)
  132. {
  133. ProcessTouchPanelEvents();
  134. }
  135. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  136. private static void ProcessTouchPanelEvents()
  137. {
  138. Point delta = new Point(0, 0);
  139. GeneralTransform deltaTransform = null;
  140. while (TouchPanel.IsGestureAvailable)
  141. {
  142. GestureSample sample = TouchPanel.ReadGesture();
  143. Point samplePosition = sample.Position.ToPoint();
  144. Point samplePosition2 = sample.Position2.ToPoint();
  145. Point sampleDelta = sample.Delta.ToPoint();
  146. GetTranslatedDelta(ref deltaTransform, ref sampleDelta, ref _cumulativeDelta, sample.GestureType != GestureType.Flick);
  147. Point sampleDelta2 = sample.Delta2.ToPoint();
  148. GetTranslatedDelta(ref deltaTransform, ref sampleDelta2, ref _cumulativeDelta2, sample.GestureType != GestureType.Flick);
  149. // Example: if a drag becomes a pinch, or vice-versa, we want to change the elements receiving the event
  150. if (_elements == null || _gestureOriginChanged)
  151. {
  152. _gestureOrigin = samplePosition;
  153. _elements = new List<UIElement>(VisualTreeHelper.FindElementsInHostCoordinates(_gestureOrigin, Application.Current.RootVisual));
  154. _gestureOriginChanged = false;
  155. }
  156. if (!_gestureOrientation.HasValue && (sampleDelta.X != 0 || sampleDelta.Y != 0))
  157. {
  158. _gestureOrientation = Math.Abs(sampleDelta.X) >= Math.Abs(sampleDelta.Y) ? Orientation.Horizontal : Orientation.Vertical;
  159. }
  160. switch (sample.GestureType)
  161. {
  162. case GestureType.Tap:
  163. RaiseGestureEvent((helper) => helper.Tap, () => new GestureEventArgs(_gestureOrigin, samplePosition), false);
  164. break;
  165. case GestureType.DoubleTap:
  166. RaiseGestureEvent((helper) => helper.DoubleTap, () => new GestureEventArgs(_gestureOrigin, samplePosition), false);
  167. break;
  168. case GestureType.Hold:
  169. RaiseGestureEvent((helper) => helper.Hold, () => new GestureEventArgs(_gestureOrigin, samplePosition), false);
  170. break;
  171. case GestureType.FreeDrag:
  172. if (sampleDelta.X != 0 || sampleDelta.Y != 0)
  173. {
  174. if (!_isDragging)
  175. {
  176. RaiseGestureEvent((helper) => helper.DragStarted, () => new DragStartedGestureEventArgs(_gestureOrigin, _gestureOrientation.Value), true);
  177. _isDragging = true;
  178. }
  179. delta.X += sampleDelta.X;
  180. delta.Y += sampleDelta.Y;
  181. _lastSamplePosition = samplePosition;
  182. }
  183. break;
  184. case GestureType.DragComplete:
  185. if (!_flicked)
  186. {
  187. if (delta.X != 0 || delta.Y != 0)
  188. {
  189. // raise drag
  190. RaiseGestureEvent((helper) => helper.DragDelta, () => new DragDeltaGestureEventArgs(_gestureOrigin, samplePosition, delta, _gestureOrientation.Value), false);
  191. delta.X = delta.Y = 0;
  192. }
  193. }
  194. if (_isDragging)
  195. {
  196. RaiseGestureEvent((helper) => helper.DragCompleted, () => new DragCompletedGestureEventArgs(_gestureOrigin, _lastSamplePosition, _cumulativeDelta, _gestureOrientation.Value, _finalVelocity), false);
  197. delta.X = delta.Y = 0;
  198. }
  199. _cumulativeDelta.X = _cumulativeDelta.Y = 0;
  200. _flicked = _isDragging = false;
  201. _gestureOriginChanged = true;
  202. break;
  203. case GestureType.Flick:
  204. // Do not raise any additional drag events that may be queued.
  205. _flicked = true;
  206. _finalVelocity = sampleDelta;
  207. RaiseGestureEvent((helper) => helper.Flick, () => new FlickGestureEventArgs(_gestureOrigin, sampleDelta), true);
  208. break;
  209. case GestureType.Pinch:
  210. {
  211. if (!_isPinching)
  212. {
  213. _isPinching = true;
  214. _pinchOrigin = samplePosition;
  215. _pinchOrigin2 = samplePosition2;
  216. RaiseGestureEvent((helper) => helper.PinchStarted, () => new PinchStartedGestureEventArgs(_pinchOrigin, _pinchOrigin2, _pinchOrigin, _pinchOrigin2), true);
  217. }
  218. _lastSamplePosition = samplePosition;
  219. _lastSamplePosition2 = samplePosition2;
  220. RaiseGestureEvent((helper) => helper.PinchDelta, () => new PinchGestureEventArgs(_pinchOrigin, _pinchOrigin2, samplePosition, samplePosition2), false);
  221. }
  222. break;
  223. case GestureType.PinchComplete:
  224. _isPinching = false;
  225. RaiseGestureEvent((helper) => helper.PinchCompleted, () => new PinchGestureEventArgs(_pinchOrigin, _pinchOrigin2, _lastSamplePosition, _lastSamplePosition2), false);
  226. _cumulativeDelta.X = _cumulativeDelta.Y = _cumulativeDelta2.X = _cumulativeDelta2.Y = 0;
  227. _gestureOriginChanged = true;
  228. break;
  229. }
  230. }
  231. if (!_flicked && (delta.X != 0 || delta.Y != 0))
  232. {
  233. RaiseGestureEvent((helper) => helper.DragDelta, () => new DragDeltaGestureEventArgs(_gestureOrigin, _lastSamplePosition, delta, _gestureOrientation.Value), false);
  234. }
  235. }
  236. private static void GetTranslatedDelta(ref GeneralTransform deltaTransform, ref Point sampleDelta, ref Point cumulativeDelta, bool addToCumulative)
  237. {
  238. if (sampleDelta.X != 0 || sampleDelta.Y != 0)
  239. {
  240. if (deltaTransform == null)
  241. {
  242. deltaTransform = GetInverseRootTransformNoOffset();
  243. }
  244. sampleDelta = deltaTransform.Transform(sampleDelta);
  245. if (addToCumulative)
  246. {
  247. cumulativeDelta.X += sampleDelta.X;
  248. cumulativeDelta.Y += sampleDelta.Y;
  249. }
  250. }
  251. }
  252. private static GeneralTransform GetInverseRootTransformNoOffset()
  253. {
  254. GeneralTransform transform = Application.Current.RootVisual.TransformToVisual(null).Inverse;
  255. MatrixTransform matrixTransform = transform as MatrixTransform;
  256. if (matrixTransform != null)
  257. {
  258. Matrix matrix = matrixTransform.Matrix;
  259. matrix.OffsetX = matrix.OffsetY = 0;
  260. matrixTransform.Matrix = matrix;
  261. }
  262. return transform;
  263. }
  264. /// <summary>
  265. /// This method does all the necessary work to raise a gesture event. It sets the orginal source, does the routing,
  266. /// handles Handled, and only creates the event args if they are needed.
  267. /// </summary>
  268. /// <typeparam name="T">This is the type of event args that will be raised.</typeparam>
  269. /// <param name="eventGetter">Gets the specific event to raise.</param>
  270. /// <param name="argsGetter">Lazy creator function for the event args.</param>
  271. /// <param name="releaseMouseCapture">Indicates whether the mouse capture should be released </param>
  272. private static void RaiseGestureEvent<T>(Func<GestureListener, EventHandler<T>> eventGetter, Func<T> argsGetter, bool releaseMouseCapture) where T : GestureEventArgs
  273. {
  274. T args = null;
  275. FrameworkElement originalSource = null;
  276. bool handled = false;
  277. foreach (FrameworkElement element in _elements)
  278. {
  279. if (releaseMouseCapture)
  280. {
  281. element.ReleaseMouseCapture();
  282. }
  283. if (!handled)
  284. {
  285. if (originalSource == null)
  286. {
  287. originalSource = element;
  288. }
  289. GestureListener helper = GestureService.GetGestureListenerInternal(element, false);
  290. if (helper != null)
  291. {
  292. SafeRaise.Raise(eventGetter(helper), element, () =>
  293. {
  294. if (args == null)
  295. {
  296. args = argsGetter();
  297. args.OriginalSource = originalSource;
  298. }
  299. return args;
  300. });
  301. }
  302. if (args != null && args.Handled == true)
  303. {
  304. handled = true;
  305. }
  306. }
  307. }
  308. }
  309. }
  310. }