Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / System / Windows / Input / Stylus / StylusDevice.cs / 1 / StylusDevice.cs
using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Specialized;
using System.Windows.Threading;
using System.Windows;
using System.Security;
using System.Security.Permissions;
using System.Windows.Media;
using System.Windows.Interop;
using MS.Internal;
using MS.Internal.PresentationCore; // SecurityHelper
using MS.Win32;
using System.Globalization;
using System.Windows.Input.StylusPlugIns;
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
namespace System.Windows.Input
{
/////////////////////////////////////////////////////////////////////////
///
/// The StylusDevice class represents the stylus device
///
public sealed class StylusDevice : InputDevice
{
/////////////////////////////////////////////////////////////////////
///
/// Critical - This is code that elevates AND creates the stylus device which
/// happens to hold the callback to filter stylus messages
/// TreatAsSafe: This constructor handles critical data but does not expose it
///
[SecurityCritical,SecurityTreatAsSafe]
internal StylusDevice(TabletDevice tabletDevice, string sName, int id, bool fInverted, StylusButtonCollection stylusButtonCollection)
{
_tabletDevice = tabletDevice;
_sName = sName;
_id = id;
_fInverted = fInverted;
// For tablet devices that can go out of range default them to
// being out of range until we see some events from it.
_fInRange = false; // All tablets out of range by default.
_stylusButtonCollection = stylusButtonCollection;
if (_stylusButtonCollection != null)
{
foreach (StylusButton button in _stylusButtonCollection)
{
button.SetOwner(this);
}
}
// Because the stylus device gets a steady stream of input events when it is in range,
// we don't have to be so careful about responding to layout changes as we have to be
// with the mouse.
// InputManager.Current.HitTestInvalidatedAsync += new EventHandler(OnHitTestInvalidatedAsync);
InputManager inputManager = (InputManager)Dispatcher.InputManager;
_stylusLogic = inputManager.StylusLogic;
_stylusLogic.RegisterStylusDeviceCore(this);
}
/////////////////////////////////////////////////////////////////////
///
/// Critical - Calls UnregisterStylusDeviceCore which can cause device
/// to be unusable.
/// This could be TreatAsSafe, but it is only called by a critical method
/// so we're leaving it as critical for now.
///
[SecurityCritical]
internal void Dispose()
{
_stylusLogic.UnregisterStylusDeviceCore(this);
// Make sure we clean up any references that could keep our object alive.
_inputSource = null;
_stylusCapture = null;
_stylusOver = null;
_nonVerifiedTarget = null;
_verifiedTarget = null;
_rtiCaptureChanged = null;
_stylusCapturePlugInCollection = null;
_fBlockMouseMoveChanges = false;
_tabletDevice = null;
_stylusLogic = null;
_fInRange = false;
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the element that input from this device is sent to.
///
public override IInputElement Target
{
get
{
VerifyAccess();
return _stylusOver;
}
}
///
/// Returns the PresentationSource that is reporting input for this device.
///
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
///
/// Critical - accesses critical data ( _inputSource)
/// PublicOK - there is a demand.
/// this is safe as:
/// there is a demand for the UI permissions in the code
///
public override PresentationSource ActiveSource
{
[SecurityCritical ]
get
{
SecurityHelper.DemandUIWindowPermission();
if (_inputSource != null)
{
return _inputSource.Value;
}
return null;
}
}
///
/// Returns the PresentationSource that is reporting input for this device.
///
///
/// Critical - accesses critical data (_inputSource) and returns it.
///
internal PresentationSource CriticalActiveSource
{
[SecurityCritical]
get
{
if (_inputSource != null)
{
return _inputSource.Value;
}
return null;
}
}
///
/// Returns the currently active PenContext (if seen) for this device.
/// Gets set on InRange and cleared on the out of range event (that matches PenContext).
///
///
/// Critical - accesses critical data (_activePenContext) and returns it.
///
internal PenContext ActivePenContext
{
[SecurityCritical]
get
{
if (_activePenContext != null)
{
return _activePenContext.Value;
}
return null;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the element that the stylus is over.
///
internal StylusPlugInCollection CurrentNonVerifiedTarget
{
get
{
return _nonVerifiedTarget;
}
set
{
_nonVerifiedTarget = value;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the element that the stylus is over.
///
internal StylusPlugInCollection CurrentVerifiedTarget
{
get
{
return _verifiedTarget;
}
set
{
_verifiedTarget = value;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the element that the stylus is over.
///
public IInputElement DirectlyOver
{
get
{
VerifyAccess();
return _stylusOver;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the element that has captured the stylus.
///
public IInputElement Captured
{
get
{
VerifyAccess();
return _stylusCapture;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the element that has captured the stylus.
///
internal CaptureMode CapturedMode
{
get
{
return _captureMode;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Captures the stylus to a particular element.
///
public bool Capture(IInputElement element, CaptureMode captureMode)
{
int timeStamp = Environment.TickCount;
VerifyAccess();
if (!(captureMode == CaptureMode.None || captureMode == CaptureMode.Element || captureMode == CaptureMode.SubTree))
{
throw new System.ComponentModel.InvalidEnumArgumentException("captureMode", (int)captureMode, typeof(CaptureMode));
}
if(element == null)
{
captureMode = CaptureMode.None;
}
if (captureMode == CaptureMode.None)
{
element = null;
}
// Validate that element is either a UIElement or a ContentElement
DependencyObject doStylusCapture = element as DependencyObject;
if (doStylusCapture != null && !InputElement.IsValid(element))
{
throw new InvalidOperationException(SR.Get(SRID.Invalid_IInputElement, doStylusCapture.GetType()));
}
if ( doStylusCapture != null )
{
doStylusCapture.VerifyAccess();
}
bool success = false;
// The element we are capturing to must be both enabled and visible.
UIElement e = element as UIElement;
if (e != null)
{
if(e.IsVisible || e.IsEnabled)
{
success = true;
}
}
else
{
ContentElement ce = element as ContentElement;
if (ce != null)
{
if(ce.IsEnabled) // There is no IsVisible property for ContentElement
{
success = true;
}
}
else
{
// Setting capture to null.
success = true;
}
}
if(success)
{
ChangeStylusCapture(element, captureMode, timeStamp);
}
return success;
}
///
/// Captures the stylus to a particular element.
///
public bool Capture(IInputElement element)
{
// No need for calling ApplyTemplate since we forward the call.
return Capture(element, CaptureMode.Element);
}
// called from the penthread to find out if a plugincollection has capture.
internal StylusPlugInCollection GetCapturedPlugInCollection(ref bool elementHasCapture)
{
// Take lock so both are returned with proper state since called from a pen thread.
lock(_rtiCaptureChanged)
{
elementHasCapture = (_stylusCapture != null);
return _stylusCapturePlugInCollection;
}
}
///
/// Forces the stylusdevice to resynchronize at it's current location and state.
/// It can conditionally generate a Stylus Move/InAirMove (at the current location) if a change
/// in hittesting is detected that requires an event be generated to update elements
/// to the current state (typically due to layout changes without Stylus changes).
/// Has the same behavior as MouseDevice.Synchronize().
///
///
/// Critical - accesses SecurityCritical Data _inputSource.Value and _stylusLogic.
/// - calls SecurityCritical code HwndSource.CriticalHandle,
/// StylusLogic.GetStylusPenContextForHwnd and
/// StylusLogic.InputManagerProcessInputEventsArgs (which can be used to spoof input).
/// PublicOK: This code does take any inputs or outputs nor is this operation risky (no
/// random Stylus input can be spoofed using this API).
///
[SecurityCritical]
public void Synchronize()
{
// Simulate a stylus move (if we are current stylus, inrange, visuals still valid to update
// and has moved).
if (InRange && _inputSource != null && _inputSource.Value != null &&
_inputSource.Value.CompositionTarget != null && !_inputSource.Value.CompositionTarget.IsDisposed)
{
Point ptDevice = PointUtil.ScreenToClient(_lastScreenLocation, _inputSource.Value);
// GlobalHitTest always returns an IInputElement, so we are sure to have one.
IInputElement stylusOver = GlobalHitTest(_inputSource.Value, ptDevice);
bool fOffsetChanged = false;
if (_stylusOver == stylusOver)
{
Point ptOffset = GetPosition(stylusOver);
fOffsetChanged = MS.Internal.DoubleUtil.AreClose(ptOffset.X, _rawElementRelativePosition.X) == false || MS.Internal.DoubleUtil.AreClose(ptOffset.Y, _rawElementRelativePosition.Y) == false;
}
if(fOffsetChanged || _stylusOver != stylusOver)
{
int timeStamp = Environment.TickCount;
PenContext penContext = _stylusLogic.GetStylusPenContextForHwnd(_inputSource.Value,TabletDevice.Id);
if (_eventStylusPoints != null &&
_eventStylusPoints.Count > 0 &&
StylusPointDescription.AreCompatible(penContext.StylusPointDescription, _eventStylusPoints.Description))
{
StylusPoint stylusPoint = _eventStylusPoints[_eventStylusPoints.Count - 1];
int[] data = stylusPoint.GetPacketData();
// get back to the correct coordinate system
Matrix m = TabletDevice.TabletToScreen;
m.Invert();
Point ptTablet = ptDevice * m;
data[0] = (int)ptTablet.X;
data[1] = (int)ptTablet.Y;
RawStylusInputReport report = new RawStylusInputReport(InputMode.Foreground,
timeStamp,
_inputSource.Value,
penContext,
InAir?RawStylusActions.InAirMove:RawStylusActions.Move,
TabletDevice.Id,
Id,
data);
report.Synchronized = true;
InputReportEventArgs inputReportEventArgs = new InputReportEventArgs(this, report);
inputReportEventArgs.RoutedEvent=InputManager.PreviewInputReportEvent;
_stylusLogic.InputManagerProcessInputEventArgs(inputReportEventArgs);
}
}
}
}
/////////////////////////////////////////////////////////////////////
// NOTE: This will typically get called for each stylus device on the
// system since Stylus.Capture will enumerate them all and call
// capture.
///
/// Critical: Calls SecurityCritical code (PresentationSource.CriticalFromVisual,
/// StylusLogic.GetPenContextsFromHwndand and StylusLogic.InputManagerProcessInputEventArgs).
/// Accesses SecurityCriticalData (_stylusLogic).
/// TreatAsSafe: This operation is ok to expose since stylus capture is ok. Even if you get the
/// source changed events you cannot get to the sources themselves
///
[SecurityCritical,SecurityTreatAsSafe]
internal void ChangeStylusCapture(IInputElement stylusCapture, CaptureMode captureMode, int timestamp)
{
// if the capture changed...
if(stylusCapture != _stylusCapture)
{
// Actually change the capture first. Invalidate the properties,
// and then send the events.
IInputElement oldStylusCapture = _stylusCapture;
using(Dispatcher.DisableProcessing()) // Disable reentrancy due to locks taken
{
lock(_rtiCaptureChanged)
{
_stylusCapture = stylusCapture;
_captureMode = captureMode;
// We also need to figure out ahead of time if any plugincollections on this captured element (or a parent)
// for the penthread hittesting code.
_stylusCapturePlugInCollection = null;
if (stylusCapture != null)
{
UIElement uiElement = InputElement.GetContainingUIElement(stylusCapture as DependencyObject) as UIElement;
if (uiElement != null)
{
PresentationSource source = PresentationSource.CriticalFromVisual(uiElement as Visual);
if (source != null)
{
PenContexts penContexts = _stylusLogic.GetPenContextsFromHwnd(source);
_stylusCapturePlugInCollection = penContexts.FindPlugInCollection(uiElement);
}
}
}
}
}
_stylusLogic.UpdateStylusCapture(this, oldStylusCapture, _stylusCapture, timestamp);
// Send the LostStylusCapture and GotStylusCapture events.
if(oldStylusCapture != null)
{
StylusEventArgs lostCapture = new StylusEventArgs(this, timestamp);
lostCapture.RoutedEvent=Stylus.LostStylusCaptureEvent;
lostCapture.Source= oldStylusCapture;
_stylusLogic.InputManagerProcessInputEventArgs(lostCapture);
}
if(_stylusCapture != null)
{
StylusEventArgs gotCapture = new StylusEventArgs(this, timestamp);
gotCapture.RoutedEvent=Stylus.GotStylusCaptureEvent;
gotCapture.Source= _stylusCapture;
_stylusLogic.InputManagerProcessInputEventArgs(gotCapture);
}
// Now update the stylus over state (only if this is the current stylus and
// it is inrange).
if (_stylusLogic.CurrentStylusDevice == this || InRange)
{
if (_stylusCapture != null)
{
IInputElement inputElementHit = _stylusCapture;
// See if we need to update over for subtree mode.
if (CapturedMode == CaptureMode.SubTree && _inputSource != null && _inputSource.Value != null)
{
Point pt = _stylusLogic.DeviceUnitsFromMeasureUnits(GetPosition(null));
inputElementHit = FindTarget(_inputSource.Value, pt);
}
ChangeStylusOver(inputElementHit);
}
else
{
// Only try to update over if we have a valid input source.
if (_inputSource != null && _inputSource.Value != null)
{
Point pt = GetPosition(null); // relative to window (root element)
pt = _stylusLogic.DeviceUnitsFromMeasureUnits(pt); // change back to device coords.
IInputElement currentOver = GlobalHitTest(_inputSource.Value, pt);
ChangeStylusOver(currentOver);
}
}
}
// For Mouse StylusDevice we want to make sure Mouse capture is set up the same.
if (Mouse.Captured != _stylusCapture || Mouse.CapturedMode != _captureMode)
{
Mouse.Capture(_stylusCapture, _captureMode);
}
}
}
/////////////////////////////////////////////////////////////////////
///
/// Critical - Accesses SecurityCriticalData _stylusLogic.
/// TreatAsSafe: This code does not expose the PresentationSource and simply changes the stylus over element
///
[SecurityCritical,SecurityTreatAsSafe]
internal void ChangeStylusOver(IInputElement stylusOver)
{
// We are not syncing the OverSourceChanged event
// the reasons for doing so are listed in the MouseDevice.cs OnOverSourceChanged implementation
if(_stylusOver != stylusOver)
{
_stylusOver = stylusOver;
_rawElementRelativePosition = GetPosition(_stylusOver);
}
else
{
// Always update the relative position if InRange since ChangeStylusOver is only
// called when something changed (like capture or stylus moved) and in
// that case we want this updated properly. This value is used in Synchronize().
if (InRange)
{
_rawElementRelativePosition = GetPosition(_stylusOver);
}
}
// The stylus over property is a singleton (only one stylus device at a time can
// be over an element) so we let StylusLogic manager the element over state.
// NOTE: StylusLogic only allows the CurrentStylusDevice to change the over state.
// Also note that Capture is also managed by StylusLogic in a similar fashion.
_stylusLogic.UpdateOverProperty(this, _stylusOver);
}
/////////////////////////////////////////////////////////////////////
///
/// Critical: - Uses security critical data (inputSource)
/// - TreatAsSafe boundry at ChangeStylusCapture
/// - called by ChangeStylusCapture
///
[SecurityCritical]
internal IInputElement FindTarget(PresentationSource inputSource, Point position)
{
IInputElement stylusOver = null;
switch (_captureMode)
{
case CaptureMode.None:
{
stylusOver = GlobalHitTest(inputSource, position);
// We understand UIElements and ContentElements.
// If we are over something else (like a raw visual)
// find the containing element.
if (!InputElement.IsValid(stylusOver))
stylusOver = InputElement.GetContainingInputElement(stylusOver as DependencyObject);
}
break;
case CaptureMode.Element:
//
stylusOver = _stylusCapture;
break;
case CaptureMode.SubTree:
{
IInputElement stylusCapture = InputElement.GetContainingInputElement(_stylusCapture as DependencyObject);
if ( stylusCapture != null && inputSource != 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.
stylusOver = GlobalHitTest(inputSource, position);
}
if (stylusOver != null && !InputElement.IsValid(stylusOver))
stylusOver = InputElement.GetContainingInputElement(stylusOver as DependencyObject);
// 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 (stylusOver != null)
{
IInputElement ieTest = stylusOver;
UIElement eTest = null;
ContentElement ceTest = null;
while (ieTest != null && ieTest != stylusCapture)
{
eTest = ieTest as UIElement;
if(eTest != null)
{
ieTest = InputElement.GetContainingInputElement(eTest.GetUIParent(true));
}
else
{
ceTest = ieTest as ContentElement; // Should never fail.
ieTest = InputElement.GetContainingInputElement(ceTest.GetUIParent(true));
}
}
// If we missed the capture point, we didn't hit anything.
if (ieTest != stylusCapture)
{
stylusOver = _stylusCapture;
}
}
else
{
// We didn't hit anything. Consider the stylus over the capture point.
stylusOver = _stylusCapture;
}
}
break;
}
return stylusOver;
}
/////////////////////////////////////////////////////////////////////
internal static IInputElement LocalHitTest(PresentationSource inputSource, Point pt)
{
return MouseDevice.LocalHitTest(pt, inputSource);
}
/////////////////////////////////////////////////////////////////////
internal static IInputElement GlobalHitTest(PresentationSource inputSource, Point pt)
{
return MouseDevice.GlobalHitTest(pt, inputSource);
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the tablet associated with the StylusDevice
///
public TabletDevice TabletDevice
{
get
{
// Don't do the VerifyAccess call any more since we need to call this prop
// from the pen thread to get access to internal data. The TabletDevice
// is already a DispatcherObject so it will do VerifyAccess() on any
// methods called on the wrong thread.
// VerifyAccess();
return _tabletDevice;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the name of the StylusDevice
///
public string Name
{
get
{
VerifyAccess();
return _sName;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the friendly representation of the StylusDevice
///
public override string ToString()
{
return String.Format(CultureInfo.CurrentCulture, "{0}({1})", base.ToString(), this.Name);
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the hardware id of the StylusDevice
///
public int Id
{
get
{
VerifyAccess();
return _id;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns a StylusPointCollection object for processing the data in the packet.
/// This method creates a new StylusPointCollection and copies the data.
///
public StylusPointCollection GetStylusPoints(IInputElement relativeTo)
{
VerifyAccess();
// Fake up an empty one if we have to.
if (_eventStylusPoints == null)
{
return new StylusPointCollection(TabletDevice.StylusPointDescription);
}
return _eventStylusPoints.Clone(GetElementTransform(relativeTo), _eventStylusPoints.Description);
}
/////////////////////////////////////////////////////////////////////
///
/// Returns a StylusPointCollection object for processing the data in the packet.
/// This method creates a new StylusPointCollection and copies the data.
///
public StylusPointCollection GetStylusPoints(IInputElement relativeTo, StylusPointDescription subsetToReformatTo)
{
if (null == subsetToReformatTo)
{
throw new ArgumentNullException("subsetToReformatTo");
}
// Fake up an empty one if we have to.
if (_eventStylusPoints == null)
{
return new StylusPointCollection(subsetToReformatTo);
}
return _eventStylusPoints.Reformat(subsetToReformatTo, GetElementTransform(relativeTo));
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the button collection that is associated with the StylusDevice.
///
public StylusButtonCollection StylusButtons
{
get
{
VerifyAccess();
return _stylusButtonCollection;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Calculates the position of the stylus relative to a particular element.
///
///
/// Critical - accesses critical data _inputSource.Value
/// PublicOK - we do the elevation of _inputSource to get RootVisual.
///
[SecurityCritical]
public Point GetPosition(IInputElement relativeTo)
{
VerifyAccess();
// Validate that relativeTo is either a UIElement or a ContentElement
if (relativeTo != null && !InputElement.IsValid(relativeTo))
{
throw new InvalidOperationException(SR.Get(SRID.Invalid_IInputElement, relativeTo.GetType()));
}
PresentationSource relativePresentationSource = null;
if (relativeTo != null)
{
DependencyObject dependencyObject = relativeTo as DependencyObject;
DependencyObject containingVisual = InputElement.GetContainingVisual(dependencyObject);
if(containingVisual != null)
{
relativePresentationSource = PresentationSource.CriticalFromVisual(containingVisual);
}
}
else
{
if (_inputSource != null)
{
relativePresentationSource = _inputSource.Value;
}
}
// Verify that we have a valid PresentationSource with a valid RootVisual
// - if we don't we won't be able to invoke ClientToRoot or TranslatePoint and
// we will just return 0,0
if (relativePresentationSource == null || relativePresentationSource.RootVisual == null)
{
return new Point(0, 0);
}
Point ptClient = PointUtil.ScreenToClient(_lastScreenLocation, relativePresentationSource);
Point ptRoot = PointUtil.ClientToRoot(ptClient, relativePresentationSource);
Point ptRelative = InputElement.TranslatePoint(ptRoot, relativePresentationSource.RootVisual, (DependencyObject)relativeTo);
return ptRelative;
}
///
/// This will return the same result as GetPosition if the packet data points
/// are not modified in the StylusPlugIns, otherwise it will return the unmodified
/// data
///
///
///
internal Point GetRawPosition(IInputElement relativeTo)
{
GeneralTransform transform = GetElementTransform(relativeTo);
Point pt;
transform.TryTransform(_rawPosition, out pt);
return pt;
}
///
/// Gets the current state of the specified button
///
///
/// The mouse button to get the state of
///
///
/// The MouseDevice that is making the request
///
///
/// The state of the specified mouse button
///
///
/// This is the hook where the Input system (via the MouseDevice) can call back into
/// the Stylus system when we are processing Stylus events instead of Mouse events
///
///
/// Critical: References SecurityCriticalData _stylusLogic.
/// TreatAsSafe: Takes no securityCriticalInput and returns safe data (MouseButtonState).
/// Called by MouseDevice for StylusDevice promoted mouse events to query
/// the mouse button state that should be reported.
///
[SecurityCritical, SecurityTreatAsSafe]
internal MouseButtonState GetMouseButtonState(MouseButton mouseButton, MouseDevice mouseDevice)
{
if (mouseButton == MouseButton.Left)
{
return _stylusLogic.GetMouseLeftOrRightButtonState(true);
}
if (mouseButton == MouseButton.Right)
{
return _stylusLogic.GetMouseLeftOrRightButtonState(false);
}
// can defer back to the mouse device that called you and it will call Win32
return mouseDevice.GetButtonStateFromSystem(mouseButton);
}
///
/// Gets the current position of the mouse in screen co-ords
///
///
/// The MouseDevice that is making the request
///
///
/// The current mouse location in screen co-ords
///
///
/// This is the hook where the Input system (via the MouseDevice) can call back into
/// the Stylus system when we are processing Stylus events instead of Mouse events
///
internal Point GetMouseScreenPosition(MouseDevice mouseDevice)
{
if (mouseDevice == null)
{
// return the last location this stylus device promoted a mouse for.
return _lastMouseScreenLocation;
}
else
{
// The mouse device now caches the last location seen from the last input
// report so we can just call back to them to get the location. We don't
// need to return our cached location currrently.
return mouseDevice.GetScreenPositionFromSystem();
}
}
/////////////////////////////////////////////////////////////////////
///
/// [TBS]
///
///
///
internal static GeneralTransform GetElementTransform(IInputElement relativeTo)
{
GeneralTransform elementTransform = Transform.Identity;
DependencyObject doRelativeTo = relativeTo as DependencyObject;
if (doRelativeTo != null)
{
Visual visualFirstAncestor = VisualTreeHelper.GetContainingVisual2D(InputElement.GetContainingVisual(doRelativeTo));
Visual visualRoot = VisualTreeHelper.GetContainingVisual2D(InputElement.GetRootVisual (doRelativeTo));
GeneralTransform g = visualRoot.TransformToDescendant(visualFirstAncestor);
if (g != null)
{
elementTransform = g;
}
}
return elementTransform;
}
/////////////////////////////////////////////////////////////////////
///
/// Critical - accesses critical member _stylusLogic
///
///
/// Returns the transform for converting from tablet to element
/// relative coordinates.
///
[SecurityCritical]
private GeneralTransform GetTabletToElementTransform(IInputElement relativeTo)
{
GeneralTransformGroup group = new GeneralTransformGroup();
group.Children.Add(new MatrixTransform(_stylusLogic.GetTabletToViewTransform(TabletDevice)));
group.Children.Add(GetElementTransform(relativeTo));
return group;
}
/////////////////////////////////////////////////////////////////////
///
/// Indicates the stylus is not touching the surface.
/// InAir events are general sent at a lower frequency.
///
public bool InAir
{
get
{
VerifyAccess();
return _fInAir;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Indicates stylusDevice is in the inverted state.
///
public bool Inverted
{
get
{
VerifyAccess();
return _fInverted;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Indicates stylusDevice is in the inverted state.
///
public bool InRange
{
get
{
VerifyAccess();
return _fInRange;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Critical - Can be used to spoof input.
/// At the top called from StylusLogic::PostProcessInput event which is SecurityCritical
///
[SecurityCritical]
internal void UpdateEventStylusPoints(RawStylusInputReport report, bool resetIfNoOverride)
{
if (report.RawStylusInput != null && report.RawStylusInput.StylusPointsModified)
{
GeneralTransform transformToElement = report.RawStylusInput.Target.ViewToElement.Inverse;
//note that RawStylusInput.Target (of type StylusPluginCollection)
//guarantees that ViewToElement is invertible
Debug.Assert(transformToElement != null);
_eventStylusPoints = report.RawStylusInput.GetStylusPoints(transformToElement);
}
else if (resetIfNoOverride)
{
_eventStylusPoints =
new StylusPointCollection(report.StylusPointDescription,
report.GetRawPacketData(),
GetTabletToElementTransform(null),
Matrix.Identity);
}
}
internal int TapCount
{
get {return _tapCount;}
set { _tapCount = value;}
}
internal int LastTapTime
{
get {return _lastTapTime;}
set { _lastTapTime = value;}
}
internal Point LastTapPoint
{
get {return _lastTapXY;}
set { _lastTapXY = value;}
}
internal bool LastTapBarrelDown
{
get {return _lastTapBarrelDown;}
set { _lastTapBarrelDown = value;}
}
internal int DoubleTapDeltaX
{
get {return (int)TabletDevice.DoubleTapSize.Width;}
}
internal int DoubleTapDeltaY
{
get {return (int)TabletDevice.DoubleTapSize.Height;}
}
///
/// Critical - Calls SecurityCritical method StylusLogic.CurrentlStylusLogic.
/// TreatAsSafe: Takes no input and returns safe data (double tap info - time delta for double tap).
///
internal int DoubleTapDeltaTime
{
[SecurityCritical, SecurityTreatAsSafe]
get {return _stylusLogic.DoubleTapDeltaTime;}
}
/////////////////////////////////////////////////////////////////////
///
/// Critical: creates SecurityCriticalData (_inputSource)
/// - Called from the StylusLogic::PreProcessInput event handler
///
[SecurityCritical]
internal void UpdateState(RawStylusInputReport report)
{
Debug.Assert(report.TabletDeviceId == _tabletDevice.Id);
Debug.Assert((report.Actions & RawStylusActions.None) == 0);
_eventStylusPoints =
new StylusPointCollection( report.StylusPointDescription,
report.GetRawPacketData(),
GetTabletToElementTransform(null),
Matrix.Identity);
PresentationSource inputSource = DetermineValidSource(report.InputSource, _eventStylusPoints, report.PenContext.Contexts);
// See if we need to remap the stylus data X and Y values to different presentation source.
if (inputSource != null && inputSource != report.InputSource)
{
Point newWindowLocation = PointUtil.ClientToScreen(new Point(0, 0), inputSource);
newWindowLocation = _stylusLogic.MeasureUnitsFromDeviceUnits(newWindowLocation);
Point oldWindowLocation = _stylusLogic.MeasureUnitsFromDeviceUnits(report.PenContext.Contexts.DestroyedLocation);
// Create translate matrix transform to shift coords to map points to new window location.
MatrixTransform additionalTransform = new MatrixTransform(new Matrix(1, 0, 0, 1,
oldWindowLocation.X - newWindowLocation.X,
oldWindowLocation.Y - newWindowLocation.Y));
_eventStylusPoints = _eventStylusPoints.Reformat(report.StylusPointDescription, additionalTransform);
}
_rawPosition =
(Point)_eventStylusPoints[_eventStylusPoints.Count - 1];
_inputSource = new SecurityCriticalDataClass(inputSource);
if (inputSource != null)
{
// Update our screen position from this move.
Point pt = _stylusLogic.DeviceUnitsFromMeasureUnits(_rawPosition);
_lastScreenLocation = PointUtil.ClientToScreen(pt, inputSource);
}
// If we are not blocked from updating the location we want to use for the
// promoted mouse location then update it. We set this flag in the post process phase
// of Stylus events (after they have fired).
if (!_fBlockMouseMoveChanges)
{
_lastMouseScreenLocation = _lastScreenLocation;
}
if ((report.Actions & RawStylusActions.Down) != 0 ||
(report.Actions & RawStylusActions.Move) != 0)
{
_fInAir = false;
// Keep the stylus down location for turning system gestures into mouse event
if ((report.Actions & RawStylusActions.Down) != 0)
{
_needToSendMouseDown = true;
// reset the gesture flag. This is used to determine if we will need to fabricate a systemgesture tap on the
// corresponding up event.
_fGestureWasFired = false;
_fDetectedDrag = false;
_seenHoldEnterGesture = false;
// Make sure our drag and move deltas are up to date.
TabletDevice.UpdateSizeDeltas(report.StylusPointDescription, _stylusLogic);
}
// See if we need to do our own Drag detection (on Stylus Move event)
else if (inputSource != null && _fBlockMouseMoveChanges && _seenDoubleTapGesture && !_fGestureWasFired && !_fDetectedDrag)
{
Size delta = TabletDevice.CancelSize;
// We use the first point of the packet data for Drag detection to try and
// filter out cases where the stylus skips when going down.
Point dragPosition =(Point)_eventStylusPoints[0];
dragPosition = _stylusLogic.DeviceUnitsFromMeasureUnits(dragPosition);
dragPosition = PointUtil.ClientToScreen(dragPosition, inputSource);
// See if we need to detect a Drag gesture. If so do the calculation.
if ((Math.Abs(_lastMouseScreenLocation.X - dragPosition.X) > delta.Width) ||
(Math.Abs(_lastMouseScreenLocation.Y - dragPosition.Y) > delta.Height))
{
_fDetectedDrag = true;
}
}
}
UpdateEventStylusPoints(report, false);
if ((report.Actions & RawStylusActions.Up) != 0 ||
(report.Actions & RawStylusActions.InAirMove) != 0)
{
_fInAir = true;
if ((report.Actions & RawStylusActions.Up) != 0)
{
_sawMouseButton1Down = false; // reset this on Stylus Up.
}
}
}
///////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
///
/// Critical: Gets passed critical data (inputSource and ignoreSource).
/// Calls SecurityCritical methods (PresentationSource.CompositionTarget,
/// PresentationSource.CriticalFromVisual, UnsafeNativeMethods.WindowFromPoint,
/// HwndSource.CriticalFromHwnd).
///
[SecurityCritical]
private PresentationSource DetermineValidSource(PresentationSource inputSource, StylusPointCollection stylusPoints, PenContexts penContextsOfPoints)
{
HwndSource hwndSource = (HwndSource)inputSource;
// See if window has been closed or is invalid
if (inputSource.CompositionTarget == null || inputSource.CompositionTarget.IsDisposed ||
hwndSource == null || hwndSource.IsHandleNull)
{
PresentationSource newSource = null;
// use capture as fallback first
if (_stylusCapture != null)
{
DependencyObject containingVisual = InputElement.GetContainingVisual(_stylusCapture as DependencyObject);
PresentationSource capturedSource = PresentationSource.CriticalFromVisual(containingVisual);
if (capturedSource != null &&
capturedSource.CompositionTarget != null &&
!capturedSource.CompositionTarget.IsDisposed)
{
newSource = capturedSource; // Good new source to use!
}
}
// Now try last screen point hittesting to find a new window/PresetationSource.
if (newSource == null && stylusPoints != null)
{
Point ptScreen;
// If we have the last penContext then we can remap the coordinates properly.
// Otherwise we just use the last stylus mouse location to figure out a PresenationSource.
if (penContextsOfPoints != null)
{
ptScreen = _stylusLogic.DeviceUnitsFromMeasureUnits((Point)stylusPoints[0]);
// map from window to screen (ie - add the window location).
ptScreen.Offset(penContextsOfPoints.DestroyedLocation.X, penContextsOfPoints.DestroyedLocation.Y);
}
else
{
ptScreen = _lastMouseScreenLocation;
}
IntPtr hwndHit = UnsafeNativeMethods.WindowFromPoint((int)ptScreen.X, (int)ptScreen.Y);
if (hwndHit != IntPtr.Zero)
{
HwndSource newHwndSource = HwndSource.CriticalFromHwnd(hwndHit);
if (newHwndSource != null && newHwndSource.Dispatcher == Dispatcher)
{
newSource = newHwndSource;
}
}
}
return newSource;
}
else
{
return inputSource;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Critical: Accesses security critical data _stylusLogic.
/// - Called from the StylusLogic::PreNotifyInput event handler
///
[SecurityCritical]
internal void UpdateInRange(bool inRange, PenContext penContext)
{
_fInRange = inRange;
// Make sure we clean the last _inputSource for down at this time.
//_inputSourceForDown = null;
if (inRange)
_activePenContext = new SecurityCriticalDataClass(penContext);
else
_activePenContext = null;
}
/////////////////////////////////////////////////////////////////////
///
/// Critical: Creates SecurityCriticalData (_inputSource) and accesses
/// SecurityCriticalData _stylusLogic.
/// - Called from the StylusLogic::PreNotifyInput event handler
///
[SecurityCritical]
internal void UpdateStateForSystemGesture(RawStylusSystemGestureInputReport report)
{
switch (report.SystemGesture)
{
case SystemGesture.Tap:
case SystemGesture.Drag:
// request the next mouse move to become LeftButtonDown
_fLeftButtonDownTrigger = true;
_fGestureWasFired = true;
break;
case SystemGesture.RightTap:
case SystemGesture.RightDrag:
// request the next mouse move to become RightButtonDown
_fLeftButtonDownTrigger = false;
_fGestureWasFired = true;
break;
case SystemGesture.HoldEnter:
// press & hold animation started..
_seenHoldEnterGesture = true;
break;
case SystemGesture.Flick:
// We don't do any mouse promotion for a flick!
_fGestureWasFired = true;
// Update the stylus location info just for flick gestures. This is because
// we want to fire the flick event not from the last stylus location
// (end of flick gesture) but from the beginning of the flick gesture
// (stylus down point) since this is the element that we query whether they
// allow flicks and since scrolling is targetted we need to scroll the
// element you really flicked on.
// Only route the flick if we have data we can send.
if (report.InputSource != null && _eventStylusPoints != null && _eventStylusPoints.Count > 0)
{
StylusPoint stylusPoint = _eventStylusPoints[_eventStylusPoints.Count - 1];
stylusPoint.X = report.GestureX;
stylusPoint.Y = report.GestureY;
// Update the current point with this data.
_eventStylusPoints = new StylusPointCollection(stylusPoint.Description,
stylusPoint.GetPacketData(),
GetTabletToElementTransform(null),
Matrix.Identity);
PresentationSource inputSource = DetermineValidSource(report.InputSource, _eventStylusPoints, report.PenContext.Contexts);
if (inputSource != null)
{
// See if we need to remap the stylus data X and Y values to different presentation source.
if (inputSource != report.InputSource)
{
Point newWindowLocation = PointUtil.ClientToScreen(new Point(0, 0), inputSource);
newWindowLocation = _stylusLogic.MeasureUnitsFromDeviceUnits(newWindowLocation);
Point oldWindowLocation = _stylusLogic.MeasureUnitsFromDeviceUnits(report.PenContext.Contexts.DestroyedLocation);
// Create translate matrix transform to shift coords to map points to new window location.
MatrixTransform additionalTransform = new MatrixTransform(new Matrix(1, 0, 0, 1,
oldWindowLocation.X - newWindowLocation.X,
oldWindowLocation.Y - newWindowLocation.Y));
_eventStylusPoints = _eventStylusPoints.Reformat(report.StylusPointDescription, additionalTransform);
}
_rawPosition = (Point)_eventStylusPoints[_eventStylusPoints.Count - 1];
_inputSource = new SecurityCriticalDataClass(inputSource);
Point pt = _stylusLogic.DeviceUnitsFromMeasureUnits(_rawPosition);
_lastScreenLocation = PointUtil.ClientToScreen(pt, inputSource);
}
}
break;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Critical - Calls in to SecurityCritical code (StylusLogic::InputManagerProcesssInput)
/// and accesses SecurityCriticalData _stylusLogic.
/// At the top called from StylusLogic::PostProcessInput event which is SecurityCritical
///
[SecurityCritical]
internal void PlayBackCachedDownInputReport(int timestamp)
{
if (_needToSendMouseDown)
{
// if we have marked this as handled we need to play the down otherwise we can ignore the down
// as it will be process anyway and either way we need to clean up the cached down
PresentationSource mouseInputSource = GetMousePresentationSource();
if (mouseInputSource != null)
{
Point pt = PointUtil.ScreenToClient(_lastMouseScreenLocation, mouseInputSource);
_needToSendMouseDown = false; // We've sent down, don't send again.
// Update the state we report to the mouse (GetButtonState).
_promotedMouseState = MouseButtonState.Pressed;
RawMouseActions actions = _fLeftButtonDownTrigger?RawMouseActions.Button1Press:RawMouseActions.Button2Press;
// StylusLogic manages the mouse state reported to the MouseDevice to deal with multiple stylusdevice input.
if (_stylusLogic.UpdateMouseButtonState(actions))
{
// See if we need to set the Mouse Activate flag.
InputManager inputManager = (InputManager)Dispatcher.InputManager;
if (inputManager != null)
{
if (inputManager.PrimaryMouseDevice.CriticalActiveSource != mouseInputSource)
{
actions |= RawMouseActions.Activate;
}
}
// Update the last event we've sent through.
_stylusLogic.SetLastRawMouseActions(actions);
RawMouseInputReport mouseInputReport = new RawMouseInputReport(
InputMode.Foreground, timestamp, mouseInputSource,
actions,
(int)pt.X, (int)pt.Y, 0, IntPtr.Zero);
InputReportEventArgs inputReportArgs = new InputReportEventArgs(this, mouseInputReport);
inputReportArgs.RoutedEvent=InputManager.PreviewInputReportEvent;
_stylusLogic.InputManagerProcessInputEventArgs(inputReportArgs);
}
}
_needToSendMouseDown = false; // so we don't try and resend it later.
}
}
/////////////////////////////////////////////////////////////////////
///
/// Critical: - Accesses and hands out critical data. (HwndSource)
/// - Calls SecurityCritical code PresentationSource.CriticalFromVisual.
/// At the top called from StylusLogic::PostProcessInput event which is SecurityCritical
///
[SecurityCritical]
internal PresentationSource GetMousePresentationSource()
{
// See if we need to adjust the mouse point to a different
// presentation source. We have to do this if the mouse has capture.
InputManager inputManager = (InputManager)Dispatcher.InputManager;
PresentationSource mouseInputSource = null;
if (inputManager != null)
{
IInputElement mouseCaptured = inputManager.PrimaryMouseDevice.Captured;
if (mouseCaptured != null)
{
// See if mouse is captured to a different window (HwndSource will be different)
// NOTE: Today we can only translate points between HwndSources (PresentationSource doesn't support this)
DependencyObject mouseCapturedVisual = InputElement.GetContainingVisual((DependencyObject)mouseCaptured);
if (mouseCapturedVisual != null)
{
mouseInputSource = PresentationSource.CriticalFromVisual(mouseCapturedVisual);
}
}
else if (_stylusOver != null)
{
// Use our current input source (or one we're may be over) if no capture.
mouseInputSource = (_inputSource != null && _inputSource.Value != null) ?
DetermineValidSource(_inputSource.Value, _eventStylusPoints, null) : null;
}
}
return mouseInputSource;
}
///
/// Critical as this calls a critical method. (PlayBackCachedDownInputReport)
/// and access critical member _inputReportCachedMoves
///
/// At the top called from StylusLogic::PostProcessInput event which is SecurityCritical
///
[SecurityCritical]
internal RawMouseActions GetMouseActionsFromStylusEventAndPlaybackCachedDown(RoutedEvent stylusEvent, StylusEventArgs stylusArgs)
{
if (stylusEvent == Stylus.StylusSystemGestureEvent)
{
// See if this is an OK gesture to trigger a mouse event on.
StylusSystemGestureEventArgs systemGestureArgs = (StylusSystemGestureEventArgs)stylusArgs;
if (systemGestureArgs.SystemGesture == SystemGesture.Tap ||
systemGestureArgs.SystemGesture == SystemGesture.RightTap ||
systemGestureArgs.SystemGesture == SystemGesture.Drag ||
systemGestureArgs.SystemGesture == SystemGesture.RightDrag ||
systemGestureArgs.SystemGesture == SystemGesture.Flick)
{
if (systemGestureArgs.SystemGesture == SystemGesture.Drag ||
systemGestureArgs.SystemGesture == SystemGesture.RightDrag ||
systemGestureArgs.SystemGesture == SystemGesture.Flick)
{
_fBlockMouseMoveChanges = false;
TapCount = 1; // reset on a drag or flick.
if (systemGestureArgs.SystemGesture == SystemGesture.Flick)
{
// Don't want to play down or cached moves.
_needToSendMouseDown = false;
}
else
{
PlayBackCachedDownInputReport(systemGestureArgs.Timestamp);
}
}
else //we have a Tap
{
PlayBackCachedDownInputReport(systemGestureArgs.Timestamp);
}
}
}
else if (stylusEvent == Stylus.StylusInAirMoveEvent)
{
return RawMouseActions.AbsoluteMove;
}
else if (stylusEvent == Stylus.StylusDownEvent)
{
_fLeftButtonDownTrigger = true; // Default to left click until system gesture says otherwise.
_fBlockMouseMoveChanges = true;
// See if we can promote the mouse button down right now.
if (_seenDoubleTapGesture || _sawMouseButton1Down)
{
PlayBackCachedDownInputReport(stylusArgs.Timestamp);
}
}
else if (stylusEvent == Stylus.StylusMoveEvent)
{
if (!_fBlockMouseMoveChanges)
{
return RawMouseActions.AbsoluteMove;
}
}
else if (stylusEvent == Stylus.StylusUpEvent)
{
_fBlockMouseMoveChanges = false;
_seenDoubleTapGesture = false; // reset this on Stylus Up.
_sawMouseButton1Down = false; // reset to make sure we don't promote a mouse down on the next stylus down.
if (_promotedMouseState == MouseButtonState.Pressed)
{
_promotedMouseState = MouseButtonState.Released;
RawMouseActions actions = _fLeftButtonDownTrigger ?
RawMouseActions.Button1Release :
RawMouseActions.Button2Release;
// Make sure we only promote a mouse up if the mouse is in the down
// state (UpdateMousebuttonState returns true in that case)!
if (_stylusLogic.UpdateMouseButtonState(actions))
{
return actions;
}
// else - just return default of RawMouseActions.None since we don't want this
// duplicate mouse up to be processed.
}
}
// Default return
return RawMouseActions.None;
}
/////////////////////////////////////////////////////////////////////
internal Point LastMouseScreenPoint
{
get { return _lastMouseScreenLocation; }
set { _lastMouseScreenLocation = value; }
}
internal bool SeenDoubleTapGesture
{
get { return _seenDoubleTapGesture; }
set { _seenDoubleTapGesture = value; }
}
internal bool SeenHoldEnterGesture
{
get { return _seenHoldEnterGesture; }
}
internal bool GestureWasFired
{
get { return _fGestureWasFired;}
}
internal bool SentMouseDown
{
get { return _promotedMouseState == MouseButtonState.Pressed;}
}
internal bool DetectedDrag
{
get { return _fDetectedDrag; }
}
internal bool LeftIsActiveMouseButton
{
get { return _fLeftButtonDownTrigger; }
}
internal void SetSawMouseButton1Down(bool sawMouseButton1Down)
{
_sawMouseButton1Down = sawMouseButton1Down;
}
internal bool IgnoreStroke
{
get { return _ignoreStroke; }
set { _ignoreStroke = value; }
}
/////////////////////////////////////////////////////////////////////
TabletDevice _tabletDevice;
string _sName;
int _id;
bool _fInverted;
bool _fInRange;
StylusButtonCollection _stylusButtonCollection;
IInputElement _stylusOver;
IInputElement _stylusCapture;
CaptureMode _captureMode;
Point _rawPosition = new Point(0, 0);
Point _rawElementRelativePosition = new Point(0, 0);
StylusPointCollection _eventStylusPoints;
///
/// This data is not safe to expose as it holds refrence to PresentationSource
///
private SecurityCriticalDataClass _inputSource;
///
/// This data is not safe to expose as it holds refrence to PenContext
///
private SecurityCriticalDataClass _activePenContext;
bool _needToSendMouseDown;
private Point _lastMouseScreenLocation = new Point(0,0);
private Point _lastScreenLocation = new Point(0,0);
bool _fInAir = true;
bool _fLeftButtonDownTrigger = true; // default to left button down
bool _fGestureWasFired = true; // StylusDown resets this.
bool _fBlockMouseMoveChanges; // StylusDown sets to true, SystemGesture & StylusUp sets to false.
bool _fDetectedDrag; // StylusDown resets this. Used for generating DoubleTap gestures.
// Used to track the promoted mouse state.
MouseButtonState _promotedMouseState;
// real time pen input info that is tracked per stylus device
StylusPlugInCollection _nonVerifiedTarget;
StylusPlugInCollection _verifiedTarget;
object _rtiCaptureChanged = new object();
StylusPlugInCollection _stylusCapturePlugInCollection;
// Information used to distinguish double-clicks (actually, multi clicks) from
// multiple independent clicks.
private Point _lastTapXY = new Point(0,0);
private int _tapCount;
private int _lastTapTime;
private bool _lastTapBarrelDown;
private bool _seenDoubleTapGesture;
private bool _seenHoldEnterGesture;
private bool _sawMouseButton1Down; // Did we see the mouse down before the stylus down?
private bool _ignoreStroke; // Should we ignore promoting the stylus/mouse events for the current stroke?
///
/// Critical to prevent accidental spread to transparent code
///
[SecurityCritical]
private StylusLogic _stylusLogic;
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Specialized;
using System.Windows.Threading;
using System.Windows;
using System.Security;
using System.Security.Permissions;
using System.Windows.Media;
using System.Windows.Interop;
using MS.Internal;
using MS.Internal.PresentationCore; // SecurityHelper
using MS.Win32;
using System.Globalization;
using System.Windows.Input.StylusPlugIns;
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
namespace System.Windows.Input
{
/////////////////////////////////////////////////////////////////////////
///
/// The StylusDevice class represents the stylus device
///
public sealed class StylusDevice : InputDevice
{
/////////////////////////////////////////////////////////////////////
///
/// Critical - This is code that elevates AND creates the stylus device which
/// happens to hold the callback to filter stylus messages
/// TreatAsSafe: This constructor handles critical data but does not expose it
///
[SecurityCritical,SecurityTreatAsSafe]
internal StylusDevice(TabletDevice tabletDevice, string sName, int id, bool fInverted, StylusButtonCollection stylusButtonCollection)
{
_tabletDevice = tabletDevice;
_sName = sName;
_id = id;
_fInverted = fInverted;
// For tablet devices that can go out of range default them to
// being out of range until we see some events from it.
_fInRange = false; // All tablets out of range by default.
_stylusButtonCollection = stylusButtonCollection;
if (_stylusButtonCollection != null)
{
foreach (StylusButton button in _stylusButtonCollection)
{
button.SetOwner(this);
}
}
// Because the stylus device gets a steady stream of input events when it is in range,
// we don't have to be so careful about responding to layout changes as we have to be
// with the mouse.
// InputManager.Current.HitTestInvalidatedAsync += new EventHandler(OnHitTestInvalidatedAsync);
InputManager inputManager = (InputManager)Dispatcher.InputManager;
_stylusLogic = inputManager.StylusLogic;
_stylusLogic.RegisterStylusDeviceCore(this);
}
/////////////////////////////////////////////////////////////////////
///
/// Critical - Calls UnregisterStylusDeviceCore which can cause device
/// to be unusable.
/// This could be TreatAsSafe, but it is only called by a critical method
/// so we're leaving it as critical for now.
///
[SecurityCritical]
internal void Dispose()
{
_stylusLogic.UnregisterStylusDeviceCore(this);
// Make sure we clean up any references that could keep our object alive.
_inputSource = null;
_stylusCapture = null;
_stylusOver = null;
_nonVerifiedTarget = null;
_verifiedTarget = null;
_rtiCaptureChanged = null;
_stylusCapturePlugInCollection = null;
_fBlockMouseMoveChanges = false;
_tabletDevice = null;
_stylusLogic = null;
_fInRange = false;
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the element that input from this device is sent to.
///
public override IInputElement Target
{
get
{
VerifyAccess();
return _stylusOver;
}
}
///
/// Returns the PresentationSource that is reporting input for this device.
///
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
///
/// Critical - accesses critical data ( _inputSource)
/// PublicOK - there is a demand.
/// this is safe as:
/// there is a demand for the UI permissions in the code
///
public override PresentationSource ActiveSource
{
[SecurityCritical ]
get
{
SecurityHelper.DemandUIWindowPermission();
if (_inputSource != null)
{
return _inputSource.Value;
}
return null;
}
}
///
/// Returns the PresentationSource that is reporting input for this device.
///
///
/// Critical - accesses critical data (_inputSource) and returns it.
///
internal PresentationSource CriticalActiveSource
{
[SecurityCritical]
get
{
if (_inputSource != null)
{
return _inputSource.Value;
}
return null;
}
}
///
/// Returns the currently active PenContext (if seen) for this device.
/// Gets set on InRange and cleared on the out of range event (that matches PenContext).
///
///
/// Critical - accesses critical data (_activePenContext) and returns it.
///
internal PenContext ActivePenContext
{
[SecurityCritical]
get
{
if (_activePenContext != null)
{
return _activePenContext.Value;
}
return null;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the element that the stylus is over.
///
internal StylusPlugInCollection CurrentNonVerifiedTarget
{
get
{
return _nonVerifiedTarget;
}
set
{
_nonVerifiedTarget = value;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the element that the stylus is over.
///
internal StylusPlugInCollection CurrentVerifiedTarget
{
get
{
return _verifiedTarget;
}
set
{
_verifiedTarget = value;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the element that the stylus is over.
///
public IInputElement DirectlyOver
{
get
{
VerifyAccess();
return _stylusOver;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the element that has captured the stylus.
///
public IInputElement Captured
{
get
{
VerifyAccess();
return _stylusCapture;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the element that has captured the stylus.
///
internal CaptureMode CapturedMode
{
get
{
return _captureMode;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Captures the stylus to a particular element.
///
public bool Capture(IInputElement element, CaptureMode captureMode)
{
int timeStamp = Environment.TickCount;
VerifyAccess();
if (!(captureMode == CaptureMode.None || captureMode == CaptureMode.Element || captureMode == CaptureMode.SubTree))
{
throw new System.ComponentModel.InvalidEnumArgumentException("captureMode", (int)captureMode, typeof(CaptureMode));
}
if(element == null)
{
captureMode = CaptureMode.None;
}
if (captureMode == CaptureMode.None)
{
element = null;
}
// Validate that element is either a UIElement or a ContentElement
DependencyObject doStylusCapture = element as DependencyObject;
if (doStylusCapture != null && !InputElement.IsValid(element))
{
throw new InvalidOperationException(SR.Get(SRID.Invalid_IInputElement, doStylusCapture.GetType()));
}
if ( doStylusCapture != null )
{
doStylusCapture.VerifyAccess();
}
bool success = false;
// The element we are capturing to must be both enabled and visible.
UIElement e = element as UIElement;
if (e != null)
{
if(e.IsVisible || e.IsEnabled)
{
success = true;
}
}
else
{
ContentElement ce = element as ContentElement;
if (ce != null)
{
if(ce.IsEnabled) // There is no IsVisible property for ContentElement
{
success = true;
}
}
else
{
// Setting capture to null.
success = true;
}
}
if(success)
{
ChangeStylusCapture(element, captureMode, timeStamp);
}
return success;
}
///
/// Captures the stylus to a particular element.
///
public bool Capture(IInputElement element)
{
// No need for calling ApplyTemplate since we forward the call.
return Capture(element, CaptureMode.Element);
}
// called from the penthread to find out if a plugincollection has capture.
internal StylusPlugInCollection GetCapturedPlugInCollection(ref bool elementHasCapture)
{
// Take lock so both are returned with proper state since called from a pen thread.
lock(_rtiCaptureChanged)
{
elementHasCapture = (_stylusCapture != null);
return _stylusCapturePlugInCollection;
}
}
///
/// Forces the stylusdevice to resynchronize at it's current location and state.
/// It can conditionally generate a Stylus Move/InAirMove (at the current location) if a change
/// in hittesting is detected that requires an event be generated to update elements
/// to the current state (typically due to layout changes without Stylus changes).
/// Has the same behavior as MouseDevice.Synchronize().
///
///
/// Critical - accesses SecurityCritical Data _inputSource.Value and _stylusLogic.
/// - calls SecurityCritical code HwndSource.CriticalHandle,
/// StylusLogic.GetStylusPenContextForHwnd and
/// StylusLogic.InputManagerProcessInputEventsArgs (which can be used to spoof input).
/// PublicOK: This code does take any inputs or outputs nor is this operation risky (no
/// random Stylus input can be spoofed using this API).
///
[SecurityCritical]
public void Synchronize()
{
// Simulate a stylus move (if we are current stylus, inrange, visuals still valid to update
// and has moved).
if (InRange && _inputSource != null && _inputSource.Value != null &&
_inputSource.Value.CompositionTarget != null && !_inputSource.Value.CompositionTarget.IsDisposed)
{
Point ptDevice = PointUtil.ScreenToClient(_lastScreenLocation, _inputSource.Value);
// GlobalHitTest always returns an IInputElement, so we are sure to have one.
IInputElement stylusOver = GlobalHitTest(_inputSource.Value, ptDevice);
bool fOffsetChanged = false;
if (_stylusOver == stylusOver)
{
Point ptOffset = GetPosition(stylusOver);
fOffsetChanged = MS.Internal.DoubleUtil.AreClose(ptOffset.X, _rawElementRelativePosition.X) == false || MS.Internal.DoubleUtil.AreClose(ptOffset.Y, _rawElementRelativePosition.Y) == false;
}
if(fOffsetChanged || _stylusOver != stylusOver)
{
int timeStamp = Environment.TickCount;
PenContext penContext = _stylusLogic.GetStylusPenContextForHwnd(_inputSource.Value,TabletDevice.Id);
if (_eventStylusPoints != null &&
_eventStylusPoints.Count > 0 &&
StylusPointDescription.AreCompatible(penContext.StylusPointDescription, _eventStylusPoints.Description))
{
StylusPoint stylusPoint = _eventStylusPoints[_eventStylusPoints.Count - 1];
int[] data = stylusPoint.GetPacketData();
// get back to the correct coordinate system
Matrix m = TabletDevice.TabletToScreen;
m.Invert();
Point ptTablet = ptDevice * m;
data[0] = (int)ptTablet.X;
data[1] = (int)ptTablet.Y;
RawStylusInputReport report = new RawStylusInputReport(InputMode.Foreground,
timeStamp,
_inputSource.Value,
penContext,
InAir?RawStylusActions.InAirMove:RawStylusActions.Move,
TabletDevice.Id,
Id,
data);
report.Synchronized = true;
InputReportEventArgs inputReportEventArgs = new InputReportEventArgs(this, report);
inputReportEventArgs.RoutedEvent=InputManager.PreviewInputReportEvent;
_stylusLogic.InputManagerProcessInputEventArgs(inputReportEventArgs);
}
}
}
}
/////////////////////////////////////////////////////////////////////
// NOTE: This will typically get called for each stylus device on the
// system since Stylus.Capture will enumerate them all and call
// capture.
///
/// Critical: Calls SecurityCritical code (PresentationSource.CriticalFromVisual,
/// StylusLogic.GetPenContextsFromHwndand and StylusLogic.InputManagerProcessInputEventArgs).
/// Accesses SecurityCriticalData (_stylusLogic).
/// TreatAsSafe: This operation is ok to expose since stylus capture is ok. Even if you get the
/// source changed events you cannot get to the sources themselves
///
[SecurityCritical,SecurityTreatAsSafe]
internal void ChangeStylusCapture(IInputElement stylusCapture, CaptureMode captureMode, int timestamp)
{
// if the capture changed...
if(stylusCapture != _stylusCapture)
{
// Actually change the capture first. Invalidate the properties,
// and then send the events.
IInputElement oldStylusCapture = _stylusCapture;
using(Dispatcher.DisableProcessing()) // Disable reentrancy due to locks taken
{
lock(_rtiCaptureChanged)
{
_stylusCapture = stylusCapture;
_captureMode = captureMode;
// We also need to figure out ahead of time if any plugincollections on this captured element (or a parent)
// for the penthread hittesting code.
_stylusCapturePlugInCollection = null;
if (stylusCapture != null)
{
UIElement uiElement = InputElement.GetContainingUIElement(stylusCapture as DependencyObject) as UIElement;
if (uiElement != null)
{
PresentationSource source = PresentationSource.CriticalFromVisual(uiElement as Visual);
if (source != null)
{
PenContexts penContexts = _stylusLogic.GetPenContextsFromHwnd(source);
_stylusCapturePlugInCollection = penContexts.FindPlugInCollection(uiElement);
}
}
}
}
}
_stylusLogic.UpdateStylusCapture(this, oldStylusCapture, _stylusCapture, timestamp);
// Send the LostStylusCapture and GotStylusCapture events.
if(oldStylusCapture != null)
{
StylusEventArgs lostCapture = new StylusEventArgs(this, timestamp);
lostCapture.RoutedEvent=Stylus.LostStylusCaptureEvent;
lostCapture.Source= oldStylusCapture;
_stylusLogic.InputManagerProcessInputEventArgs(lostCapture);
}
if(_stylusCapture != null)
{
StylusEventArgs gotCapture = new StylusEventArgs(this, timestamp);
gotCapture.RoutedEvent=Stylus.GotStylusCaptureEvent;
gotCapture.Source= _stylusCapture;
_stylusLogic.InputManagerProcessInputEventArgs(gotCapture);
}
// Now update the stylus over state (only if this is the current stylus and
// it is inrange).
if (_stylusLogic.CurrentStylusDevice == this || InRange)
{
if (_stylusCapture != null)
{
IInputElement inputElementHit = _stylusCapture;
// See if we need to update over for subtree mode.
if (CapturedMode == CaptureMode.SubTree && _inputSource != null && _inputSource.Value != null)
{
Point pt = _stylusLogic.DeviceUnitsFromMeasureUnits(GetPosition(null));
inputElementHit = FindTarget(_inputSource.Value, pt);
}
ChangeStylusOver(inputElementHit);
}
else
{
// Only try to update over if we have a valid input source.
if (_inputSource != null && _inputSource.Value != null)
{
Point pt = GetPosition(null); // relative to window (root element)
pt = _stylusLogic.DeviceUnitsFromMeasureUnits(pt); // change back to device coords.
IInputElement currentOver = GlobalHitTest(_inputSource.Value, pt);
ChangeStylusOver(currentOver);
}
}
}
// For Mouse StylusDevice we want to make sure Mouse capture is set up the same.
if (Mouse.Captured != _stylusCapture || Mouse.CapturedMode != _captureMode)
{
Mouse.Capture(_stylusCapture, _captureMode);
}
}
}
/////////////////////////////////////////////////////////////////////
///
/// Critical - Accesses SecurityCriticalData _stylusLogic.
/// TreatAsSafe: This code does not expose the PresentationSource and simply changes the stylus over element
///
[SecurityCritical,SecurityTreatAsSafe]
internal void ChangeStylusOver(IInputElement stylusOver)
{
// We are not syncing the OverSourceChanged event
// the reasons for doing so are listed in the MouseDevice.cs OnOverSourceChanged implementation
if(_stylusOver != stylusOver)
{
_stylusOver = stylusOver;
_rawElementRelativePosition = GetPosition(_stylusOver);
}
else
{
// Always update the relative position if InRange since ChangeStylusOver is only
// called when something changed (like capture or stylus moved) and in
// that case we want this updated properly. This value is used in Synchronize().
if (InRange)
{
_rawElementRelativePosition = GetPosition(_stylusOver);
}
}
// The stylus over property is a singleton (only one stylus device at a time can
// be over an element) so we let StylusLogic manager the element over state.
// NOTE: StylusLogic only allows the CurrentStylusDevice to change the over state.
// Also note that Capture is also managed by StylusLogic in a similar fashion.
_stylusLogic.UpdateOverProperty(this, _stylusOver);
}
/////////////////////////////////////////////////////////////////////
///
/// Critical: - Uses security critical data (inputSource)
/// - TreatAsSafe boundry at ChangeStylusCapture
/// - called by ChangeStylusCapture
///
[SecurityCritical]
internal IInputElement FindTarget(PresentationSource inputSource, Point position)
{
IInputElement stylusOver = null;
switch (_captureMode)
{
case CaptureMode.None:
{
stylusOver = GlobalHitTest(inputSource, position);
// We understand UIElements and ContentElements.
// If we are over something else (like a raw visual)
// find the containing element.
if (!InputElement.IsValid(stylusOver))
stylusOver = InputElement.GetContainingInputElement(stylusOver as DependencyObject);
}
break;
case CaptureMode.Element:
//
stylusOver = _stylusCapture;
break;
case CaptureMode.SubTree:
{
IInputElement stylusCapture = InputElement.GetContainingInputElement(_stylusCapture as DependencyObject);
if ( stylusCapture != null && inputSource != 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.
stylusOver = GlobalHitTest(inputSource, position);
}
if (stylusOver != null && !InputElement.IsValid(stylusOver))
stylusOver = InputElement.GetContainingInputElement(stylusOver as DependencyObject);
// 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 (stylusOver != null)
{
IInputElement ieTest = stylusOver;
UIElement eTest = null;
ContentElement ceTest = null;
while (ieTest != null && ieTest != stylusCapture)
{
eTest = ieTest as UIElement;
if(eTest != null)
{
ieTest = InputElement.GetContainingInputElement(eTest.GetUIParent(true));
}
else
{
ceTest = ieTest as ContentElement; // Should never fail.
ieTest = InputElement.GetContainingInputElement(ceTest.GetUIParent(true));
}
}
// If we missed the capture point, we didn't hit anything.
if (ieTest != stylusCapture)
{
stylusOver = _stylusCapture;
}
}
else
{
// We didn't hit anything. Consider the stylus over the capture point.
stylusOver = _stylusCapture;
}
}
break;
}
return stylusOver;
}
/////////////////////////////////////////////////////////////////////
internal static IInputElement LocalHitTest(PresentationSource inputSource, Point pt)
{
return MouseDevice.LocalHitTest(pt, inputSource);
}
/////////////////////////////////////////////////////////////////////
internal static IInputElement GlobalHitTest(PresentationSource inputSource, Point pt)
{
return MouseDevice.GlobalHitTest(pt, inputSource);
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the tablet associated with the StylusDevice
///
public TabletDevice TabletDevice
{
get
{
// Don't do the VerifyAccess call any more since we need to call this prop
// from the pen thread to get access to internal data. The TabletDevice
// is already a DispatcherObject so it will do VerifyAccess() on any
// methods called on the wrong thread.
// VerifyAccess();
return _tabletDevice;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the name of the StylusDevice
///
public string Name
{
get
{
VerifyAccess();
return _sName;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the friendly representation of the StylusDevice
///
public override string ToString()
{
return String.Format(CultureInfo.CurrentCulture, "{0}({1})", base.ToString(), this.Name);
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the hardware id of the StylusDevice
///
public int Id
{
get
{
VerifyAccess();
return _id;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Returns a StylusPointCollection object for processing the data in the packet.
/// This method creates a new StylusPointCollection and copies the data.
///
public StylusPointCollection GetStylusPoints(IInputElement relativeTo)
{
VerifyAccess();
// Fake up an empty one if we have to.
if (_eventStylusPoints == null)
{
return new StylusPointCollection(TabletDevice.StylusPointDescription);
}
return _eventStylusPoints.Clone(GetElementTransform(relativeTo), _eventStylusPoints.Description);
}
/////////////////////////////////////////////////////////////////////
///
/// Returns a StylusPointCollection object for processing the data in the packet.
/// This method creates a new StylusPointCollection and copies the data.
///
public StylusPointCollection GetStylusPoints(IInputElement relativeTo, StylusPointDescription subsetToReformatTo)
{
if (null == subsetToReformatTo)
{
throw new ArgumentNullException("subsetToReformatTo");
}
// Fake up an empty one if we have to.
if (_eventStylusPoints == null)
{
return new StylusPointCollection(subsetToReformatTo);
}
return _eventStylusPoints.Reformat(subsetToReformatTo, GetElementTransform(relativeTo));
}
/////////////////////////////////////////////////////////////////////
///
/// Returns the button collection that is associated with the StylusDevice.
///
public StylusButtonCollection StylusButtons
{
get
{
VerifyAccess();
return _stylusButtonCollection;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Calculates the position of the stylus relative to a particular element.
///
///
/// Critical - accesses critical data _inputSource.Value
/// PublicOK - we do the elevation of _inputSource to get RootVisual.
///
[SecurityCritical]
public Point GetPosition(IInputElement relativeTo)
{
VerifyAccess();
// Validate that relativeTo is either a UIElement or a ContentElement
if (relativeTo != null && !InputElement.IsValid(relativeTo))
{
throw new InvalidOperationException(SR.Get(SRID.Invalid_IInputElement, relativeTo.GetType()));
}
PresentationSource relativePresentationSource = null;
if (relativeTo != null)
{
DependencyObject dependencyObject = relativeTo as DependencyObject;
DependencyObject containingVisual = InputElement.GetContainingVisual(dependencyObject);
if(containingVisual != null)
{
relativePresentationSource = PresentationSource.CriticalFromVisual(containingVisual);
}
}
else
{
if (_inputSource != null)
{
relativePresentationSource = _inputSource.Value;
}
}
// Verify that we have a valid PresentationSource with a valid RootVisual
// - if we don't we won't be able to invoke ClientToRoot or TranslatePoint and
// we will just return 0,0
if (relativePresentationSource == null || relativePresentationSource.RootVisual == null)
{
return new Point(0, 0);
}
Point ptClient = PointUtil.ScreenToClient(_lastScreenLocation, relativePresentationSource);
Point ptRoot = PointUtil.ClientToRoot(ptClient, relativePresentationSource);
Point ptRelative = InputElement.TranslatePoint(ptRoot, relativePresentationSource.RootVisual, (DependencyObject)relativeTo);
return ptRelative;
}
///
/// This will return the same result as GetPosition if the packet data points
/// are not modified in the StylusPlugIns, otherwise it will return the unmodified
/// data
///
///
///
internal Point GetRawPosition(IInputElement relativeTo)
{
GeneralTransform transform = GetElementTransform(relativeTo);
Point pt;
transform.TryTransform(_rawPosition, out pt);
return pt;
}
///
/// Gets the current state of the specified button
///
///
/// The mouse button to get the state of
///
///
/// The MouseDevice that is making the request
///
///
/// The state of the specified mouse button
///
///
/// This is the hook where the Input system (via the MouseDevice) can call back into
/// the Stylus system when we are processing Stylus events instead of Mouse events
///
///
/// Critical: References SecurityCriticalData _stylusLogic.
/// TreatAsSafe: Takes no securityCriticalInput and returns safe data (MouseButtonState).
/// Called by MouseDevice for StylusDevice promoted mouse events to query
/// the mouse button state that should be reported.
///
[SecurityCritical, SecurityTreatAsSafe]
internal MouseButtonState GetMouseButtonState(MouseButton mouseButton, MouseDevice mouseDevice)
{
if (mouseButton == MouseButton.Left)
{
return _stylusLogic.GetMouseLeftOrRightButtonState(true);
}
if (mouseButton == MouseButton.Right)
{
return _stylusLogic.GetMouseLeftOrRightButtonState(false);
}
// can defer back to the mouse device that called you and it will call Win32
return mouseDevice.GetButtonStateFromSystem(mouseButton);
}
///
/// Gets the current position of the mouse in screen co-ords
///
///
/// The MouseDevice that is making the request
///
///
/// The current mouse location in screen co-ords
///
///
/// This is the hook where the Input system (via the MouseDevice) can call back into
/// the Stylus system when we are processing Stylus events instead of Mouse events
///
internal Point GetMouseScreenPosition(MouseDevice mouseDevice)
{
if (mouseDevice == null)
{
// return the last location this stylus device promoted a mouse for.
return _lastMouseScreenLocation;
}
else
{
// The mouse device now caches the last location seen from the last input
// report so we can just call back to them to get the location. We don't
// need to return our cached location currrently.
return mouseDevice.GetScreenPositionFromSystem();
}
}
/////////////////////////////////////////////////////////////////////
///
/// [TBS]
///
///
///
internal static GeneralTransform GetElementTransform(IInputElement relativeTo)
{
GeneralTransform elementTransform = Transform.Identity;
DependencyObject doRelativeTo = relativeTo as DependencyObject;
if (doRelativeTo != null)
{
Visual visualFirstAncestor = VisualTreeHelper.GetContainingVisual2D(InputElement.GetContainingVisual(doRelativeTo));
Visual visualRoot = VisualTreeHelper.GetContainingVisual2D(InputElement.GetRootVisual (doRelativeTo));
GeneralTransform g = visualRoot.TransformToDescendant(visualFirstAncestor);
if (g != null)
{
elementTransform = g;
}
}
return elementTransform;
}
/////////////////////////////////////////////////////////////////////
///
/// Critical - accesses critical member _stylusLogic
///
///
/// Returns the transform for converting from tablet to element
/// relative coordinates.
///
[SecurityCritical]
private GeneralTransform GetTabletToElementTransform(IInputElement relativeTo)
{
GeneralTransformGroup group = new GeneralTransformGroup();
group.Children.Add(new MatrixTransform(_stylusLogic.GetTabletToViewTransform(TabletDevice)));
group.Children.Add(GetElementTransform(relativeTo));
return group;
}
/////////////////////////////////////////////////////////////////////
///
/// Indicates the stylus is not touching the surface.
/// InAir events are general sent at a lower frequency.
///
public bool InAir
{
get
{
VerifyAccess();
return _fInAir;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Indicates stylusDevice is in the inverted state.
///
public bool Inverted
{
get
{
VerifyAccess();
return _fInverted;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Indicates stylusDevice is in the inverted state.
///
public bool InRange
{
get
{
VerifyAccess();
return _fInRange;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Critical - Can be used to spoof input.
/// At the top called from StylusLogic::PostProcessInput event which is SecurityCritical
///
[SecurityCritical]
internal void UpdateEventStylusPoints(RawStylusInputReport report, bool resetIfNoOverride)
{
if (report.RawStylusInput != null && report.RawStylusInput.StylusPointsModified)
{
GeneralTransform transformToElement = report.RawStylusInput.Target.ViewToElement.Inverse;
//note that RawStylusInput.Target (of type StylusPluginCollection)
//guarantees that ViewToElement is invertible
Debug.Assert(transformToElement != null);
_eventStylusPoints = report.RawStylusInput.GetStylusPoints(transformToElement);
}
else if (resetIfNoOverride)
{
_eventStylusPoints =
new StylusPointCollection(report.StylusPointDescription,
report.GetRawPacketData(),
GetTabletToElementTransform(null),
Matrix.Identity);
}
}
internal int TapCount
{
get {return _tapCount;}
set { _tapCount = value;}
}
internal int LastTapTime
{
get {return _lastTapTime;}
set { _lastTapTime = value;}
}
internal Point LastTapPoint
{
get {return _lastTapXY;}
set { _lastTapXY = value;}
}
internal bool LastTapBarrelDown
{
get {return _lastTapBarrelDown;}
set { _lastTapBarrelDown = value;}
}
internal int DoubleTapDeltaX
{
get {return (int)TabletDevice.DoubleTapSize.Width;}
}
internal int DoubleTapDeltaY
{
get {return (int)TabletDevice.DoubleTapSize.Height;}
}
///
/// Critical - Calls SecurityCritical method StylusLogic.CurrentlStylusLogic.
/// TreatAsSafe: Takes no input and returns safe data (double tap info - time delta for double tap).
///
internal int DoubleTapDeltaTime
{
[SecurityCritical, SecurityTreatAsSafe]
get {return _stylusLogic.DoubleTapDeltaTime;}
}
/////////////////////////////////////////////////////////////////////
///
/// Critical: creates SecurityCriticalData (_inputSource)
/// - Called from the StylusLogic::PreProcessInput event handler
///
[SecurityCritical]
internal void UpdateState(RawStylusInputReport report)
{
Debug.Assert(report.TabletDeviceId == _tabletDevice.Id);
Debug.Assert((report.Actions & RawStylusActions.None) == 0);
_eventStylusPoints =
new StylusPointCollection( report.StylusPointDescription,
report.GetRawPacketData(),
GetTabletToElementTransform(null),
Matrix.Identity);
PresentationSource inputSource = DetermineValidSource(report.InputSource, _eventStylusPoints, report.PenContext.Contexts);
// See if we need to remap the stylus data X and Y values to different presentation source.
if (inputSource != null && inputSource != report.InputSource)
{
Point newWindowLocation = PointUtil.ClientToScreen(new Point(0, 0), inputSource);
newWindowLocation = _stylusLogic.MeasureUnitsFromDeviceUnits(newWindowLocation);
Point oldWindowLocation = _stylusLogic.MeasureUnitsFromDeviceUnits(report.PenContext.Contexts.DestroyedLocation);
// Create translate matrix transform to shift coords to map points to new window location.
MatrixTransform additionalTransform = new MatrixTransform(new Matrix(1, 0, 0, 1,
oldWindowLocation.X - newWindowLocation.X,
oldWindowLocation.Y - newWindowLocation.Y));
_eventStylusPoints = _eventStylusPoints.Reformat(report.StylusPointDescription, additionalTransform);
}
_rawPosition =
(Point)_eventStylusPoints[_eventStylusPoints.Count - 1];
_inputSource = new SecurityCriticalDataClass(inputSource);
if (inputSource != null)
{
// Update our screen position from this move.
Point pt = _stylusLogic.DeviceUnitsFromMeasureUnits(_rawPosition);
_lastScreenLocation = PointUtil.ClientToScreen(pt, inputSource);
}
// If we are not blocked from updating the location we want to use for the
// promoted mouse location then update it. We set this flag in the post process phase
// of Stylus events (after they have fired).
if (!_fBlockMouseMoveChanges)
{
_lastMouseScreenLocation = _lastScreenLocation;
}
if ((report.Actions & RawStylusActions.Down) != 0 ||
(report.Actions & RawStylusActions.Move) != 0)
{
_fInAir = false;
// Keep the stylus down location for turning system gestures into mouse event
if ((report.Actions & RawStylusActions.Down) != 0)
{
_needToSendMouseDown = true;
// reset the gesture flag. This is used to determine if we will need to fabricate a systemgesture tap on the
// corresponding up event.
_fGestureWasFired = false;
_fDetectedDrag = false;
_seenHoldEnterGesture = false;
// Make sure our drag and move deltas are up to date.
TabletDevice.UpdateSizeDeltas(report.StylusPointDescription, _stylusLogic);
}
// See if we need to do our own Drag detection (on Stylus Move event)
else if (inputSource != null && _fBlockMouseMoveChanges && _seenDoubleTapGesture && !_fGestureWasFired && !_fDetectedDrag)
{
Size delta = TabletDevice.CancelSize;
// We use the first point of the packet data for Drag detection to try and
// filter out cases where the stylus skips when going down.
Point dragPosition =(Point)_eventStylusPoints[0];
dragPosition = _stylusLogic.DeviceUnitsFromMeasureUnits(dragPosition);
dragPosition = PointUtil.ClientToScreen(dragPosition, inputSource);
// See if we need to detect a Drag gesture. If so do the calculation.
if ((Math.Abs(_lastMouseScreenLocation.X - dragPosition.X) > delta.Width) ||
(Math.Abs(_lastMouseScreenLocation.Y - dragPosition.Y) > delta.Height))
{
_fDetectedDrag = true;
}
}
}
UpdateEventStylusPoints(report, false);
if ((report.Actions & RawStylusActions.Up) != 0 ||
(report.Actions & RawStylusActions.InAirMove) != 0)
{
_fInAir = true;
if ((report.Actions & RawStylusActions.Up) != 0)
{
_sawMouseButton1Down = false; // reset this on Stylus Up.
}
}
}
///////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
///
/// Critical: Gets passed critical data (inputSource and ignoreSource).
/// Calls SecurityCritical methods (PresentationSource.CompositionTarget,
/// PresentationSource.CriticalFromVisual, UnsafeNativeMethods.WindowFromPoint,
/// HwndSource.CriticalFromHwnd).
///
[SecurityCritical]
private PresentationSource DetermineValidSource(PresentationSource inputSource, StylusPointCollection stylusPoints, PenContexts penContextsOfPoints)
{
HwndSource hwndSource = (HwndSource)inputSource;
// See if window has been closed or is invalid
if (inputSource.CompositionTarget == null || inputSource.CompositionTarget.IsDisposed ||
hwndSource == null || hwndSource.IsHandleNull)
{
PresentationSource newSource = null;
// use capture as fallback first
if (_stylusCapture != null)
{
DependencyObject containingVisual = InputElement.GetContainingVisual(_stylusCapture as DependencyObject);
PresentationSource capturedSource = PresentationSource.CriticalFromVisual(containingVisual);
if (capturedSource != null &&
capturedSource.CompositionTarget != null &&
!capturedSource.CompositionTarget.IsDisposed)
{
newSource = capturedSource; // Good new source to use!
}
}
// Now try last screen point hittesting to find a new window/PresetationSource.
if (newSource == null && stylusPoints != null)
{
Point ptScreen;
// If we have the last penContext then we can remap the coordinates properly.
// Otherwise we just use the last stylus mouse location to figure out a PresenationSource.
if (penContextsOfPoints != null)
{
ptScreen = _stylusLogic.DeviceUnitsFromMeasureUnits((Point)stylusPoints[0]);
// map from window to screen (ie - add the window location).
ptScreen.Offset(penContextsOfPoints.DestroyedLocation.X, penContextsOfPoints.DestroyedLocation.Y);
}
else
{
ptScreen = _lastMouseScreenLocation;
}
IntPtr hwndHit = UnsafeNativeMethods.WindowFromPoint((int)ptScreen.X, (int)ptScreen.Y);
if (hwndHit != IntPtr.Zero)
{
HwndSource newHwndSource = HwndSource.CriticalFromHwnd(hwndHit);
if (newHwndSource != null && newHwndSource.Dispatcher == Dispatcher)
{
newSource = newHwndSource;
}
}
}
return newSource;
}
else
{
return inputSource;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Critical: Accesses security critical data _stylusLogic.
/// - Called from the StylusLogic::PreNotifyInput event handler
///
[SecurityCritical]
internal void UpdateInRange(bool inRange, PenContext penContext)
{
_fInRange = inRange;
// Make sure we clean the last _inputSource for down at this time.
//_inputSourceForDown = null;
if (inRange)
_activePenContext = new SecurityCriticalDataClass(penContext);
else
_activePenContext = null;
}
/////////////////////////////////////////////////////////////////////
///
/// Critical: Creates SecurityCriticalData (_inputSource) and accesses
/// SecurityCriticalData _stylusLogic.
/// - Called from the StylusLogic::PreNotifyInput event handler
///
[SecurityCritical]
internal void UpdateStateForSystemGesture(RawStylusSystemGestureInputReport report)
{
switch (report.SystemGesture)
{
case SystemGesture.Tap:
case SystemGesture.Drag:
// request the next mouse move to become LeftButtonDown
_fLeftButtonDownTrigger = true;
_fGestureWasFired = true;
break;
case SystemGesture.RightTap:
case SystemGesture.RightDrag:
// request the next mouse move to become RightButtonDown
_fLeftButtonDownTrigger = false;
_fGestureWasFired = true;
break;
case SystemGesture.HoldEnter:
// press & hold animation started..
_seenHoldEnterGesture = true;
break;
case SystemGesture.Flick:
// We don't do any mouse promotion for a flick!
_fGestureWasFired = true;
// Update the stylus location info just for flick gestures. This is because
// we want to fire the flick event not from the last stylus location
// (end of flick gesture) but from the beginning of the flick gesture
// (stylus down point) since this is the element that we query whether they
// allow flicks and since scrolling is targetted we need to scroll the
// element you really flicked on.
// Only route the flick if we have data we can send.
if (report.InputSource != null && _eventStylusPoints != null && _eventStylusPoints.Count > 0)
{
StylusPoint stylusPoint = _eventStylusPoints[_eventStylusPoints.Count - 1];
stylusPoint.X = report.GestureX;
stylusPoint.Y = report.GestureY;
// Update the current point with this data.
_eventStylusPoints = new StylusPointCollection(stylusPoint.Description,
stylusPoint.GetPacketData(),
GetTabletToElementTransform(null),
Matrix.Identity);
PresentationSource inputSource = DetermineValidSource(report.InputSource, _eventStylusPoints, report.PenContext.Contexts);
if (inputSource != null)
{
// See if we need to remap the stylus data X and Y values to different presentation source.
if (inputSource != report.InputSource)
{
Point newWindowLocation = PointUtil.ClientToScreen(new Point(0, 0), inputSource);
newWindowLocation = _stylusLogic.MeasureUnitsFromDeviceUnits(newWindowLocation);
Point oldWindowLocation = _stylusLogic.MeasureUnitsFromDeviceUnits(report.PenContext.Contexts.DestroyedLocation);
// Create translate matrix transform to shift coords to map points to new window location.
MatrixTransform additionalTransform = new MatrixTransform(new Matrix(1, 0, 0, 1,
oldWindowLocation.X - newWindowLocation.X,
oldWindowLocation.Y - newWindowLocation.Y));
_eventStylusPoints = _eventStylusPoints.Reformat(report.StylusPointDescription, additionalTransform);
}
_rawPosition = (Point)_eventStylusPoints[_eventStylusPoints.Count - 1];
_inputSource = new SecurityCriticalDataClass(inputSource);
Point pt = _stylusLogic.DeviceUnitsFromMeasureUnits(_rawPosition);
_lastScreenLocation = PointUtil.ClientToScreen(pt, inputSource);
}
}
break;
}
}
/////////////////////////////////////////////////////////////////////
///
/// Critical - Calls in to SecurityCritical code (StylusLogic::InputManagerProcesssInput)
/// and accesses SecurityCriticalData _stylusLogic.
/// At the top called from StylusLogic::PostProcessInput event which is SecurityCritical
///
[SecurityCritical]
internal void PlayBackCachedDownInputReport(int timestamp)
{
if (_needToSendMouseDown)
{
// if we have marked this as handled we need to play the down otherwise we can ignore the down
// as it will be process anyway and either way we need to clean up the cached down
PresentationSource mouseInputSource = GetMousePresentationSource();
if (mouseInputSource != null)
{
Point pt = PointUtil.ScreenToClient(_lastMouseScreenLocation, mouseInputSource);
_needToSendMouseDown = false; // We've sent down, don't send again.
// Update the state we report to the mouse (GetButtonState).
_promotedMouseState = MouseButtonState.Pressed;
RawMouseActions actions = _fLeftButtonDownTrigger?RawMouseActions.Button1Press:RawMouseActions.Button2Press;
// StylusLogic manages the mouse state reported to the MouseDevice to deal with multiple stylusdevice input.
if (_stylusLogic.UpdateMouseButtonState(actions))
{
// See if we need to set the Mouse Activate flag.
InputManager inputManager = (InputManager)Dispatcher.InputManager;
if (inputManager != null)
{
if (inputManager.PrimaryMouseDevice.CriticalActiveSource != mouseInputSource)
{
actions |= RawMouseActions.Activate;
}
}
// Update the last event we've sent through.
_stylusLogic.SetLastRawMouseActions(actions);
RawMouseInputReport mouseInputReport = new RawMouseInputReport(
InputMode.Foreground, timestamp, mouseInputSource,
actions,
(int)pt.X, (int)pt.Y, 0, IntPtr.Zero);
InputReportEventArgs inputReportArgs = new InputReportEventArgs(this, mouseInputReport);
inputReportArgs.RoutedEvent=InputManager.PreviewInputReportEvent;
_stylusLogic.InputManagerProcessInputEventArgs(inputReportArgs);
}
}
_needToSendMouseDown = false; // so we don't try and resend it later.
}
}
/////////////////////////////////////////////////////////////////////
///
/// Critical: - Accesses and hands out critical data. (HwndSource)
/// - Calls SecurityCritical code PresentationSource.CriticalFromVisual.
/// At the top called from StylusLogic::PostProcessInput event which is SecurityCritical
///
[SecurityCritical]
internal PresentationSource GetMousePresentationSource()
{
// See if we need to adjust the mouse point to a different
// presentation source. We have to do this if the mouse has capture.
InputManager inputManager = (InputManager)Dispatcher.InputManager;
PresentationSource mouseInputSource = null;
if (inputManager != null)
{
IInputElement mouseCaptured = inputManager.PrimaryMouseDevice.Captured;
if (mouseCaptured != null)
{
// See if mouse is captured to a different window (HwndSource will be different)
// NOTE: Today we can only translate points between HwndSources (PresentationSource doesn't support this)
DependencyObject mouseCapturedVisual = InputElement.GetContainingVisual((DependencyObject)mouseCaptured);
if (mouseCapturedVisual != null)
{
mouseInputSource = PresentationSource.CriticalFromVisual(mouseCapturedVisual);
}
}
else if (_stylusOver != null)
{
// Use our current input source (or one we're may be over) if no capture.
mouseInputSource = (_inputSource != null && _inputSource.Value != null) ?
DetermineValidSource(_inputSource.Value, _eventStylusPoints, null) : null;
}
}
return mouseInputSource;
}
///
/// Critical as this calls a critical method. (PlayBackCachedDownInputReport)
/// and access critical member _inputReportCachedMoves
///
/// At the top called from StylusLogic::PostProcessInput event which is SecurityCritical
///
[SecurityCritical]
internal RawMouseActions GetMouseActionsFromStylusEventAndPlaybackCachedDown(RoutedEvent stylusEvent, StylusEventArgs stylusArgs)
{
if (stylusEvent == Stylus.StylusSystemGestureEvent)
{
// See if this is an OK gesture to trigger a mouse event on.
StylusSystemGestureEventArgs systemGestureArgs = (StylusSystemGestureEventArgs)stylusArgs;
if (systemGestureArgs.SystemGesture == SystemGesture.Tap ||
systemGestureArgs.SystemGesture == SystemGesture.RightTap ||
systemGestureArgs.SystemGesture == SystemGesture.Drag ||
systemGestureArgs.SystemGesture == SystemGesture.RightDrag ||
systemGestureArgs.SystemGesture == SystemGesture.Flick)
{
if (systemGestureArgs.SystemGesture == SystemGesture.Drag ||
systemGestureArgs.SystemGesture == SystemGesture.RightDrag ||
systemGestureArgs.SystemGesture == SystemGesture.Flick)
{
_fBlockMouseMoveChanges = false;
TapCount = 1; // reset on a drag or flick.
if (systemGestureArgs.SystemGesture == SystemGesture.Flick)
{
// Don't want to play down or cached moves.
_needToSendMouseDown = false;
}
else
{
PlayBackCachedDownInputReport(systemGestureArgs.Timestamp);
}
}
else //we have a Tap
{
PlayBackCachedDownInputReport(systemGestureArgs.Timestamp);
}
}
}
else if (stylusEvent == Stylus.StylusInAirMoveEvent)
{
return RawMouseActions.AbsoluteMove;
}
else if (stylusEvent == Stylus.StylusDownEvent)
{
_fLeftButtonDownTrigger = true; // Default to left click until system gesture says otherwise.
_fBlockMouseMoveChanges = true;
// See if we can promote the mouse button down right now.
if (_seenDoubleTapGesture || _sawMouseButton1Down)
{
PlayBackCachedDownInputReport(stylusArgs.Timestamp);
}
}
else if (stylusEvent == Stylus.StylusMoveEvent)
{
if (!_fBlockMouseMoveChanges)
{
return RawMouseActions.AbsoluteMove;
}
}
else if (stylusEvent == Stylus.StylusUpEvent)
{
_fBlockMouseMoveChanges = false;
_seenDoubleTapGesture = false; // reset this on Stylus Up.
_sawMouseButton1Down = false; // reset to make sure we don't promote a mouse down on the next stylus down.
if (_promotedMouseState == MouseButtonState.Pressed)
{
_promotedMouseState = MouseButtonState.Released;
RawMouseActions actions = _fLeftButtonDownTrigger ?
RawMouseActions.Button1Release :
RawMouseActions.Button2Release;
// Make sure we only promote a mouse up if the mouse is in the down
// state (UpdateMousebuttonState returns true in that case)!
if (_stylusLogic.UpdateMouseButtonState(actions))
{
return actions;
}
// else - just return default of RawMouseActions.None since we don't want this
// duplicate mouse up to be processed.
}
}
// Default return
return RawMouseActions.None;
}
/////////////////////////////////////////////////////////////////////
internal Point LastMouseScreenPoint
{
get { return _lastMouseScreenLocation; }
set { _lastMouseScreenLocation = value; }
}
internal bool SeenDoubleTapGesture
{
get { return _seenDoubleTapGesture; }
set { _seenDoubleTapGesture = value; }
}
internal bool SeenHoldEnterGesture
{
get { return _seenHoldEnterGesture; }
}
internal bool GestureWasFired
{
get { return _fGestureWasFired;}
}
internal bool SentMouseDown
{
get { return _promotedMouseState == MouseButtonState.Pressed;}
}
internal bool DetectedDrag
{
get { return _fDetectedDrag; }
}
internal bool LeftIsActiveMouseButton
{
get { return _fLeftButtonDownTrigger; }
}
internal void SetSawMouseButton1Down(bool sawMouseButton1Down)
{
_sawMouseButton1Down = sawMouseButton1Down;
}
internal bool IgnoreStroke
{
get { return _ignoreStroke; }
set { _ignoreStroke = value; }
}
/////////////////////////////////////////////////////////////////////
TabletDevice _tabletDevice;
string _sName;
int _id;
bool _fInverted;
bool _fInRange;
StylusButtonCollection _stylusButtonCollection;
IInputElement _stylusOver;
IInputElement _stylusCapture;
CaptureMode _captureMode;
Point _rawPosition = new Point(0, 0);
Point _rawElementRelativePosition = new Point(0, 0);
StylusPointCollection _eventStylusPoints;
///
/// This data is not safe to expose as it holds refrence to PresentationSource
///
private SecurityCriticalDataClass _inputSource;
///
/// This data is not safe to expose as it holds refrence to PenContext
///
private SecurityCriticalDataClass _activePenContext;
bool _needToSendMouseDown;
private Point _lastMouseScreenLocation = new Point(0,0);
private Point _lastScreenLocation = new Point(0,0);
bool _fInAir = true;
bool _fLeftButtonDownTrigger = true; // default to left button down
bool _fGestureWasFired = true; // StylusDown resets this.
bool _fBlockMouseMoveChanges; // StylusDown sets to true, SystemGesture & StylusUp sets to false.
bool _fDetectedDrag; // StylusDown resets this. Used for generating DoubleTap gestures.
// Used to track the promoted mouse state.
MouseButtonState _promotedMouseState;
// real time pen input info that is tracked per stylus device
StylusPlugInCollection _nonVerifiedTarget;
StylusPlugInCollection _verifiedTarget;
object _rtiCaptureChanged = new object();
StylusPlugInCollection _stylusCapturePlugInCollection;
// Information used to distinguish double-clicks (actually, multi clicks) from
// multiple independent clicks.
private Point _lastTapXY = new Point(0,0);
private int _tapCount;
private int _lastTapTime;
private bool _lastTapBarrelDown;
private bool _seenDoubleTapGesture;
private bool _seenHoldEnterGesture;
private bool _sawMouseButton1Down; // Did we see the mouse down before the stylus down?
private bool _ignoreStroke; // Should we ignore promoting the stylus/mouse events for the current stroke?
///
/// Critical to prevent accidental spread to transparent code
///
[SecurityCritical]
private StylusLogic _stylusLogic;
}
}
// 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
- StaticExtensionConverter.cs
- Query.cs
- BypassElementCollection.cs
- Control.cs
- X509SecurityTokenAuthenticator.cs
- CheckBoxRenderer.cs
- Rectangle.cs
- KeyFrames.cs
- PassportPrincipal.cs
- TypeGeneratedEventArgs.cs
- InitializerFacet.cs
- TypeSystem.cs
- TextEndOfParagraph.cs
- MsmqAppDomainProtocolHandler.cs
- TextRangeEditTables.cs
- WebPageTraceListener.cs
- LinkLabel.cs
- RegexRunner.cs
- XmlDesigner.cs
- WebSysDisplayNameAttribute.cs
- WindowsGraphicsCacheManager.cs
- EnumerableRowCollectionExtensions.cs
- GeneralTransform3DGroup.cs
- ChildTable.cs
- ListView.cs
- MediaElementAutomationPeer.cs
- WhereQueryOperator.cs
- FunctionParameter.cs
- SHA256Cng.cs
- TraceRecords.cs
- WSHttpBindingBase.cs
- HtmlEncodedRawTextWriter.cs
- NativeWindow.cs
- DataSourceCache.cs
- SrgsDocumentParser.cs
- LocatorPartList.cs
- SecurityRequiresReviewAttribute.cs
- WebHttpSecurityElement.cs
- InitializerFacet.cs
- DateRangeEvent.cs
- LexicalChunk.cs
- XmlParserContext.cs
- ReceiveCompletedEventArgs.cs
- HttpHostedTransportConfiguration.cs
- HttpProxyCredentialType.cs
- CallSite.cs
- CapabilitiesRule.cs
- XmlCollation.cs
- GradientSpreadMethodValidation.cs
- BaseCAMarshaler.cs
- StreamProxy.cs
- PageRequestManager.cs
- ComplexTypeEmitter.cs
- WmlSelectionListAdapter.cs
- ManagementScope.cs
- ProcessingInstructionAction.cs
- Interlocked.cs
- ErrorWebPart.cs
- ToolboxItemCollection.cs
- DefaultValueTypeConverter.cs
- SamlAttributeStatement.cs
- ReaderWriterLock.cs
- ParameterRetriever.cs
- SoapTypeAttribute.cs
- BufferBuilder.cs
- DateTimeOffsetConverter.cs
- Encoding.cs
- ClientTarget.cs
- ContextMenuStripGroup.cs
- ConvertersCollection.cs
- WindowsFormsSynchronizationContext.cs
- SpellerError.cs
- OleDbConnectionPoolGroupProviderInfo.cs
- HeaderedContentControl.cs
- XmlArrayAttribute.cs
- AssemblyBuilder.cs
- SafeProcessHandle.cs
- WindowsListViewItemCheckBox.cs
- ToolStripStatusLabel.cs
- GuidelineCollection.cs
- SpotLight.cs
- SecurityPermission.cs
- ToolStripContainer.cs
- BaseParaClient.cs
- FileDialogCustomPlace.cs
- DataServiceQueryProvider.cs
- XamlTemplateSerializer.cs
- CompilerCollection.cs
- WebContentFormatHelper.cs
- CompletedAsyncResult.cs
- ToolStripItemBehavior.cs
- Queue.cs
- ConfigXmlAttribute.cs
- List.cs
- ButtonChrome.cs
- ZipIOExtraFieldZip64Element.cs
- SslStream.cs
- Hyperlink.cs
- DescendentsWalker.cs
- ConfigXmlCDataSection.cs