Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Input / TouchDevice.cs / 1305600 / TouchDevice.cs
//----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//---------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;
using System.Security;
using System.Security.Permissions;
using MS.Internal;
using MS.Internal.KnownBoxes;
using MS.Internal.PresentationCore;
using MS.Utility;
using SR = MS.Internal.PresentationCore.SR;
using SRID = MS.Internal.PresentationCore.SRID;
namespace System.Windows.Input
{
///
/// Represents a touch device (i.e. a finger).
///
///
/// InheritanceDemand - Prevents subclassing TouchDevice from partial trust code.
/// This is for defense in depth since there is no scenario where partial trust code
/// needs to inherit from this class.
///
[UIPermission(SecurityAction.InheritanceDemand, Unrestricted = true)]
public abstract class TouchDevice : InputDevice, IManipulator
{
///
/// Instantiates a new instance of this class.
///
///
/// The ID of this device.
/// For a particular subclass of TouchDevice, ID should be unique.
/// Note: This is not validated to be unique.
///
///
/// Critical: Retrieves an InputManager instance.
/// PublicOK: Does not expose the InputManager.
///
[SecurityCritical]
protected TouchDevice(int deviceId)
: base()
{
_deviceId = deviceId;
_inputManager = InputManager.UnsecureCurrent;
}
///
/// Critical: Attaches to InputManager event handlers.
/// TreatAsSafe: Does not expose the InputManager.
///
[SecurityCritical, SecurityTreatAsSafe]
private void AttachTouchDevice()
{
_inputManager.PostProcessInput += new ProcessInputEventHandler(PostProcessInput);
_inputManager.HitTestInvalidatedAsync += new EventHandler(OnHitTestInvalidatedAsync);
}
///
/// Critical: Detaches from InputManager event handlers.
/// TreatAsSafe: Does not expose the InputManager.
///
[SecurityCritical, SecurityTreatAsSafe]
private void DetachTouchDevice()
{
_inputManager.PostProcessInput -= new ProcessInputEventHandler(PostProcessInput);
_inputManager.HitTestInvalidatedAsync -= new EventHandler(OnHitTestInvalidatedAsync);
}
///
/// The ID of this device.
/// For a particular subclass of TouchDevice, ID should be unique.
///
public int Id
{
get { return _deviceId; }
}
///
/// This event will be raised whenever the device gets activated
///
public event EventHandler Activated;
///
/// This event will be raised whenever the device gets deactivated
///
public event EventHandler Deactivated;
///
/// IsActive boolean
///
public bool IsActive
{
get
{
return _isActive;
}
}
#region InputDevice
///
/// Returns the element that input from this device is sent to.
///
///
/// Always the same value as DirectlyOver.
///
public sealed override IInputElement Target
{
get { return _directlyOver; }
}
///
/// Returns the PresentationSource that is reporting input for this device.
///
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
/// Subclasses should use SetActiveSource to set this property.
///
///
/// Critical - Accesses critical data (_activeSource)
/// PublicOK - There is a demand.
///
public sealed override PresentationSource ActiveSource
{
[SecurityCritical]
get
{
SecurityHelper.DemandUIWindowPermission();
return _activeSource;
}
}
///
/// Critical - PresentationSource is critical data.
/// PublicOK - This method has a link demand.
///
[SecurityCritical]
[UIPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
protected void SetActiveSource(PresentationSource activeSource)
{
_activeSource = activeSource;
}
#endregion
#region Location
///
/// Returns the element that this device is over.
///
public IInputElement DirectlyOver
{
get { return _directlyOver; }
}
///
/// Provides the current position.
///
/// Defines the coordinate space.
/// The current position in the coordinate space of relativeTo.
public abstract TouchPoint GetTouchPoint(IInputElement relativeTo);
///
/// Provides all of the known points the device hit since the last reported position update.
///
/// Defines the coordinate space.
/// A list of points in the coordinate space of relativeTo.
public abstract TouchPointCollection GetIntermediateTouchPoints(IInputElement relativeTo);
///
/// Critical - Access _activeSource.
/// TreatAsSafe - Does not expose _activeSource.
///
[SecurityCritical, SecurityTreatAsSafe]
private IInputElement CriticalHitTest(Point point, bool isSynchronize)
{
IInputElement over = null;
if (_activeSource != null)
{
switch (_captureMode)
{
case CaptureMode.None:
// No capture, do a regular hit-test.
if (_isDown)
{
if (isSynchronize)
{
// In a synchronize call, we need to hit-test the window in addition to the element
over = GlobalHitTest(point, _activeSource);
}
else
{
// Just hit-test the element
over = LocalHitTest(point, _activeSource);
}
EnsureValid(ref over);
}
break;
case CaptureMode.Element:
// Capture is to a specific element, so the device will always be over that element.
over = _captured;
break;
case CaptureMode.SubTree:
// Capture is set to an entire subtree. Hit-test to determine the element (and window)
// the device is over. If the element is within the captured sub-tree (which can span
// multiple windows), then the device is over that element. If the element is not within
// the sub-tree, then the device is over the captured element.
{
IInputElement capture = InputElement.GetContainingInputElement(_captured as DependencyObject);
if (capture != null)
{
// We need to re-hit-test to get the "real" UIElement we are over.
// This allows us to have our capture-to-subtree span multiple windows.
// GlobalHitTest always returns an IInputElement, so we are sure to have one.
over = GlobalHitTest(point, _activeSource);
}
EnsureValid(ref over);
// Make sure that the element we hit is acutally underneath
// our captured element. Because we did a global hit test, we
// could have hit an element in a completely different window.
//
// Note that we support the child being in a completely different window.
// So we use the GetUIParent method instead of just looking at
// visual/content parents.
if (over != null)
{
IInputElement ieTest = over;
while ((ieTest != null) && (ieTest != _captured))
{
UIElement eTest = ieTest as UIElement;
if (eTest != null)
{
ieTest = InputElement.GetContainingInputElement(eTest.GetUIParent(true));
}
else
{
ContentElement ceTest = ieTest as ContentElement;
if (ceTest != null)
{
ieTest = InputElement.GetContainingInputElement(ceTest.GetUIParent(true));
}
else
{
UIElement3D e3DTest = (UIElement3D)ieTest;
ieTest = InputElement.GetContainingInputElement(e3DTest.GetUIParent(true));
}
}
}
if (ieTest != _captured)
{
// If we missed the capture point, consider the device over the capture point.
over = _captured;
}
}
else
{
// If we didn't hit anything, consider the device over the capture point.
over = _captured;
}
}
break;
}
}
return over;
}
private static void EnsureValid(ref IInputElement element)
{
// We understand UIElements and ContentElements.
// If we are over something else (like a raw visual) find the containing element.
if ((element != null) && !InputElement.IsValid(element))
{
element = InputElement.GetContainingInputElement(element as DependencyObject);
}
}
private static IInputElement GlobalHitTest(Point pt, PresentationSource inputSource)
{
return MouseDevice.GlobalHitTest(false, pt, inputSource);
}
private static IInputElement LocalHitTest(Point pt, PresentationSource inputSource)
{
return MouseDevice.LocalHitTest(false, pt, inputSource);
}
#endregion
#region Capture
///
/// The element this device is currently captured to.
///
///
/// This value affects hit-testing to determine DirectlyOver.
///
public IInputElement Captured
{
get { return _captured; }
}
///
/// The type of capture being used.
///
///
/// This value affects hit-testing to determine DirectlyOver.
///
public CaptureMode CaptureMode
{
get { return _captureMode; }
}
///
/// Captures this device to a particular element using CaptureMode.Element.
///
/// The element this device will be captured to.
/// true if capture was changed, false otherwise.
public bool Capture(IInputElement element)
{
return Capture(element, CaptureMode.Element);
}
///
/// Captures this device to a particular element.
///
/// The element this device will be captured to.
/// The type of capture to use.
/// true if capture was changed, false otherwise.
public bool Capture(IInputElement element, CaptureMode captureMode)
{
VerifyAccess();
// If the element is null or captureMode is None, ensure
// that the other parameter is consistent.
if ((element == null) || (captureMode == CaptureMode.None))
{
element = null;
captureMode = CaptureMode.None;
}
UIElement uiElement;
ContentElement contentElement;
UIElement3D uiElement3D;
CastInputElement(element, out uiElement, out contentElement, out uiElement3D);
if ((element != null) && (uiElement == null) && (contentElement == null) && (uiElement3D == null))
{
throw new ArgumentException(SR.Get(SRID.Invalid_IInputElement, element.GetType()), "element");
}
if (_captured != element)
{
// Ensure that the new element is visible and enabled
if ((element == null) ||
(((uiElement != null) && uiElement.IsVisible && uiElement.IsEnabled) ||
((contentElement != null) && contentElement.IsEnabled) ||
((uiElement3D != null) && uiElement3D.IsVisible && uiElement3D.IsEnabled)))
{
IInputElement oldCapture = _captured;
_captured = element;
_captureMode = captureMode;
UIElement oldUIElement;
ContentElement oldContentElement;
UIElement3D oldUIElement3D;
CastInputElement(oldCapture, out oldUIElement, out oldContentElement, out oldUIElement3D);
if (oldUIElement != null)
{
oldUIElement.IsEnabledChanged -= OnReevaluateCapture;
oldUIElement.IsVisibleChanged -= OnReevaluateCapture;
oldUIElement.IsHitTestVisibleChanged -= OnReevaluateCapture;
}
else if (oldContentElement != null)
{
oldContentElement.IsEnabledChanged -= OnReevaluateCapture;
}
else if (oldUIElement3D != null)
{
oldUIElement3D.IsEnabledChanged -= OnReevaluateCapture;
oldUIElement3D.IsVisibleChanged -= OnReevaluateCapture;
oldUIElement3D.IsHitTestVisibleChanged -= OnReevaluateCapture;
}
if (uiElement != null)
{
uiElement.IsEnabledChanged += OnReevaluateCapture;
uiElement.IsVisibleChanged += OnReevaluateCapture;
uiElement.IsHitTestVisibleChanged += OnReevaluateCapture;
}
else if (contentElement != null)
{
contentElement.IsEnabledChanged += OnReevaluateCapture;
}
else if (uiElement3D != null)
{
uiElement3D.IsEnabledChanged += OnReevaluateCapture;
uiElement3D.IsVisibleChanged += OnReevaluateCapture;
uiElement3D.IsHitTestVisibleChanged += OnReevaluateCapture;
}
UpdateReverseInheritedProperty(/* capture = */ true, oldCapture, _captured);
if (oldCapture != null)
{
DependencyObject o = oldCapture as DependencyObject;
o.SetValue(UIElement.AreAnyTouchesCapturedPropertyKey,
BooleanBoxes.Box(AreAnyTouchesCapturedOrDirectlyOver(oldCapture, /* isCapture = */ true)));
}
if (_captured != null)
{
DependencyObject o = _captured as DependencyObject;
o.SetValue(UIElement.AreAnyTouchesCapturedPropertyKey, BooleanBoxes.TrueBox);
}
if (oldCapture != null)
{
RaiseLostCapture(oldCapture);
}
if (_captured != null)
{
RaiseGotCapture(_captured);
}
// Capture successfully moved, notify the subclass.
OnCapture(element, captureMode);
Synchronize();
return true;
}
else
{
return false;
}
}
else
{
return true;
}
}
private void UpdateReverseInheritedProperty(bool capture, IInputElement oldElement, IInputElement newElement)
{
//
List others = null;
int count = (_activeDevices != null) ? _activeDevices.Count : 0;
if (count > 0)
{
others = new List(count);
}
for (int i = 0; i < count; i++)
{
TouchDevice touchDevice = _activeDevices[i];
if (touchDevice != this)
{
DependencyObject other = capture ? (touchDevice._captured as DependencyObject) : (touchDevice._directlyOver as DependencyObject);
if (other != null)
{
others.Add(other);
}
}
}
ReverseInheritProperty property = capture ? (ReverseInheritProperty)UIElement.TouchesCapturedWithinProperty : (ReverseInheritProperty)UIElement.TouchesOverProperty;
DeferredElementTreeState treeState = capture ? _capturedWithinTreeState : _directlyOverTreeState;
Action originChangedAction = capture ? null : RaiseTouchEnterOrLeaveAction;
property.OnOriginValueChanged(oldElement as DependencyObject, newElement as DependencyObject, others, ref treeState, originChangedAction);
if (capture)
{
_capturedWithinTreeState = treeState;
}
else
{
_directlyOverTreeState = treeState;
}
}
internal static void ReevaluateCapturedWithin(DependencyObject element, DependencyObject oldParent, bool isCoreParent)
{
int count = _activeDevices != null ? _activeDevices.Count : 0;
for (int i = 0; i < count; i++)
{
TouchDevice touchDevice = _activeDevices[i];
touchDevice.ReevaluateCapturedWithinAsync(element, oldParent, isCoreParent);
}
}
private void ReevaluateCapturedWithinAsync(DependencyObject element, DependencyObject oldParent, bool isCoreParent)
{
if (element != null)
{
if (_capturedWithinTreeState == null)
{
_capturedWithinTreeState = new DeferredElementTreeState();
}
if (isCoreParent)
{
_capturedWithinTreeState.SetCoreParent(element, oldParent);
}
else
{
_capturedWithinTreeState.SetLogicalParent(element, oldParent);
}
}
if (_reevaluateCapture == null)
{
_reevaluateCapture = Dispatcher.BeginInvoke(DispatcherPriority.Input,
(DispatcherOperationCallback)delegate(object args)
{
_reevaluateCapture = null;
OnReevaluateCapturedWithinAsync();
return null;
}, null);
}
}
private void OnReevaluateCapturedWithinAsync()
{
if (_captured == null)
{
return;
}
bool killCapture = false;
//
// First, check things like IsEnabled, IsVisible, etc. on a
// UIElement vs. ContentElement basis.
//
UIElement uiElement;
ContentElement contentElement;
UIElement3D uiElement3D;
CastInputElement(_captured, out uiElement, out contentElement, out uiElement3D);
if (uiElement != null)
{
killCapture = !uiElement.IsEnabled || !uiElement.IsVisible || !uiElement.IsHitTestVisible;
}
else if (contentElement != null)
{
killCapture = !contentElement.IsEnabled;
}
else if (uiElement3D != null)
{
killCapture = !uiElement3D.IsEnabled || !uiElement3D.IsVisible || !uiElement3D.IsHitTestVisible;
}
else
{
killCapture = true;
}
//
// Second, if we still haven't thought of a reason to kill capture, validate
// it on a Visual basis for things like still being in the right tree.
//
if (killCapture == false)
{
DependencyObject containingVisual = InputElement.GetContainingVisual(_captured as DependencyObject);
killCapture = !ValidateVisualForCapture(containingVisual);
}
//
// Lastly, if we found any reason above, kill capture.
//
if (killCapture)
{
Capture(null);
}
// Refresh AreAnyTouchCapturesWithinProperty so that ReverseInherited flags are updated.
if ((_capturedWithinTreeState != null) && !_capturedWithinTreeState.IsEmpty)
{
UpdateReverseInheritedProperty(/* capture = */ true, _captured, _captured);
}
}
///
/// Critical: This code accesses critical data (_activeSource)
/// TreatAsSafe: Although it accesses critical data it does not modify or expose it, only compares against it.
///
[SecurityCritical, SecurityTreatAsSafe]
private bool ValidateVisualForCapture(DependencyObject visual)
{
if (visual == null)
return false;
PresentationSource presentationSource = PresentationSource.CriticalFromVisual(visual);
return ((presentationSource != null) && (presentationSource == _activeSource));
}
private void OnReevaluateCapture(object sender, DependencyPropertyChangedEventArgs e)
{
// IsEnabled, IsVisible, and/or IsHitTestVisible became false
if (!(bool)e.NewValue)
{
if (_reevaluateCapture == null)
{
_reevaluateCapture = Dispatcher.BeginInvoke(DispatcherPriority.Input,
(DispatcherOperationCallback)delegate(object args)
{
_reevaluateCapture = null;
Capture(null);
return null;
}, null);
}
}
}
private static void CastInputElement(IInputElement element, out UIElement uiElement, out ContentElement contentElement, out UIElement3D uiElement3D)
{
uiElement = element as UIElement;
contentElement = (uiElement == null) ? element as ContentElement : null;
uiElement3D = ((uiElement == null) && (contentElement == null)) ? element as UIElement3D : null;
}
///
/// Critical - Accesses _inputManager.
/// TreatAsSafe - Does not expose _inputManager and event raised is not critical.
///
[SecurityCritical, SecurityTreatAsSafe]
private void RaiseLostCapture(IInputElement oldCapture)
{
Debug.Assert(oldCapture != null, "oldCapture should be non-null.");
TouchEventArgs e = CreateEventArgs(Touch.LostTouchCaptureEvent);
e.Source = oldCapture;
_inputManager.ProcessInput(e);
}
///
/// Critical - Accesses _inputManager.
/// TreatAsSafe - Does not expose _inputManager and event raised is not critical.
///
[SecurityCritical, SecurityTreatAsSafe]
private void RaiseGotCapture(IInputElement captured)
{
Debug.Assert(captured != null, "captured should be non-null.");
TouchEventArgs e = CreateEventArgs(Touch.GotTouchCaptureEvent);
e.Source = captured;
_inputManager.ProcessInput(e);
}
///
/// Notifies subclasses that capture changed.
///
///
///
protected virtual void OnCapture(IInputElement element, CaptureMode captureMode)
{
}
#endregion
#region Updating State
protected bool ReportDown()
{
EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info, EventTrace.Event.TouchDownReported, _deviceId);
_isDown = true;
UpdateDirectlyOver(/* isSynchronize = */ false);
bool handled = RaiseTouchDown();
OnUpdated();
Touch.ReportFrame();
return handled;
}
protected bool ReportMove()
{
EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info, EventTrace.Event.TouchMoveReported, _deviceId);
UpdateDirectlyOver(/* isSynchronize = */ false);
bool handled = RaiseTouchMove();
OnUpdated();
Touch.ReportFrame();
return handled;
}
protected bool ReportUp()
{
EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info, EventTrace.Event.TouchUpReported, _deviceId);
bool handled = RaiseTouchUp();
_isDown = false;
UpdateDirectlyOver(/* isSynchronize = */ false);
OnUpdated();
Touch.ReportFrame();
return handled;
}
protected void Activate()
{
if (_isActive)
{
throw new InvalidOperationException(SR.Get(SRID.Touch_DeviceAlreadyActivated));
}
PromotingToManipulation = false;
AddActiveDevice(this);
AttachTouchDevice();
Synchronize();
if (_activeDevices.Count == 1)
{
_isPrimary = true;
}
_isActive = true;
if (Activated != null)
{
Activated(this, EventArgs.Empty);
}
}
protected void Deactivate()
{
if (!_isActive)
{
throw new InvalidOperationException(SR.Get(SRID.Touch_DeviceNotActivated));
}
Capture(null);
DetachTouchDevice();
RemoveActiveDevice(this);
_isActive = false;
_manipulatingElement = null;
if (Deactivated != null)
{
Deactivated(this, EventArgs.Empty);
}
}
///
/// Forces the TouchDevice to resynchronize.
///
///
/// Critical: Accesses _activeSource
/// PublicOK: Does not expose _activeSource.
///
[SecurityCritical]
public void Synchronize()
{
if (_activeSource != null &&
_activeSource.CompositionTarget != null &&
!_activeSource.CompositionTarget.IsDisposed)
{
if (UpdateDirectlyOver(/* isSynchronize = */ true))
{
OnUpdated();
Touch.ReportFrame();
}
}
}
///
/// Critical: Calling this method would do mouse promotions.
/// PublicOK: This method has a demand on it.
/// Demand: Technically the demand is not needed because the
/// user can already do this indirectly by canceling the
/// manipulation. But the decision is to limit the scope
/// of this raw method to full trust.
///
[SecurityCritical, UIPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
protected virtual void OnManipulationEnded(bool cancel)
{
UIElement manipulatableElement = GetManipulatableElement();
if (manipulatableElement != null && PromotingToManipulation)
{
Capture(null);
}
}
protected virtual void OnManipulationStarted()
{
}
private void OnHitTestInvalidatedAsync(object sender, EventArgs e)
{
// The hit-test result may have changed.
Synchronize();
if ((_directlyOverTreeState != null) && !_directlyOverTreeState.IsEmpty)
{
UpdateReverseInheritedProperty(/* capture = */ false, _directlyOver, _directlyOver);
}
}
private bool UpdateDirectlyOver(bool isSynchronize)
{
IInputElement newDirectlyOver = null;
TouchPoint touchPoint = GetTouchPoint(null);
if (touchPoint != null)
{
Point position = touchPoint.Position;
newDirectlyOver = CriticalHitTest(position, isSynchronize);
}
if (newDirectlyOver != _directlyOver)
{
ChangeDirectlyOver(newDirectlyOver);
return true;
}
else
{
return false;
}
}
private void OnReevaluateDirectlyOver(object sender, DependencyPropertyChangedEventArgs e)
{
ReevaluateDirectlyOverAsync(null, null, true);
}
internal static void ReevaluateDirectlyOver(DependencyObject element, DependencyObject oldParent, bool isCoreParent)
{
int count = _activeDevices != null ? _activeDevices.Count : 0;
for (int i = 0; i < count; i++)
{
TouchDevice touchDevice = _activeDevices[i];
touchDevice.ReevaluateDirectlyOverAsync(element, oldParent, isCoreParent);
}
}
private void ReevaluateDirectlyOverAsync(DependencyObject element, DependencyObject oldParent, bool isCoreParent)
{
if (element != null)
{
if (_directlyOverTreeState == null)
{
_directlyOverTreeState = new DeferredElementTreeState();
}
if (isCoreParent)
{
_directlyOverTreeState.SetCoreParent(element, oldParent);
}
else
{
_directlyOverTreeState.SetLogicalParent(element, oldParent);
}
}
if (_reevaluateOver == null)
{
_reevaluateOver = Dispatcher.BeginInvoke(DispatcherPriority.Input,
(DispatcherOperationCallback)delegate(object args)
{
_reevaluateOver = null;
OnHitTestInvalidatedAsync(this, EventArgs.Empty);
return null;
}, null);
}
}
private void ChangeDirectlyOver(IInputElement newDirectlyOver)
{
Debug.Assert(newDirectlyOver != _directlyOver, "ChangeDirectlyOver called when newDirectlyOver is the same as _directlyOver.");
IInputElement oldDirectlyOver = _directlyOver;
_directlyOver = newDirectlyOver;
UIElement oldUIElement;
ContentElement oldContentElement;
UIElement3D oldUIElement3D;
CastInputElement(oldDirectlyOver, out oldUIElement, out oldContentElement, out oldUIElement3D);
UIElement newUIElement;
ContentElement newContentElement;
UIElement3D newUIElement3D;
CastInputElement(newDirectlyOver, out newUIElement, out newContentElement, out newUIElement3D);
if (oldUIElement != null)
{
oldUIElement.IsEnabledChanged -= OnReevaluateDirectlyOver;
oldUIElement.IsVisibleChanged -= OnReevaluateDirectlyOver;
oldUIElement.IsHitTestVisibleChanged -= OnReevaluateDirectlyOver;
}
else if (oldContentElement != null)
{
oldContentElement.IsEnabledChanged -= OnReevaluateDirectlyOver;
}
else if (oldUIElement3D != null)
{
oldUIElement3D.IsEnabledChanged -= OnReevaluateDirectlyOver;
oldUIElement3D.IsVisibleChanged -= OnReevaluateDirectlyOver;
oldUIElement3D.IsHitTestVisibleChanged -= OnReevaluateDirectlyOver;
}
if (newUIElement != null)
{
newUIElement.IsEnabledChanged += OnReevaluateDirectlyOver;
newUIElement.IsVisibleChanged += OnReevaluateDirectlyOver;
newUIElement.IsHitTestVisibleChanged += OnReevaluateDirectlyOver;
}
else if (newContentElement != null)
{
newContentElement.IsEnabledChanged += OnReevaluateDirectlyOver;
}
else if (newUIElement3D != null)
{
newUIElement3D.IsEnabledChanged += OnReevaluateDirectlyOver;
newUIElement3D.IsVisibleChanged += OnReevaluateDirectlyOver;
newUIElement3D.IsHitTestVisibleChanged += OnReevaluateDirectlyOver;
}
UpdateReverseInheritedProperty(/* capture = */ false, oldDirectlyOver, newDirectlyOver);
if (oldDirectlyOver != null)
{
DependencyObject o = oldDirectlyOver as DependencyObject;
o.SetValue(UIElement.AreAnyTouchesDirectlyOverPropertyKey,
BooleanBoxes.Box(AreAnyTouchesCapturedOrDirectlyOver(oldDirectlyOver, /* isCapture = */ false)));
}
if (newDirectlyOver != null)
{
DependencyObject o = newDirectlyOver as DependencyObject;
o.SetValue(UIElement.AreAnyTouchesDirectlyOverPropertyKey, BooleanBoxes.TrueBox);
}
}
///
/// Action to raise the TouchEnter/TouchLeave events.
/// This will be executed by TouchesOver RevereInheritance
/// property class on the entire parent chain affected by the
/// changes in TouchDevice's DirectlyOver.
///
private Action RaiseTouchEnterOrLeaveAction
{
get
{
if (_raiseTouchEnterOrLeaveAction == null)
{
_raiseTouchEnterOrLeaveAction = new Action(RaiseTouchEnterOrLeave);
}
return _raiseTouchEnterOrLeaveAction;
}
}
///
/// Critical - Accesses _inputManager.
/// TreatAsSafe - Does not expose _inputManager and event raised is not critical.
///
[SecurityCritical, SecurityTreatAsSafe]
private void RaiseTouchEnterOrLeave(DependencyObject element, bool isLeave)
{
Debug.Assert(element != null);
TouchEventArgs touchEventArgs = CreateEventArgs(isLeave ? Touch.TouchLeaveEvent : Touch.TouchEnterEvent);
touchEventArgs.Source = element;
_inputManager.ProcessInput(touchEventArgs);
}
private TouchEventArgs CreateEventArgs(RoutedEvent routedEvent)
{
//
TouchEventArgs touchEventArgs = new TouchEventArgs(this, Environment.TickCount);
touchEventArgs.RoutedEvent = routedEvent;
return touchEventArgs;
}
///
/// Critical - Accesses _inputManager.
/// TreatAsSafe - Does not expose _inputManager and event raised is not critical.
///
[SecurityCritical, SecurityTreatAsSafe]
private bool RaiseTouchDown()
{
TouchEventArgs e = CreateEventArgs(Touch.PreviewTouchDownEvent);
_lastDownHandled = false;
_inputManager.ProcessInput(e);
// We want to return true if either of PreviewTouchDown or TouchDown
// events are handled. Hence we cannot use e.Handled which is only
// for preview.
return _lastDownHandled;
}
///
/// Critical - Accesses _inputManager.
/// TreatAsSafe - Does not expose _inputManager and event raised is not critical.
///
[SecurityCritical, SecurityTreatAsSafe]
private bool RaiseTouchMove()
{
TouchEventArgs e = CreateEventArgs(Touch.PreviewTouchMoveEvent);
_lastMoveHandled = false;
_inputManager.ProcessInput(e);
// We want to return true if either of PreviewTouchMove or TouchMove
// events are handled. Hence we cannot use e.Handled which is only
// for preview.
return _lastMoveHandled;
}
///
/// Critical - Accesses _inputManager.
/// TreatAsSafe - Does not expose _inputManager and event raised is not critical.
///
[SecurityCritical, SecurityTreatAsSafe]
private bool RaiseTouchUp()
{
TouchEventArgs e = CreateEventArgs(Touch.PreviewTouchUpEvent);
_lastUpHandled = false;
_inputManager.ProcessInput(e);
// We want to return true if either of PreviewTouchUp or TouchUp
// events are handled. Hence we cannot use e.Handled which is only
// for preview.
return _lastUpHandled;
}
#endregion
#region Input Processing and Promotion
///
/// Critical: This method can be used for input spoofing
///
[SecurityCritical]
private void PostProcessInput(object sender, ProcessInputEventArgs e)
{
InputEventArgs inputEventArgs = e.StagingItem.Input;
if ((inputEventArgs != null) && (inputEventArgs.Device == this))
{
if (inputEventArgs.Handled)
{
RoutedEvent routedEvent = inputEventArgs.RoutedEvent;
if (routedEvent == Touch.PreviewTouchMoveEvent ||
routedEvent == Touch.TouchMoveEvent)
{
_lastMoveHandled = true;
}
else if (routedEvent == Touch.PreviewTouchDownEvent ||
routedEvent == Touch.TouchDownEvent)
{
_lastDownHandled = true;
}
else if (routedEvent == Touch.PreviewTouchUpEvent ||
routedEvent == Touch.TouchUpEvent)
{
_lastUpHandled = true;
}
}
else
{
bool forManipulation;
RoutedEvent promotedTouchEvent = PromotePreviewToMain(inputEventArgs.RoutedEvent, out forManipulation);
if (promotedTouchEvent != null)
{
TouchEventArgs promotedTouchEventArgs = CreateEventArgs(promotedTouchEvent);
e.PushInput(promotedTouchEventArgs, e.StagingItem);
}
else if (forManipulation)
{
UIElement manipulatableElement = GetManipulatableElement();
if (manipulatableElement != null)
{
PromoteMainToManipulation(manipulatableElement, (TouchEventArgs)inputEventArgs);
}
}
}
}
}
private RoutedEvent PromotePreviewToMain(RoutedEvent routedEvent, out bool forManipulation)
{
forManipulation = false;
if (routedEvent == Touch.PreviewTouchMoveEvent)
{
return Touch.TouchMoveEvent;
}
else if (routedEvent == Touch.PreviewTouchDownEvent)
{
return Touch.TouchDownEvent;
}
else if (routedEvent == Touch.PreviewTouchUpEvent)
{
return Touch.TouchUpEvent;
}
forManipulation = (routedEvent == Touch.TouchMoveEvent) ||
(routedEvent == Touch.TouchDownEvent) ||
(routedEvent == Touch.TouchUpEvent) ||
(routedEvent == Touch.GotTouchCaptureEvent) ||
(routedEvent == Touch.LostTouchCaptureEvent);
return null;
}
private UIElement GetManipulatableElement()
{
UIElement element = InputElement.GetContainingUIElement(_directlyOver as DependencyObject) as UIElement;
if (element != null)
{
element = Manipulation.FindManipulationParent(element);
}
return element;
}
private void PromoteMainToManipulation(UIElement manipulatableElement, TouchEventArgs touchEventArgs)
{
RoutedEvent routedEvent = touchEventArgs.RoutedEvent;
if (routedEvent == Touch.TouchDownEvent)
{
// When touch goes down or if we're in the middle of a move, capture so that we can
// start manipulation. We could be in the middle of a move if a device delayed
// promotion, such as the StylusTouchDevice, due to other gesture detection.
Capture(manipulatableElement);
}
else if ((routedEvent == Touch.TouchUpEvent) && PromotingToManipulation)
{
// When touch goes up, release capture so that we can stop manipulation.
Capture(null);
}
else if ((routedEvent == Touch.GotTouchCaptureEvent) && !PromotingToManipulation)
{
UIElement element = _captured as UIElement;
if (element != null && element.IsManipulationEnabled)
{
// When touch gets capture and if the captured element
// is manipulable, then add it as a manipulator to
// the captured element.
_manipulatingElement = new WeakReference(element);
Manipulation.AddManipulator(element, this);
PromotingToManipulation = true;
OnManipulationStarted();
}
}
else if ((routedEvent == Touch.LostTouchCaptureEvent) && PromotingToManipulation && _manipulatingElement != null)
{
UIElement element = _manipulatingElement.Target as UIElement;
_manipulatingElement = null;
if (element != null)
{
// When touch loses capture, remove it as a manipulator.
Manipulation.TryRemoveManipulator(element, this);
PromotingToManipulation = false;
}
}
}
///
/// Whether this device should promote to manipulation.
///
internal bool PromotingToManipulation
{
get;
private set;
}
#endregion
#region Active Devices
private static void AddActiveDevice(TouchDevice device)
{
if (_activeDevices == null)
{
_activeDevices = new List(2);
}
_activeDevices.Add(device);
}
private static void RemoveActiveDevice(TouchDevice device)
{
if (_activeDevices != null)
{
_activeDevices.Remove(device);
}
}
internal static TouchPointCollection GetTouchPoints(IInputElement relativeTo)
{
TouchPointCollection points = new TouchPointCollection();
if (_activeDevices != null)
{
int count = _activeDevices.Count;
for (int i = 0; i < count; i++)
{
TouchDevice device = _activeDevices[i];
points.Add(device.GetTouchPoint(relativeTo));
}
}
return points;
}
internal static TouchPoint GetPrimaryTouchPoint(IInputElement relativeTo)
{
if ((_activeDevices != null) && (_activeDevices.Count > 0))
{
TouchDevice device = _activeDevices[0];
if (device._isPrimary)
{
return device.GetTouchPoint(relativeTo);
}
}
return null;
}
internal static void ReleaseAllCaptures(IInputElement element)
{
if (_activeDevices != null)
{
int count = _activeDevices.Count;
for (int i = 0; i < count; i++)
{
TouchDevice device = _activeDevices[i];
if (device.Captured == element)
{
device.Capture(null);
}
}
}
}
internal static IEnumerable GetCapturedTouches(IInputElement element, bool includeWithin)
{
return GetCapturedOrOverTouches(element, includeWithin, /* isCapture = */ true);
}
internal static IEnumerable GetTouchesOver(IInputElement element, bool includeWithin)
{
return GetCapturedOrOverTouches(element, includeWithin, /* isCapture = */ false);
}
private static bool IsWithin(IInputElement parent, IInputElement child)
{
// We are assuming parent and child are Visual, Visual3D, or ContentElement
DependencyObject currentChild = child as DependencyObject;
while ((currentChild != null) && (currentChild != parent))
{
if (currentChild is Visual || currentChild is Visual3D)
{
currentChild = VisualTreeHelper.GetParent(currentChild);
}
else
{
currentChild = ((ContentElement)currentChild).Parent;
}
}
return (currentChild == parent);
}
private static IEnumerable GetCapturedOrOverTouches(IInputElement element, bool includeWithin, bool isCapture)
{
List touches = new List();
if (_activeDevices != null)
{
int count = _activeDevices.Count;
for (int i = 0; i < count; i++)
{
TouchDevice device = _activeDevices[i];
IInputElement touchElement = isCapture ? device.Captured : device.DirectlyOver;
if ((touchElement != null) &&
((touchElement == element) ||
(includeWithin && IsWithin(element, touchElement))))
{
touches.Add(device);
}
}
}
return touches;
}
private static bool AreAnyTouchesCapturedOrDirectlyOver(IInputElement element, bool isCapture)
{
if (_activeDevices != null)
{
int count = _activeDevices.Count;
for (int i = 0; i < count; i++)
{
TouchDevice device = _activeDevices[i];
IInputElement touchElement = isCapture ? device.Captured : device.DirectlyOver;
if (touchElement != null &&
touchElement == element)
{
return true;
}
}
}
return false;
}
#endregion
#region IManipulator
int IManipulator.Id
{
get
{
return Id;
}
}
Point IManipulator.GetPosition(IInputElement relativeTo)
{
return GetTouchPoint(relativeTo).Position;
}
public event EventHandler Updated;
private void OnUpdated()
{
if (Updated != null)
{
Updated(this, EventArgs.Empty);
}
}
///
/// Critical: Calling this method would do mouse promotions.
/// PublicOK: This method has a demand on it.
/// Demand: Technically the demand is not needed because the
/// user can already do this indirectly by canceling the
/// manipulation. But the decision is to limit the scope
/// of this raw method to full trust.
///
[SecurityCritical, UIPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
void IManipulator.ManipulationEnded(bool cancel)
{
this.OnManipulationEnded(cancel);
}
#endregion
#region Data
private int _deviceId;
private IInputElement _directlyOver;
private IInputElement _captured;
private CaptureMode _captureMode;
private bool _isDown;
private DispatcherOperation _reevaluateCapture;
private DispatcherOperation _reevaluateOver;
private DeferredElementTreeState _directlyOverTreeState;
private DeferredElementTreeState _capturedWithinTreeState;
private bool _isPrimary;
private bool _isActive;
private Action _raiseTouchEnterOrLeaveAction;
// Technically only one flag is needed as per current code. But if
// one of the derived touch devices raise a synchronizing TouchMove event,
// while raising TouchUp, things would be messed up. Hence using three
// different flags.
private bool _lastDownHandled;
private bool _lastUpHandled;
private bool _lastMoveHandled;
///
/// Critical - PresentationSource must be protected.
///
[SecurityCritical]
private PresentationSource _activeSource;
///
/// Critical - InputManager must be protected.
///
[SecurityCritical]
private InputManager _inputManager;
private WeakReference _manipulatingElement;
[ThreadStatic]
private static List _activeDevices;
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//---------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;
using System.Security;
using System.Security.Permissions;
using MS.Internal;
using MS.Internal.KnownBoxes;
using MS.Internal.PresentationCore;
using MS.Utility;
using SR = MS.Internal.PresentationCore.SR;
using SRID = MS.Internal.PresentationCore.SRID;
namespace System.Windows.Input
{
///
/// Represents a touch device (i.e. a finger).
///
///
/// InheritanceDemand - Prevents subclassing TouchDevice from partial trust code.
/// This is for defense in depth since there is no scenario where partial trust code
/// needs to inherit from this class.
///
[UIPermission(SecurityAction.InheritanceDemand, Unrestricted = true)]
public abstract class TouchDevice : InputDevice, IManipulator
{
///
/// Instantiates a new instance of this class.
///
///
/// The ID of this device.
/// For a particular subclass of TouchDevice, ID should be unique.
/// Note: This is not validated to be unique.
///
///
/// Critical: Retrieves an InputManager instance.
/// PublicOK: Does not expose the InputManager.
///
[SecurityCritical]
protected TouchDevice(int deviceId)
: base()
{
_deviceId = deviceId;
_inputManager = InputManager.UnsecureCurrent;
}
///
/// Critical: Attaches to InputManager event handlers.
/// TreatAsSafe: Does not expose the InputManager.
///
[SecurityCritical, SecurityTreatAsSafe]
private void AttachTouchDevice()
{
_inputManager.PostProcessInput += new ProcessInputEventHandler(PostProcessInput);
_inputManager.HitTestInvalidatedAsync += new EventHandler(OnHitTestInvalidatedAsync);
}
///
/// Critical: Detaches from InputManager event handlers.
/// TreatAsSafe: Does not expose the InputManager.
///
[SecurityCritical, SecurityTreatAsSafe]
private void DetachTouchDevice()
{
_inputManager.PostProcessInput -= new ProcessInputEventHandler(PostProcessInput);
_inputManager.HitTestInvalidatedAsync -= new EventHandler(OnHitTestInvalidatedAsync);
}
///
/// The ID of this device.
/// For a particular subclass of TouchDevice, ID should be unique.
///
public int Id
{
get { return _deviceId; }
}
///
/// This event will be raised whenever the device gets activated
///
public event EventHandler Activated;
///
/// This event will be raised whenever the device gets deactivated
///
public event EventHandler Deactivated;
///
/// IsActive boolean
///
public bool IsActive
{
get
{
return _isActive;
}
}
#region InputDevice
///
/// Returns the element that input from this device is sent to.
///
///
/// Always the same value as DirectlyOver.
///
public sealed override IInputElement Target
{
get { return _directlyOver; }
}
///
/// Returns the PresentationSource that is reporting input for this device.
///
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
/// Subclasses should use SetActiveSource to set this property.
///
///
/// Critical - Accesses critical data (_activeSource)
/// PublicOK - There is a demand.
///
public sealed override PresentationSource ActiveSource
{
[SecurityCritical]
get
{
SecurityHelper.DemandUIWindowPermission();
return _activeSource;
}
}
///
/// Critical - PresentationSource is critical data.
/// PublicOK - This method has a link demand.
///
[SecurityCritical]
[UIPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
protected void SetActiveSource(PresentationSource activeSource)
{
_activeSource = activeSource;
}
#endregion
#region Location
///
/// Returns the element that this device is over.
///
public IInputElement DirectlyOver
{
get { return _directlyOver; }
}
///
/// Provides the current position.
///
/// Defines the coordinate space.
/// The current position in the coordinate space of relativeTo.
public abstract TouchPoint GetTouchPoint(IInputElement relativeTo);
///
/// Provides all of the known points the device hit since the last reported position update.
///
/// Defines the coordinate space.
/// A list of points in the coordinate space of relativeTo.
public abstract TouchPointCollection GetIntermediateTouchPoints(IInputElement relativeTo);
///
/// Critical - Access _activeSource.
/// TreatAsSafe - Does not expose _activeSource.
///
[SecurityCritical, SecurityTreatAsSafe]
private IInputElement CriticalHitTest(Point point, bool isSynchronize)
{
IInputElement over = null;
if (_activeSource != null)
{
switch (_captureMode)
{
case CaptureMode.None:
// No capture, do a regular hit-test.
if (_isDown)
{
if (isSynchronize)
{
// In a synchronize call, we need to hit-test the window in addition to the element
over = GlobalHitTest(point, _activeSource);
}
else
{
// Just hit-test the element
over = LocalHitTest(point, _activeSource);
}
EnsureValid(ref over);
}
break;
case CaptureMode.Element:
// Capture is to a specific element, so the device will always be over that element.
over = _captured;
break;
case CaptureMode.SubTree:
// Capture is set to an entire subtree. Hit-test to determine the element (and window)
// the device is over. If the element is within the captured sub-tree (which can span
// multiple windows), then the device is over that element. If the element is not within
// the sub-tree, then the device is over the captured element.
{
IInputElement capture = InputElement.GetContainingInputElement(_captured as DependencyObject);
if (capture != null)
{
// We need to re-hit-test to get the "real" UIElement we are over.
// This allows us to have our capture-to-subtree span multiple windows.
// GlobalHitTest always returns an IInputElement, so we are sure to have one.
over = GlobalHitTest(point, _activeSource);
}
EnsureValid(ref over);
// Make sure that the element we hit is acutally underneath
// our captured element. Because we did a global hit test, we
// could have hit an element in a completely different window.
//
// Note that we support the child being in a completely different window.
// So we use the GetUIParent method instead of just looking at
// visual/content parents.
if (over != null)
{
IInputElement ieTest = over;
while ((ieTest != null) && (ieTest != _captured))
{
UIElement eTest = ieTest as UIElement;
if (eTest != null)
{
ieTest = InputElement.GetContainingInputElement(eTest.GetUIParent(true));
}
else
{
ContentElement ceTest = ieTest as ContentElement;
if (ceTest != null)
{
ieTest = InputElement.GetContainingInputElement(ceTest.GetUIParent(true));
}
else
{
UIElement3D e3DTest = (UIElement3D)ieTest;
ieTest = InputElement.GetContainingInputElement(e3DTest.GetUIParent(true));
}
}
}
if (ieTest != _captured)
{
// If we missed the capture point, consider the device over the capture point.
over = _captured;
}
}
else
{
// If we didn't hit anything, consider the device over the capture point.
over = _captured;
}
}
break;
}
}
return over;
}
private static void EnsureValid(ref IInputElement element)
{
// We understand UIElements and ContentElements.
// If we are over something else (like a raw visual) find the containing element.
if ((element != null) && !InputElement.IsValid(element))
{
element = InputElement.GetContainingInputElement(element as DependencyObject);
}
}
private static IInputElement GlobalHitTest(Point pt, PresentationSource inputSource)
{
return MouseDevice.GlobalHitTest(false, pt, inputSource);
}
private static IInputElement LocalHitTest(Point pt, PresentationSource inputSource)
{
return MouseDevice.LocalHitTest(false, pt, inputSource);
}
#endregion
#region Capture
///
/// The element this device is currently captured to.
///
///
/// This value affects hit-testing to determine DirectlyOver.
///
public IInputElement Captured
{
get { return _captured; }
}
///
/// The type of capture being used.
///
///
/// This value affects hit-testing to determine DirectlyOver.
///
public CaptureMode CaptureMode
{
get { return _captureMode; }
}
///
/// Captures this device to a particular element using CaptureMode.Element.
///
/// The element this device will be captured to.
/// true if capture was changed, false otherwise.
public bool Capture(IInputElement element)
{
return Capture(element, CaptureMode.Element);
}
///
/// Captures this device to a particular element.
///
/// The element this device will be captured to.
/// The type of capture to use.
/// true if capture was changed, false otherwise.
public bool Capture(IInputElement element, CaptureMode captureMode)
{
VerifyAccess();
// If the element is null or captureMode is None, ensure
// that the other parameter is consistent.
if ((element == null) || (captureMode == CaptureMode.None))
{
element = null;
captureMode = CaptureMode.None;
}
UIElement uiElement;
ContentElement contentElement;
UIElement3D uiElement3D;
CastInputElement(element, out uiElement, out contentElement, out uiElement3D);
if ((element != null) && (uiElement == null) && (contentElement == null) && (uiElement3D == null))
{
throw new ArgumentException(SR.Get(SRID.Invalid_IInputElement, element.GetType()), "element");
}
if (_captured != element)
{
// Ensure that the new element is visible and enabled
if ((element == null) ||
(((uiElement != null) && uiElement.IsVisible && uiElement.IsEnabled) ||
((contentElement != null) && contentElement.IsEnabled) ||
((uiElement3D != null) && uiElement3D.IsVisible && uiElement3D.IsEnabled)))
{
IInputElement oldCapture = _captured;
_captured = element;
_captureMode = captureMode;
UIElement oldUIElement;
ContentElement oldContentElement;
UIElement3D oldUIElement3D;
CastInputElement(oldCapture, out oldUIElement, out oldContentElement, out oldUIElement3D);
if (oldUIElement != null)
{
oldUIElement.IsEnabledChanged -= OnReevaluateCapture;
oldUIElement.IsVisibleChanged -= OnReevaluateCapture;
oldUIElement.IsHitTestVisibleChanged -= OnReevaluateCapture;
}
else if (oldContentElement != null)
{
oldContentElement.IsEnabledChanged -= OnReevaluateCapture;
}
else if (oldUIElement3D != null)
{
oldUIElement3D.IsEnabledChanged -= OnReevaluateCapture;
oldUIElement3D.IsVisibleChanged -= OnReevaluateCapture;
oldUIElement3D.IsHitTestVisibleChanged -= OnReevaluateCapture;
}
if (uiElement != null)
{
uiElement.IsEnabledChanged += OnReevaluateCapture;
uiElement.IsVisibleChanged += OnReevaluateCapture;
uiElement.IsHitTestVisibleChanged += OnReevaluateCapture;
}
else if (contentElement != null)
{
contentElement.IsEnabledChanged += OnReevaluateCapture;
}
else if (uiElement3D != null)
{
uiElement3D.IsEnabledChanged += OnReevaluateCapture;
uiElement3D.IsVisibleChanged += OnReevaluateCapture;
uiElement3D.IsHitTestVisibleChanged += OnReevaluateCapture;
}
UpdateReverseInheritedProperty(/* capture = */ true, oldCapture, _captured);
if (oldCapture != null)
{
DependencyObject o = oldCapture as DependencyObject;
o.SetValue(UIElement.AreAnyTouchesCapturedPropertyKey,
BooleanBoxes.Box(AreAnyTouchesCapturedOrDirectlyOver(oldCapture, /* isCapture = */ true)));
}
if (_captured != null)
{
DependencyObject o = _captured as DependencyObject;
o.SetValue(UIElement.AreAnyTouchesCapturedPropertyKey, BooleanBoxes.TrueBox);
}
if (oldCapture != null)
{
RaiseLostCapture(oldCapture);
}
if (_captured != null)
{
RaiseGotCapture(_captured);
}
// Capture successfully moved, notify the subclass.
OnCapture(element, captureMode);
Synchronize();
return true;
}
else
{
return false;
}
}
else
{
return true;
}
}
private void UpdateReverseInheritedProperty(bool capture, IInputElement oldElement, IInputElement newElement)
{
//
List others = null;
int count = (_activeDevices != null) ? _activeDevices.Count : 0;
if (count > 0)
{
others = new List(count);
}
for (int i = 0; i < count; i++)
{
TouchDevice touchDevice = _activeDevices[i];
if (touchDevice != this)
{
DependencyObject other = capture ? (touchDevice._captured as DependencyObject) : (touchDevice._directlyOver as DependencyObject);
if (other != null)
{
others.Add(other);
}
}
}
ReverseInheritProperty property = capture ? (ReverseInheritProperty)UIElement.TouchesCapturedWithinProperty : (ReverseInheritProperty)UIElement.TouchesOverProperty;
DeferredElementTreeState treeState = capture ? _capturedWithinTreeState : _directlyOverTreeState;
Action originChangedAction = capture ? null : RaiseTouchEnterOrLeaveAction;
property.OnOriginValueChanged(oldElement as DependencyObject, newElement as DependencyObject, others, ref treeState, originChangedAction);
if (capture)
{
_capturedWithinTreeState = treeState;
}
else
{
_directlyOverTreeState = treeState;
}
}
internal static void ReevaluateCapturedWithin(DependencyObject element, DependencyObject oldParent, bool isCoreParent)
{
int count = _activeDevices != null ? _activeDevices.Count : 0;
for (int i = 0; i < count; i++)
{
TouchDevice touchDevice = _activeDevices[i];
touchDevice.ReevaluateCapturedWithinAsync(element, oldParent, isCoreParent);
}
}
private void ReevaluateCapturedWithinAsync(DependencyObject element, DependencyObject oldParent, bool isCoreParent)
{
if (element != null)
{
if (_capturedWithinTreeState == null)
{
_capturedWithinTreeState = new DeferredElementTreeState();
}
if (isCoreParent)
{
_capturedWithinTreeState.SetCoreParent(element, oldParent);
}
else
{
_capturedWithinTreeState.SetLogicalParent(element, oldParent);
}
}
if (_reevaluateCapture == null)
{
_reevaluateCapture = Dispatcher.BeginInvoke(DispatcherPriority.Input,
(DispatcherOperationCallback)delegate(object args)
{
_reevaluateCapture = null;
OnReevaluateCapturedWithinAsync();
return null;
}, null);
}
}
private void OnReevaluateCapturedWithinAsync()
{
if (_captured == null)
{
return;
}
bool killCapture = false;
//
// First, check things like IsEnabled, IsVisible, etc. on a
// UIElement vs. ContentElement basis.
//
UIElement uiElement;
ContentElement contentElement;
UIElement3D uiElement3D;
CastInputElement(_captured, out uiElement, out contentElement, out uiElement3D);
if (uiElement != null)
{
killCapture = !uiElement.IsEnabled || !uiElement.IsVisible || !uiElement.IsHitTestVisible;
}
else if (contentElement != null)
{
killCapture = !contentElement.IsEnabled;
}
else if (uiElement3D != null)
{
killCapture = !uiElement3D.IsEnabled || !uiElement3D.IsVisible || !uiElement3D.IsHitTestVisible;
}
else
{
killCapture = true;
}
//
// Second, if we still haven't thought of a reason to kill capture, validate
// it on a Visual basis for things like still being in the right tree.
//
if (killCapture == false)
{
DependencyObject containingVisual = InputElement.GetContainingVisual(_captured as DependencyObject);
killCapture = !ValidateVisualForCapture(containingVisual);
}
//
// Lastly, if we found any reason above, kill capture.
//
if (killCapture)
{
Capture(null);
}
// Refresh AreAnyTouchCapturesWithinProperty so that ReverseInherited flags are updated.
if ((_capturedWithinTreeState != null) && !_capturedWithinTreeState.IsEmpty)
{
UpdateReverseInheritedProperty(/* capture = */ true, _captured, _captured);
}
}
///
/// Critical: This code accesses critical data (_activeSource)
/// TreatAsSafe: Although it accesses critical data it does not modify or expose it, only compares against it.
///
[SecurityCritical, SecurityTreatAsSafe]
private bool ValidateVisualForCapture(DependencyObject visual)
{
if (visual == null)
return false;
PresentationSource presentationSource = PresentationSource.CriticalFromVisual(visual);
return ((presentationSource != null) && (presentationSource == _activeSource));
}
private void OnReevaluateCapture(object sender, DependencyPropertyChangedEventArgs e)
{
// IsEnabled, IsVisible, and/or IsHitTestVisible became false
if (!(bool)e.NewValue)
{
if (_reevaluateCapture == null)
{
_reevaluateCapture = Dispatcher.BeginInvoke(DispatcherPriority.Input,
(DispatcherOperationCallback)delegate(object args)
{
_reevaluateCapture = null;
Capture(null);
return null;
}, null);
}
}
}
private static void CastInputElement(IInputElement element, out UIElement uiElement, out ContentElement contentElement, out UIElement3D uiElement3D)
{
uiElement = element as UIElement;
contentElement = (uiElement == null) ? element as ContentElement : null;
uiElement3D = ((uiElement == null) && (contentElement == null)) ? element as UIElement3D : null;
}
///
/// Critical - Accesses _inputManager.
/// TreatAsSafe - Does not expose _inputManager and event raised is not critical.
///
[SecurityCritical, SecurityTreatAsSafe]
private void RaiseLostCapture(IInputElement oldCapture)
{
Debug.Assert(oldCapture != null, "oldCapture should be non-null.");
TouchEventArgs e = CreateEventArgs(Touch.LostTouchCaptureEvent);
e.Source = oldCapture;
_inputManager.ProcessInput(e);
}
///
/// Critical - Accesses _inputManager.
/// TreatAsSafe - Does not expose _inputManager and event raised is not critical.
///
[SecurityCritical, SecurityTreatAsSafe]
private void RaiseGotCapture(IInputElement captured)
{
Debug.Assert(captured != null, "captured should be non-null.");
TouchEventArgs e = CreateEventArgs(Touch.GotTouchCaptureEvent);
e.Source = captured;
_inputManager.ProcessInput(e);
}
///
/// Notifies subclasses that capture changed.
///
///
///
protected virtual void OnCapture(IInputElement element, CaptureMode captureMode)
{
}
#endregion
#region Updating State
protected bool ReportDown()
{
EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info, EventTrace.Event.TouchDownReported, _deviceId);
_isDown = true;
UpdateDirectlyOver(/* isSynchronize = */ false);
bool handled = RaiseTouchDown();
OnUpdated();
Touch.ReportFrame();
return handled;
}
protected bool ReportMove()
{
EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info, EventTrace.Event.TouchMoveReported, _deviceId);
UpdateDirectlyOver(/* isSynchronize = */ false);
bool handled = RaiseTouchMove();
OnUpdated();
Touch.ReportFrame();
return handled;
}
protected bool ReportUp()
{
EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info, EventTrace.Event.TouchUpReported, _deviceId);
bool handled = RaiseTouchUp();
_isDown = false;
UpdateDirectlyOver(/* isSynchronize = */ false);
OnUpdated();
Touch.ReportFrame();
return handled;
}
protected void Activate()
{
if (_isActive)
{
throw new InvalidOperationException(SR.Get(SRID.Touch_DeviceAlreadyActivated));
}
PromotingToManipulation = false;
AddActiveDevice(this);
AttachTouchDevice();
Synchronize();
if (_activeDevices.Count == 1)
{
_isPrimary = true;
}
_isActive = true;
if (Activated != null)
{
Activated(this, EventArgs.Empty);
}
}
protected void Deactivate()
{
if (!_isActive)
{
throw new InvalidOperationException(SR.Get(SRID.Touch_DeviceNotActivated));
}
Capture(null);
DetachTouchDevice();
RemoveActiveDevice(this);
_isActive = false;
_manipulatingElement = null;
if (Deactivated != null)
{
Deactivated(this, EventArgs.Empty);
}
}
///
/// Forces the TouchDevice to resynchronize.
///
///
/// Critical: Accesses _activeSource
/// PublicOK: Does not expose _activeSource.
///
[SecurityCritical]
public void Synchronize()
{
if (_activeSource != null &&
_activeSource.CompositionTarget != null &&
!_activeSource.CompositionTarget.IsDisposed)
{
if (UpdateDirectlyOver(/* isSynchronize = */ true))
{
OnUpdated();
Touch.ReportFrame();
}
}
}
///
/// Critical: Calling this method would do mouse promotions.
/// PublicOK: This method has a demand on it.
/// Demand: Technically the demand is not needed because the
/// user can already do this indirectly by canceling the
/// manipulation. But the decision is to limit the scope
/// of this raw method to full trust.
///
[SecurityCritical, UIPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
protected virtual void OnManipulationEnded(bool cancel)
{
UIElement manipulatableElement = GetManipulatableElement();
if (manipulatableElement != null && PromotingToManipulation)
{
Capture(null);
}
}
protected virtual void OnManipulationStarted()
{
}
private void OnHitTestInvalidatedAsync(object sender, EventArgs e)
{
// The hit-test result may have changed.
Synchronize();
if ((_directlyOverTreeState != null) && !_directlyOverTreeState.IsEmpty)
{
UpdateReverseInheritedProperty(/* capture = */ false, _directlyOver, _directlyOver);
}
}
private bool UpdateDirectlyOver(bool isSynchronize)
{
IInputElement newDirectlyOver = null;
TouchPoint touchPoint = GetTouchPoint(null);
if (touchPoint != null)
{
Point position = touchPoint.Position;
newDirectlyOver = CriticalHitTest(position, isSynchronize);
}
if (newDirectlyOver != _directlyOver)
{
ChangeDirectlyOver(newDirectlyOver);
return true;
}
else
{
return false;
}
}
private void OnReevaluateDirectlyOver(object sender, DependencyPropertyChangedEventArgs e)
{
ReevaluateDirectlyOverAsync(null, null, true);
}
internal static void ReevaluateDirectlyOver(DependencyObject element, DependencyObject oldParent, bool isCoreParent)
{
int count = _activeDevices != null ? _activeDevices.Count : 0;
for (int i = 0; i < count; i++)
{
TouchDevice touchDevice = _activeDevices[i];
touchDevice.ReevaluateDirectlyOverAsync(element, oldParent, isCoreParent);
}
}
private void ReevaluateDirectlyOverAsync(DependencyObject element, DependencyObject oldParent, bool isCoreParent)
{
if (element != null)
{
if (_directlyOverTreeState == null)
{
_directlyOverTreeState = new DeferredElementTreeState();
}
if (isCoreParent)
{
_directlyOverTreeState.SetCoreParent(element, oldParent);
}
else
{
_directlyOverTreeState.SetLogicalParent(element, oldParent);
}
}
if (_reevaluateOver == null)
{
_reevaluateOver = Dispatcher.BeginInvoke(DispatcherPriority.Input,
(DispatcherOperationCallback)delegate(object args)
{
_reevaluateOver = null;
OnHitTestInvalidatedAsync(this, EventArgs.Empty);
return null;
}, null);
}
}
private void ChangeDirectlyOver(IInputElement newDirectlyOver)
{
Debug.Assert(newDirectlyOver != _directlyOver, "ChangeDirectlyOver called when newDirectlyOver is the same as _directlyOver.");
IInputElement oldDirectlyOver = _directlyOver;
_directlyOver = newDirectlyOver;
UIElement oldUIElement;
ContentElement oldContentElement;
UIElement3D oldUIElement3D;
CastInputElement(oldDirectlyOver, out oldUIElement, out oldContentElement, out oldUIElement3D);
UIElement newUIElement;
ContentElement newContentElement;
UIElement3D newUIElement3D;
CastInputElement(newDirectlyOver, out newUIElement, out newContentElement, out newUIElement3D);
if (oldUIElement != null)
{
oldUIElement.IsEnabledChanged -= OnReevaluateDirectlyOver;
oldUIElement.IsVisibleChanged -= OnReevaluateDirectlyOver;
oldUIElement.IsHitTestVisibleChanged -= OnReevaluateDirectlyOver;
}
else if (oldContentElement != null)
{
oldContentElement.IsEnabledChanged -= OnReevaluateDirectlyOver;
}
else if (oldUIElement3D != null)
{
oldUIElement3D.IsEnabledChanged -= OnReevaluateDirectlyOver;
oldUIElement3D.IsVisibleChanged -= OnReevaluateDirectlyOver;
oldUIElement3D.IsHitTestVisibleChanged -= OnReevaluateDirectlyOver;
}
if (newUIElement != null)
{
newUIElement.IsEnabledChanged += OnReevaluateDirectlyOver;
newUIElement.IsVisibleChanged += OnReevaluateDirectlyOver;
newUIElement.IsHitTestVisibleChanged += OnReevaluateDirectlyOver;
}
else if (newContentElement != null)
{
newContentElement.IsEnabledChanged += OnReevaluateDirectlyOver;
}
else if (newUIElement3D != null)
{
newUIElement3D.IsEnabledChanged += OnReevaluateDirectlyOver;
newUIElement3D.IsVisibleChanged += OnReevaluateDirectlyOver;
newUIElement3D.IsHitTestVisibleChanged += OnReevaluateDirectlyOver;
}
UpdateReverseInheritedProperty(/* capture = */ false, oldDirectlyOver, newDirectlyOver);
if (oldDirectlyOver != null)
{
DependencyObject o = oldDirectlyOver as DependencyObject;
o.SetValue(UIElement.AreAnyTouchesDirectlyOverPropertyKey,
BooleanBoxes.Box(AreAnyTouchesCapturedOrDirectlyOver(oldDirectlyOver, /* isCapture = */ false)));
}
if (newDirectlyOver != null)
{
DependencyObject o = newDirectlyOver as DependencyObject;
o.SetValue(UIElement.AreAnyTouchesDirectlyOverPropertyKey, BooleanBoxes.TrueBox);
}
}
///
/// Action to raise the TouchEnter/TouchLeave events.
/// This will be executed by TouchesOver RevereInheritance
/// property class on the entire parent chain affected by the
/// changes in TouchDevice's DirectlyOver.
///
private Action RaiseTouchEnterOrLeaveAction
{
get
{
if (_raiseTouchEnterOrLeaveAction == null)
{
_raiseTouchEnterOrLeaveAction = new Action(RaiseTouchEnterOrLeave);
}
return _raiseTouchEnterOrLeaveAction;
}
}
///
/// Critical - Accesses _inputManager.
/// TreatAsSafe - Does not expose _inputManager and event raised is not critical.
///
[SecurityCritical, SecurityTreatAsSafe]
private void RaiseTouchEnterOrLeave(DependencyObject element, bool isLeave)
{
Debug.Assert(element != null);
TouchEventArgs touchEventArgs = CreateEventArgs(isLeave ? Touch.TouchLeaveEvent : Touch.TouchEnterEvent);
touchEventArgs.Source = element;
_inputManager.ProcessInput(touchEventArgs);
}
private TouchEventArgs CreateEventArgs(RoutedEvent routedEvent)
{
//
TouchEventArgs touchEventArgs = new TouchEventArgs(this, Environment.TickCount);
touchEventArgs.RoutedEvent = routedEvent;
return touchEventArgs;
}
///
/// Critical - Accesses _inputManager.
/// TreatAsSafe - Does not expose _inputManager and event raised is not critical.
///
[SecurityCritical, SecurityTreatAsSafe]
private bool RaiseTouchDown()
{
TouchEventArgs e = CreateEventArgs(Touch.PreviewTouchDownEvent);
_lastDownHandled = false;
_inputManager.ProcessInput(e);
// We want to return true if either of PreviewTouchDown or TouchDown
// events are handled. Hence we cannot use e.Handled which is only
// for preview.
return _lastDownHandled;
}
///
/// Critical - Accesses _inputManager.
/// TreatAsSafe - Does not expose _inputManager and event raised is not critical.
///
[SecurityCritical, SecurityTreatAsSafe]
private bool RaiseTouchMove()
{
TouchEventArgs e = CreateEventArgs(Touch.PreviewTouchMoveEvent);
_lastMoveHandled = false;
_inputManager.ProcessInput(e);
// We want to return true if either of PreviewTouchMove or TouchMove
// events are handled. Hence we cannot use e.Handled which is only
// for preview.
return _lastMoveHandled;
}
///
/// Critical - Accesses _inputManager.
/// TreatAsSafe - Does not expose _inputManager and event raised is not critical.
///
[SecurityCritical, SecurityTreatAsSafe]
private bool RaiseTouchUp()
{
TouchEventArgs e = CreateEventArgs(Touch.PreviewTouchUpEvent);
_lastUpHandled = false;
_inputManager.ProcessInput(e);
// We want to return true if either of PreviewTouchUp or TouchUp
// events are handled. Hence we cannot use e.Handled which is only
// for preview.
return _lastUpHandled;
}
#endregion
#region Input Processing and Promotion
///
/// Critical: This method can be used for input spoofing
///
[SecurityCritical]
private void PostProcessInput(object sender, ProcessInputEventArgs e)
{
InputEventArgs inputEventArgs = e.StagingItem.Input;
if ((inputEventArgs != null) && (inputEventArgs.Device == this))
{
if (inputEventArgs.Handled)
{
RoutedEvent routedEvent = inputEventArgs.RoutedEvent;
if (routedEvent == Touch.PreviewTouchMoveEvent ||
routedEvent == Touch.TouchMoveEvent)
{
_lastMoveHandled = true;
}
else if (routedEvent == Touch.PreviewTouchDownEvent ||
routedEvent == Touch.TouchDownEvent)
{
_lastDownHandled = true;
}
else if (routedEvent == Touch.PreviewTouchUpEvent ||
routedEvent == Touch.TouchUpEvent)
{
_lastUpHandled = true;
}
}
else
{
bool forManipulation;
RoutedEvent promotedTouchEvent = PromotePreviewToMain(inputEventArgs.RoutedEvent, out forManipulation);
if (promotedTouchEvent != null)
{
TouchEventArgs promotedTouchEventArgs = CreateEventArgs(promotedTouchEvent);
e.PushInput(promotedTouchEventArgs, e.StagingItem);
}
else if (forManipulation)
{
UIElement manipulatableElement = GetManipulatableElement();
if (manipulatableElement != null)
{
PromoteMainToManipulation(manipulatableElement, (TouchEventArgs)inputEventArgs);
}
}
}
}
}
private RoutedEvent PromotePreviewToMain(RoutedEvent routedEvent, out bool forManipulation)
{
forManipulation = false;
if (routedEvent == Touch.PreviewTouchMoveEvent)
{
return Touch.TouchMoveEvent;
}
else if (routedEvent == Touch.PreviewTouchDownEvent)
{
return Touch.TouchDownEvent;
}
else if (routedEvent == Touch.PreviewTouchUpEvent)
{
return Touch.TouchUpEvent;
}
forManipulation = (routedEvent == Touch.TouchMoveEvent) ||
(routedEvent == Touch.TouchDownEvent) ||
(routedEvent == Touch.TouchUpEvent) ||
(routedEvent == Touch.GotTouchCaptureEvent) ||
(routedEvent == Touch.LostTouchCaptureEvent);
return null;
}
private UIElement GetManipulatableElement()
{
UIElement element = InputElement.GetContainingUIElement(_directlyOver as DependencyObject) as UIElement;
if (element != null)
{
element = Manipulation.FindManipulationParent(element);
}
return element;
}
private void PromoteMainToManipulation(UIElement manipulatableElement, TouchEventArgs touchEventArgs)
{
RoutedEvent routedEvent = touchEventArgs.RoutedEvent;
if (routedEvent == Touch.TouchDownEvent)
{
// When touch goes down or if we're in the middle of a move, capture so that we can
// start manipulation. We could be in the middle of a move if a device delayed
// promotion, such as the StylusTouchDevice, due to other gesture detection.
Capture(manipulatableElement);
}
else if ((routedEvent == Touch.TouchUpEvent) && PromotingToManipulation)
{
// When touch goes up, release capture so that we can stop manipulation.
Capture(null);
}
else if ((routedEvent == Touch.GotTouchCaptureEvent) && !PromotingToManipulation)
{
UIElement element = _captured as UIElement;
if (element != null && element.IsManipulationEnabled)
{
// When touch gets capture and if the captured element
// is manipulable, then add it as a manipulator to
// the captured element.
_manipulatingElement = new WeakReference(element);
Manipulation.AddManipulator(element, this);
PromotingToManipulation = true;
OnManipulationStarted();
}
}
else if ((routedEvent == Touch.LostTouchCaptureEvent) && PromotingToManipulation && _manipulatingElement != null)
{
UIElement element = _manipulatingElement.Target as UIElement;
_manipulatingElement = null;
if (element != null)
{
// When touch loses capture, remove it as a manipulator.
Manipulation.TryRemoveManipulator(element, this);
PromotingToManipulation = false;
}
}
}
///
/// Whether this device should promote to manipulation.
///
internal bool PromotingToManipulation
{
get;
private set;
}
#endregion
#region Active Devices
private static void AddActiveDevice(TouchDevice device)
{
if (_activeDevices == null)
{
_activeDevices = new List(2);
}
_activeDevices.Add(device);
}
private static void RemoveActiveDevice(TouchDevice device)
{
if (_activeDevices != null)
{
_activeDevices.Remove(device);
}
}
internal static TouchPointCollection GetTouchPoints(IInputElement relativeTo)
{
TouchPointCollection points = new TouchPointCollection();
if (_activeDevices != null)
{
int count = _activeDevices.Count;
for (int i = 0; i < count; i++)
{
TouchDevice device = _activeDevices[i];
points.Add(device.GetTouchPoint(relativeTo));
}
}
return points;
}
internal static TouchPoint GetPrimaryTouchPoint(IInputElement relativeTo)
{
if ((_activeDevices != null) && (_activeDevices.Count > 0))
{
TouchDevice device = _activeDevices[0];
if (device._isPrimary)
{
return device.GetTouchPoint(relativeTo);
}
}
return null;
}
internal static void ReleaseAllCaptures(IInputElement element)
{
if (_activeDevices != null)
{
int count = _activeDevices.Count;
for (int i = 0; i < count; i++)
{
TouchDevice device = _activeDevices[i];
if (device.Captured == element)
{
device.Capture(null);
}
}
}
}
internal static IEnumerable GetCapturedTouches(IInputElement element, bool includeWithin)
{
return GetCapturedOrOverTouches(element, includeWithin, /* isCapture = */ true);
}
internal static IEnumerable GetTouchesOver(IInputElement element, bool includeWithin)
{
return GetCapturedOrOverTouches(element, includeWithin, /* isCapture = */ false);
}
private static bool IsWithin(IInputElement parent, IInputElement child)
{
// We are assuming parent and child are Visual, Visual3D, or ContentElement
DependencyObject currentChild = child as DependencyObject;
while ((currentChild != null) && (currentChild != parent))
{
if (currentChild is Visual || currentChild is Visual3D)
{
currentChild = VisualTreeHelper.GetParent(currentChild);
}
else
{
currentChild = ((ContentElement)currentChild).Parent;
}
}
return (currentChild == parent);
}
private static IEnumerable GetCapturedOrOverTouches(IInputElement element, bool includeWithin, bool isCapture)
{
List touches = new List();
if (_activeDevices != null)
{
int count = _activeDevices.Count;
for (int i = 0; i < count; i++)
{
TouchDevice device = _activeDevices[i];
IInputElement touchElement = isCapture ? device.Captured : device.DirectlyOver;
if ((touchElement != null) &&
((touchElement == element) ||
(includeWithin && IsWithin(element, touchElement))))
{
touches.Add(device);
}
}
}
return touches;
}
private static bool AreAnyTouchesCapturedOrDirectlyOver(IInputElement element, bool isCapture)
{
if (_activeDevices != null)
{
int count = _activeDevices.Count;
for (int i = 0; i < count; i++)
{
TouchDevice device = _activeDevices[i];
IInputElement touchElement = isCapture ? device.Captured : device.DirectlyOver;
if (touchElement != null &&
touchElement == element)
{
return true;
}
}
}
return false;
}
#endregion
#region IManipulator
int IManipulator.Id
{
get
{
return Id;
}
}
Point IManipulator.GetPosition(IInputElement relativeTo)
{
return GetTouchPoint(relativeTo).Position;
}
public event EventHandler Updated;
private void OnUpdated()
{
if (Updated != null)
{
Updated(this, EventArgs.Empty);
}
}
///
/// Critical: Calling this method would do mouse promotions.
/// PublicOK: This method has a demand on it.
/// Demand: Technically the demand is not needed because the
/// user can already do this indirectly by canceling the
/// manipulation. But the decision is to limit the scope
/// of this raw method to full trust.
///
[SecurityCritical, UIPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
void IManipulator.ManipulationEnded(bool cancel)
{
this.OnManipulationEnded(cancel);
}
#endregion
#region Data
private int _deviceId;
private IInputElement _directlyOver;
private IInputElement _captured;
private CaptureMode _captureMode;
private bool _isDown;
private DispatcherOperation _reevaluateCapture;
private DispatcherOperation _reevaluateOver;
private DeferredElementTreeState _directlyOverTreeState;
private DeferredElementTreeState _capturedWithinTreeState;
private bool _isPrimary;
private bool _isActive;
private Action _raiseTouchEnterOrLeaveAction;
// Technically only one flag is needed as per current code. But if
// one of the derived touch devices raise a synchronizing TouchMove event,
// while raising TouchUp, things would be messed up. Hence using three
// different flags.
private bool _lastDownHandled;
private bool _lastUpHandled;
private bool _lastMoveHandled;
///
/// Critical - PresentationSource must be protected.
///
[SecurityCritical]
private PresentationSource _activeSource;
///
/// Critical - InputManager must be protected.
///
[SecurityCritical]
private InputManager _inputManager;
private WeakReference _manipulatingElement;
[ThreadStatic]
private static List _activeDevices;
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SchemaImporterExtension.cs
- SapiRecoInterop.cs
- XmlParser.cs
- TextEditorParagraphs.cs
- ObjectQuery_EntitySqlExtensions.cs
- SafeEventLogWriteHandle.cs
- DropShadowEffect.cs
- TreeViewCancelEvent.cs
- ObjectQuery_EntitySqlExtensions.cs
- SqlFormatter.cs
- QilVisitor.cs
- ExtendedPropertyDescriptor.cs
- StringCollectionEditor.cs
- DataGridViewMethods.cs
- IsolatedStorageFile.cs
- TokenCreationException.cs
- AppDomain.cs
- ReflectionTypeLoadException.cs
- AsyncOperation.cs
- PerformanceCounterPermission.cs
- Throw.cs
- DataBindingCollection.cs
- RsaSecurityTokenAuthenticator.cs
- DetailsViewModeEventArgs.cs
- GZipDecoder.cs
- Timer.cs
- StyleTypedPropertyAttribute.cs
- BamlRecordWriter.cs
- CellParagraph.cs
- UserInitiatedRoutedEventPermissionAttribute.cs
- InvokeHandlers.cs
- CancellableEnumerable.cs
- FunctionImportElement.cs
- HtmlGenericControl.cs
- ToolStripItemRenderEventArgs.cs
- CaseInsensitiveComparer.cs
- MembershipValidatePasswordEventArgs.cs
- WarningException.cs
- WebBrowserNavigatedEventHandler.cs
- NamedPermissionSet.cs
- ServiceNameElementCollection.cs
- PriorityQueue.cs
- PropertyTabChangedEvent.cs
- TranslateTransform.cs
- EventWaitHandleSecurity.cs
- ToolStripDropTargetManager.cs
- XamlFxTrace.cs
- ellipse.cs
- RadioButtonBaseAdapter.cs
- XsltSettings.cs
- RegexParser.cs
- DbProviderFactories.cs
- DrawingContext.cs
- ProcessHostFactoryHelper.cs
- UrlPath.cs
- LookupNode.cs
- KeyTimeConverter.cs
- SmtpSection.cs
- AtomicFile.cs
- MenuTracker.cs
- DecoratedNameAttribute.cs
- Constants.cs
- SqlDataSourceCustomCommandPanel.cs
- WaveHeader.cs
- SqlCharStream.cs
- isolationinterop.cs
- ResourceReferenceKeyNotFoundException.cs
- Run.cs
- EngineSite.cs
- CodeObject.cs
- ClientCredentialsElement.cs
- XmlQueryContext.cs
- BmpBitmapDecoder.cs
- TextTreeTextBlock.cs
- TextParagraphCache.cs
- FormParameter.cs
- RenderDataDrawingContext.cs
- SessionIDManager.cs
- BuildDependencySet.cs
- TableParagraph.cs
- MetadataStore.cs
- JsonUriDataContract.cs
- AnonymousIdentificationModule.cs
- ExpressionBuilder.cs
- UrlMappingsModule.cs
- X509WindowsSecurityToken.cs
- ParameterRetriever.cs
- ThreadAttributes.cs
- _LoggingObject.cs
- DecoderBestFitFallback.cs
- MarshalByValueComponent.cs
- SecurityCriticalDataForSet.cs
- PolyLineSegment.cs
- connectionpool.cs
- SamlAuthenticationStatement.cs
- FileRecordSequenceCompletedAsyncResult.cs
- ServiceRouteHandler.cs
- InstanceOwner.cs
- InheritanceContextChangedEventManager.cs
- CatalogPartCollection.cs