// TODO unify this with Android code private void OnMouseButtonChange(object sender, MouseButtonEventArgs e) { double now = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; float xConversion = SparrowSharpApp.Stage.Width / Size.Width; float yConversion = SparrowSharpApp.Stage.Height / Size.Height; Touch touchInFocus; if (e.Mouse.LeftButton == ButtonState.Pressed) { Touch newTouch = new Touch(); newTouch.TouchID = pointerId; newTouch.TimeStamp = now; newTouch.GlobalX = e.Mouse.X * xConversion; newTouch.GlobalY = e.Mouse.Y * yConversion; newTouch.InitialGlobalX = newTouch.GlobalX; newTouch.InitialGlobalY = newTouch.GlobalY; newTouch.Phase = TouchPhase.Began; Point touchPosition = Point.Create(newTouch.GlobalX, newTouch.GlobalY); newTouch.Target = SparrowSharpApp.Stage.HitTestPoint(touchPosition); _touches.Add(newTouch.TouchID, newTouch); } else { touchInFocus = _touches[pointerId]; touchInFocus.Phase = TouchPhase.Ended; long downTime = -1; // TODO touchInFocus.TimeStamp = now; double dist = Math.Sqrt( (touchInFocus.GlobalX - touchInFocus.InitialGlobalX) * (touchInFocus.GlobalX - touchInFocus.InitialGlobalX) + (touchInFocus.GlobalY - touchInFocus.InitialGlobalY) * (touchInFocus.GlobalY - touchInFocus.InitialGlobalY)); // TODO: move the time out to a constant, make dist DPI dependent if (downTime < 300 && dist < 50) { touchInFocus.IsTap = true; } } processTouch(); }
/// <summary> /// This function handles touch events. /// It is responsible for maintaining the currently active touch events and dispatching events. /// For details see http://developer.android.com/reference/android/view/View.html#onTouchEvent(android.view.MotionEvent) /// </summary> override public bool OnTouchEvent(MotionEvent e) { float xConversion = SparrowSharpApp.Stage.Width / Size.Width; float yConversion = SparrowSharpApp.Stage.Height / Size.Height; // get pointer index from the event object int pointerIndex = e.ActionIndex; Touch touchInFocus; // get pointer ID int pointerId = e.GetPointerId(pointerIndex); double now = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; // get masked (not specific to a pointer) action MotionEventActions maskedAction = e.ActionMasked; switch (maskedAction) { case MotionEventActions.Down: case MotionEventActions.PointerDown: // new pointer Touch newTouch = new Touch(); newTouch.TouchID = pointerId; newTouch.TimeStamp = now; newTouch.GlobalX = e.GetX() * xConversion; newTouch.GlobalY = e.GetY() * yConversion; newTouch.InitialGlobalX = newTouch.GlobalX; newTouch.InitialGlobalY = newTouch.GlobalY; newTouch.Phase = TouchPhase.Began; Point touchPosition = Point.Create(newTouch.GlobalX, newTouch.GlobalY); newTouch.Target = SparrowSharpApp.Stage.HitTestPoint(touchPosition); _touches.Add(newTouch.TouchID, newTouch); break; case MotionEventActions.Move: for (int size = e.PointerCount, i = 0; i < size; i++) { Touch movedTouch; _touches.TryGetValue(e.GetPointerId(i), out movedTouch); if (movedTouch != null) { // TODO: should we care about historical pointer events? movedTouch.PreviousGlobalX = movedTouch.GlobalX; movedTouch.PreviousGlobalY = movedTouch.GlobalY; movedTouch.TimeStamp = now; float xc = e.GetX(i) * xConversion; float yc = e.GetY(i) * yConversion; if (movedTouch.GlobalX == xc && movedTouch.GlobalY == yc) { movedTouch.Phase = TouchPhase.Stationary; } else { movedTouch.GlobalX = xc; movedTouch.GlobalY = yc; movedTouch.Phase = TouchPhase.Moved; } if (movedTouch.Target == null || movedTouch.Target.Stage == null) { // target could have been removed from stage -> find new target in that case Point updatedTouchPosition = Point.Create(movedTouch.GlobalX, movedTouch.GlobalY); movedTouch.Target = SparrowSharpApp.Root.HitTestPoint(updatedTouchPosition); } } } break; case MotionEventActions.Up: case MotionEventActions.PointerUp: touchInFocus = _touches[pointerId]; touchInFocus.Phase = TouchPhase.Ended; long downTime = Android.OS.SystemClock.UptimeMillis() - e.DownTime; touchInFocus.TimeStamp = now; double dist = Math.Sqrt( (touchInFocus.GlobalX - touchInFocus.InitialGlobalX) * (touchInFocus.GlobalX - touchInFocus.InitialGlobalX) + (touchInFocus.GlobalY - touchInFocus.InitialGlobalY) * (touchInFocus.GlobalY - touchInFocus.InitialGlobalY)); // TODO: move the time out to a constant, make dist DPI dependent if (downTime < 300 && dist < 50) { touchInFocus.IsTap = true; } break; case MotionEventActions.Cancel: touchInFocus = _touches[pointerId]; touchInFocus.Phase = TouchPhase.Cancelled; break; } foreach (Touch tou in _touches.Values) { TouchEvent touchEvent = new TouchEvent(new List<Touch>(_touches.Values)); if (tou.Target != null) { tou.Target.InvokeTouch(touchEvent); } //Console.WriteLine ("phase:" + tou.Phase + " ID:" + tou.TouchID + // " target:" + tou.Target + " isTap:"+ tou.IsTap + " timestamp:" + tou.TimeStamp); } var touchList = new List<Touch>(_touches.Values); foreach (Touch tou in touchList) { if (tou.Phase == TouchPhase.Ended || tou.Phase == TouchPhase.Cancelled) { _touches.Remove(tou.TouchID); } } return true; }
void processTouches(UIEvent evt) { if (_lastTouchTimestamp != evt.Timestamp) { SizeF size = Bounds.Size; float xConversion = SparrowSharpApp.Stage.Width / size.Width; float yConversion = SparrowSharpApp.Stage.Height / size.Height; // convert to Touches and forward to stage List<Touch> touches = new List<Touch>(); double now = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; foreach (UITouch uiTouch in evt.TouchesForView(this)) { PointF location = uiTouch.LocationInView(this); PointF previousLocation = uiTouch.PreviousLocationInView(this); Touch touch = new Touch(); touch.TouchID = uiTouch.Handle.ToInt32(); touch.TimeStamp = now; touch.GlobalX = location.X * xConversion; touch.GlobalY = location.Y * yConversion; touch.PreviousGlobalX = previousLocation.X * xConversion; touch.PreviousGlobalY = previousLocation.Y * yConversion; if (uiTouch.Phase == UITouchPhase.Began) { touch.InitialGlobalX = touch.GlobalX; touch.InitialGlobalY = touch.GlobalY; } touch.IsTap = (uiTouch.TapCount != 0); touch.Phase = (TouchPhase) uiTouch.Phase; touches.Add(touch); } _touchProcessor.ProcessTouches(touches); _lastTouchTimestamp = evt.Timestamp; } }