Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Input / ManipulationDevice.cs / 1305600 / ManipulationDevice.cs
//----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//---------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
using System.Windows.Input.Manipulations;
using System.Windows.Media;
using System.Windows.Threading;
using System.Security;
using MS.Internal;
using MS.Internal.PresentationCore;
using MS.Utility;
namespace System.Windows.Input
{
///
/// Analyzes input events to be processed into manipulation and inertia events.
///
internal sealed class ManipulationDevice : InputDevice
{
///
/// Critical: Accesses PresentationSource.CriticalFromVisual.
/// TreatAsSafe: Stored in Critical field and exposed in Critical property.
/// Critical: Attaches to InputManager event handlers and stores a reference to the InputManager.
/// TreatAsSafe: Does not expose the InputManager externally.
///
///
/// Created in AddManipulationDevice.
///
[SecurityCritical, SecurityTreatAsSafe]
private ManipulationDevice(UIElement element) : base()
{
_target = element;
_activeSource = PresentationSource.CriticalFromVisual(element);
_inputManager = InputManager.UnsecureCurrent;
_inputManager.PostProcessInput += new ProcessInputEventHandler(PostProcessInput);
_manipulationLogic = new ManipulationLogic(this);
}
///
/// Critical: Detaches from InputManager event handlers.
/// TreatAsSafe: Does not expose the InputManager externally.
///
[SecurityCritical, SecurityTreatAsSafe]
private void DetachManipulationDevice()
{
_inputManager.PostProcessInput -= new ProcessInputEventHandler(PostProcessInput);
}
///
/// Returns the element that input from this device is sent to.
///
public override IInputElement Target
{
get { return _target; }
}
///
/// Returns the PresentationSource of Target.
///
///
/// SecurityCritical: Exposes a PresentationSource.
/// PublicOK: There is a demand.
///
public override PresentationSource ActiveSource
{
[SecurityCritical]
get
{
SecurityHelper.DemandUIWindowPermission();
return _activeSource;
}
}
///
/// Returns a ManipulationDevice associated with the given UIElement.
///
/// The target of the ManipulationDevice.
///
/// A ManipulationDevice associated with the element.
/// If a device already exists for the element, a reference to that instance
/// will be returned, otherwise a new instance will be created.
///
///
/// This function is thread-safe but should be called only on the
/// same thread that 'element' is bound to, due to possibly calling
/// the ManipulationDevice constructor.
///
internal static ManipulationDevice AddManipulationDevice(UIElement element)
{
Debug.Assert(element != null, "element should be non-null.");
element.VerifyAccess();
ManipulationDevice device = GetManipulationDevice(element);
if (device == null)
{
if (_manipulationDevices == null)
{
_manipulationDevices = new Dictionary(2);
}
device = new ManipulationDevice(element);
_manipulationDevices[element] = device;
}
return device;
}
///
/// Returns a ManipulationDevice associated with the given UIElement.
///
/// The target of the ManipulationDevice.
///
/// A ManipulationDevice associated with the element.
/// If a device does not already exists for the element, null is returned.
///
internal static ManipulationDevice GetManipulationDevice(UIElement element)
{
Debug.Assert(element != null, "element should be non-null.");
if (_manipulationDevices != null)
{
ManipulationDevice device;
_manipulationDevices.TryGetValue(element, out device);
return device;
}
return null;
}
///
/// When a ManipulationDevice is no longer needed, remove it
/// from the global list of devices.
///
private void RemoveManipulationDevice()
{
_wasTicking = false;
StopTicking();
DetachManipulationDevice();
_compensateForBoundaryFeedback = null;
RemoveAllManipulators();
if (_manipulationDevices != null)
{
_manipulationDevices.Remove(_target);
}
}
private void RemoveAllManipulators()
{
if (_manipulators != null)
{
for (int i = _manipulators.Count - 1; i >= 0; i--)
{
_manipulators[i].Updated -= OnManipulatorUpdated;
}
_manipulators.Clear();
}
}
internal void AddManipulator(IManipulator manipulator)
{
Debug.Assert(manipulator != null);
VerifyAccess();
_manipulationEnded = false;
if (_manipulators == null)
{
_manipulators = new List(2);
}
_manipulators.Add(manipulator);
manipulator.Updated += OnManipulatorUpdated;
// Adding a manipulator counts as an update
OnManipulatorUpdated(manipulator, EventArgs.Empty);
}
internal void RemoveManipulator(IManipulator manipulator)
{
Debug.Assert(manipulator != null);
VerifyAccess();
manipulator.Updated -= OnManipulatorUpdated;
if (_manipulators != null)
{
_manipulators.Remove(manipulator);
}
// Removing a manipulator counts as an update
OnManipulatorUpdated(manipulator, EventArgs.Empty);
if (!_manipulationEnded)
{
if (_manipulators == null || _manipulators.Count == 0)
{
// cache the last removed manipulator
_removedManipulator = manipulator;
}
// Call ReportFrame so that ManipulationInertiaStarting / ManipulationCompleted
// gets called synchronously if needed
ReportFrame();
_removedManipulator = null;
}
}
///
/// Critical - Accesses _manipulationLogic.
/// TreatAsSafe - OK to pass this information
///
internal ManipulationModes ManipulationMode
{
[SecurityCritical, SecurityTreatAsSafe]
get { return _manipulationLogic.ManipulationMode; }
[SecurityCritical, SecurityTreatAsSafe]
set { _manipulationLogic.ManipulationMode = value; }
}
///
/// Critical - Accesses _manipulationLogic.
/// TreatAsSafe - OK to pass this information
///
internal ManipulationPivot ManipulationPivot
{
[SecurityCritical, SecurityTreatAsSafe]
get { return _manipulationLogic.ManipulationPivot; }
[SecurityCritical, SecurityTreatAsSafe]
set { _manipulationLogic.ManipulationPivot = value; }
}
///
/// Critical - Accesses _manipulationLogic.
/// TreatAsSafe - OK to pass this information
///
internal IInputElement ManipulationContainer
{
[SecurityCritical, SecurityTreatAsSafe]
get { return _manipulationLogic.ManipulationContainer; }
[SecurityCritical, SecurityTreatAsSafe]
set { _manipulationLogic.ManipulationContainer = value; }
}
internal IEnumerable GetManipulatorsReadOnly()
{
if (_manipulators != null)
{
return new ReadOnlyCollection(_manipulators);
}
else
{
return new ReadOnlyCollection(new List(2));
}
}
internal void OnManipulatorUpdated(object sender, EventArgs e)
{
// After a period of inactivity, the ManipulationDevice will stop polling at the screen framerate
// to stop wasting CPU usage. This notification will tell the device that activity is happening
// so that it can know to poll.
LastUpdatedTimestamp = ManipulationLogic.GetCurrentTimestamp();
ResumeAllTicking(); // Resumes the ticking of all the suspended devices on the thread
StartTicking(); // Ensures that we continue ticking or restart ticking for this device
}
internal Point GetTransformedManipulatorPosition(Point point)
{
if (_compensateForBoundaryFeedback != null)
{
return _compensateForBoundaryFeedback(point);
}
return point;
}
///
/// Starts the ticking for all the ManipulationDevices
/// on the thread only if they were ticking earlier.
///
private static void ResumeAllTicking()
{
if (_manipulationDevices != null)
{
foreach (UIElement element in _manipulationDevices.Keys)
{
ManipulationDevice device = _manipulationDevices[element];
if (device != null && device._wasTicking)
{
device.StartTicking();
device._wasTicking = false;
}
}
}
}
private void StartTicking()
{
if (!_ticking)
{
_ticking = true;
CompositionTarget.Rendering += new EventHandler(OnRendering);
SubscribeToLayoutUpdate();
}
}
private void StopTicking()
{
if (_ticking)
{
CompositionTarget.Rendering -= new EventHandler(OnRendering);
_ticking = false;
UnsubscribeFromLayoutUpdate();
}
}
[SecurityCritical, SecurityTreatAsSafe]
private void SubscribeToLayoutUpdate()
{
_manipulationLogic.ContainerLayoutUpdated += OnContainerLayoutUpdated;
}
[SecurityCritical, SecurityTreatAsSafe]
private void UnsubscribeFromLayoutUpdate()
{
_manipulationLogic.ContainerLayoutUpdated -= OnContainerLayoutUpdated;
}
private void OnContainerLayoutUpdated(object sender, EventArgs e)
{
ReportFrame();
}
private void OnRendering(object sender, EventArgs e)
{
ReportFrame();
// If Manipulation didn't activate or becomes disabled, then stop ticking.
// If we've exceeded the timeout without any manipulators updating, then stop ticking
// to save energy. If a manipulator updates, we'll start ticking again.
if (!IsManipulationActive ||
(ManipulationLogic.GetCurrentTimestamp() - LastUpdatedTimestamp) > ThrottleTimeout)
{
_wasTicking = _ticking; // ReportFrame could have stopped the ticking, hence take the latest value.
StopTicking();
}
}
///
/// Critical - Accesses _manipulationLogic.
/// TreatAsSafe - Prods the logic object to do its work. Does not expose the object.
///
[SecurityCritical, SecurityTreatAsSafe]
private void ReportFrame()
{
if (!_manipulationEnded)
{
EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info, EventTrace.Event.ManipulationReportFrame, 0);
_manipulationLogic.ReportFrame(_manipulators);
}
}
///
/// Critical - Accesses _manipulationLogic.
/// TreatAsSafe - OK to report if manipulation is enabled.
///
internal bool IsManipulationActive
{
[SecurityCritical, SecurityTreatAsSafe]
get
{
return _manipulationLogic.IsManipulationActive;
}
}
///
/// Critical: This method can be used for input spoofing.
///
[SecurityCritical]
private void PostProcessInput(object sender, ProcessInputEventArgs e)
{
InputEventArgs inputEventArgs = e.StagingItem.Input;
if (inputEventArgs.Device == this)
{
RoutedEvent routedEvent = inputEventArgs.RoutedEvent;
if (routedEvent == Manipulation.ManipulationDeltaEvent)
{
ManipulationDeltaEventArgs deltaEventArgs = inputEventArgs as ManipulationDeltaEventArgs;
if (deltaEventArgs != null)
{
// During deltas, see if panning feedback is needed on the window
ManipulationDelta unusedManipulation = deltaEventArgs.UnusedManipulation;
_manipulationLogic.RaiseBoundaryFeedback(unusedManipulation, deltaEventArgs.RequestedComplete);
_manipulationLogic.PushEventsToDevice();
// If a Complete is requested, then pass it along to the manipulation processor
if (deltaEventArgs.RequestedComplete)
{
_manipulationLogic.Complete(/* withInertia = */ deltaEventArgs.RequestedInertia);
_manipulationLogic.PushEventsToDevice();
}
else if (deltaEventArgs.RequestedCancel)
{
Debug.Assert(!deltaEventArgs.IsInertial);
OnManipulationCancel();
}
}
}
else if (routedEvent == Manipulation.ManipulationStartingEvent)
{
ManipulationStartingEventArgs startingEventArgs = inputEventArgs as ManipulationStartingEventArgs;
if (startingEventArgs != null && startingEventArgs.RequestedCancel)
{
OnManipulationCancel();
}
}
else if (routedEvent == Manipulation.ManipulationStartedEvent)
{
ManipulationStartedEventArgs startedEventArgs = inputEventArgs as ManipulationStartedEventArgs;
if (startedEventArgs != null)
{
if (startedEventArgs.RequestedComplete)
{
// If a Complete is requested, pass it along to the manipulation processor
_manipulationLogic.Complete(/* withInertia = */ false);
_manipulationLogic.PushEventsToDevice();
}
else if (startedEventArgs.RequestedCancel)
{
OnManipulationCancel();
}
else
{
// Start ticking to produce delta events
ResumeAllTicking(); // Resumes the ticking of all the suspended devices on the thread
StartTicking(); // Ensures that we continue ticking or restart ticking for this device
}
}
}
else if (routedEvent == Manipulation.ManipulationInertiaStartingEvent)
{
// Switching from using rendering for ticking to a timer at lower priority (handled by ManipulationLogic)
StopTicking();
// Remove all the manipulators so that we dont re-start manipulations accidentally
RemoveAllManipulators();
// Initialize inertia
ManipulationInertiaStartingEventArgs inertiaEventArgs = inputEventArgs as ManipulationInertiaStartingEventArgs;
if (inertiaEventArgs != null)
{
if (inertiaEventArgs.RequestedCancel)
{
OnManipulationCancel();
}
else
{
_manipulationLogic.BeginInertia(inertiaEventArgs);
}
}
}
else if (routedEvent == Manipulation.ManipulationCompletedEvent)
{
_manipulationLogic.OnCompleted();
ManipulationCompletedEventArgs completedEventArgs = inputEventArgs as ManipulationCompletedEventArgs;
if (completedEventArgs != null)
{
if (completedEventArgs.RequestedCancel)
{
Debug.Assert(!completedEventArgs.IsInertial);
OnManipulationCancel();
}
else if (!(completedEventArgs.IsInertial && _ticking))
{
// Remove the manipulation device only if
// another manipulation didnot start
OnManipulationComplete();
}
}
}
else if (routedEvent == Manipulation.ManipulationBoundaryFeedbackEvent)
{
ManipulationBoundaryFeedbackEventArgs boundaryEventArgs = inputEventArgs as ManipulationBoundaryFeedbackEventArgs;
if (boundaryEventArgs != null)
{
_compensateForBoundaryFeedback = boundaryEventArgs.CompensateForBoundaryFeedback;
}
}
}
}
///
/// Critical: Calls IManipulator.ManipulationEnded which can
/// potentially do mouse promotions.
///
[SecurityCritical]
private void OnManipulationCancel()
{
_manipulationEnded = true;
if (_manipulators != null)
{
if (_removedManipulator != null)
{
Debug.Assert(_manipulators == null || _manipulators.Count == 0);
// Report Manipulation Cancel to last removed manipulator
_removedManipulator.ManipulationEnded(true);
}
else
{
// Report Manipulation Cancel to all the remaining manipulators
List manipulators = new List(_manipulators);
foreach (IManipulator manipulator in manipulators)
{
manipulator.ManipulationEnded(true);
}
}
}
RemoveManipulationDevice();
}
///
/// Critical: Calls IManipulator.ManipulationEnded which can
/// potentially do mouse promotions.
///
[SecurityCritical]
private void OnManipulationComplete()
{
_manipulationEnded = true;
if (_manipulators != null)
{
// Report Manipulation Complete to all the remaining manipulators
List manipulators = new List(_manipulators);
foreach (IManipulator manipulator in manipulators)
{
manipulator.ManipulationEnded(false);
}
}
RemoveManipulationDevice();
}
///
/// Critical - Accesses _manipulationLogic.
/// TreatAsSafe - Does not expose the object.
///
[SecurityCritical, SecurityTreatAsSafe]
internal void SetManipulationParameters(ManipulationParameters2D parameter)
{
_manipulationLogic.SetManipulationParameters(parameter);
}
///
/// Completes the pending manipulation or inertia.
///
///
/// Critical - Accesses _manipulationLogic.
/// TreatAsSafe - Does not expose the object.
///
[SecurityCritical, SecurityTreatAsSafe]
internal void CompleteManipulation(bool withInertia)
{
if (_manipulationLogic != null)
{
_manipulationLogic.Complete(withInertia);
_manipulationLogic.PushEventsToDevice();
}
}
///
/// Critical - Accesses _inputManager.
///
[SecurityCritical]
internal void ProcessManipulationInput(InputEventArgs e)
{
EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info, EventTrace.Event.ManipulationEventRaised, 0);
_inputManager.ProcessInput(e);
}
///
/// Critical: This data is not safe to expose as it holds refrence to PresentationSource.
///
[SecurityCritical]
private InputManager _inputManager;
///
/// Critical: Holds the the current manipulation state. Trusted to give manipulation events (and not spoofed input).
///
[SecurityCritical]
private ManipulationLogic _manipulationLogic;
///
/// PresentationSource is protected data.
///
[SecurityCritical]
private PresentationSource _activeSource;
private UIElement _target;
private List _manipulators;
private bool _ticking;
private bool _wasTicking; // boolean used to track suspended manipulation devices
private Func _compensateForBoundaryFeedback;
private bool _manipulationEnded = false;
IManipulator _removedManipulator = null;
[ThreadStatic]
private static Int64 LastUpdatedTimestamp;
private const Int64 ThrottleTimeout = TimeSpan.TicksPerSecond * 5; // 5 seconds (in 100ns units) of no activity will throttle down
[ThreadStatic]
private static Dictionary _manipulationDevices;
}
}
// 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
- EngineSite.cs
- ZipIOLocalFileHeader.cs
- GeometryCollection.cs
- DateTimeOffsetAdapter.cs
- PersonalizableTypeEntry.cs
- Panel.cs
- _BasicClient.cs
- SelectionWordBreaker.cs
- ApplicationInfo.cs
- ResizeGrip.cs
- HtmlContainerControl.cs
- RepeaterDataBoundAdapter.cs
- QilParameter.cs
- LOSFormatter.cs
- PathGeometry.cs
- DESCryptoServiceProvider.cs
- HotCommands.cs
- _SslSessionsCache.cs
- CodeRegionDirective.cs
- EntityDataSourceDataSelectionPanel.cs
- ExpressionNormalizer.cs
- PerformanceCounterCategory.cs
- DateTimeAutomationPeer.cs
- ExpressionSelection.cs
- ProxyWebPartManager.cs
- SecurityDocument.cs
- Types.cs
- XmlDataLoader.cs
- IsolationInterop.cs
- FlowDocumentScrollViewer.cs
- DataContractAttribute.cs
- ListViewAutomationPeer.cs
- ToolStripDropTargetManager.cs
- EUCJPEncoding.cs
- TextEditorLists.cs
- AVElementHelper.cs
- PolicyUnit.cs
- StateDesigner.CommentLayoutGlyph.cs
- TabletDeviceInfo.cs
- ActivationServices.cs
- ListManagerBindingsCollection.cs
- SingleKeyFrameCollection.cs
- SafeRegistryHandle.cs
- NumberAction.cs
- DivideByZeroException.cs
- DataControlFieldCell.cs
- Message.cs
- XmlSiteMapProvider.cs
- ButtonBaseDesigner.cs
- FloatUtil.cs
- VirtualPathUtility.cs
- SafeTokenHandle.cs
- VBIdentifierNameEditor.cs
- XslNumber.cs
- CompositeCollection.cs
- GuidelineCollection.cs
- ITreeGenerator.cs
- PageThemeCodeDomTreeGenerator.cs
- ListChangedEventArgs.cs
- ObjectStateEntry.cs
- ServicePoint.cs
- MemberPath.cs
- DynamicResourceExtension.cs
- Function.cs
- RootProfilePropertySettingsCollection.cs
- ZipIOCentralDirectoryDigitalSignature.cs
- GZipStream.cs
- DataGridTablesFactory.cs
- GraphicsContainer.cs
- TraceHandler.cs
- WindowsIPAddress.cs
- SortedList.cs
- UpdatePanel.cs
- OdbcEnvironment.cs
- Application.cs
- XmlChoiceIdentifierAttribute.cs
- RectangleGeometry.cs
- PropagatorResult.cs
- DataServiceBehavior.cs
- SqlExpressionNullability.cs
- SQLRoleProvider.cs
- BitmapEffectInput.cs
- SystemGatewayIPAddressInformation.cs
- CodeIndexerExpression.cs
- ExceptionValidationRule.cs
- DataTemplateKey.cs
- RouteTable.cs
- SoapException.cs
- DesignerPerfEventProvider.cs
- TransportBindingElementImporter.cs
- Lease.cs
- ContextProperty.cs
- RevocationPoint.cs
- filewebresponse.cs
- LinqExpressionNormalizer.cs
- Polyline.cs
- StyleSelector.cs
- SessionStateModule.cs
- AlternateViewCollection.cs
- WmlCommandAdapter.cs