Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / Windows / Input / Stylus / StylusDevice.cs / 2 / 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.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- AlphabeticalEnumConverter.cs
- DesignerForm.cs
- MemberPathMap.cs
- SectionXmlInfo.cs
- AsyncCompletedEventArgs.cs
- RichTextBoxAutomationPeer.cs
- PolicyManager.cs
- TreeIterators.cs
- SqlUdtInfo.cs
- EndOfStreamException.cs
- UpdateException.cs
- TimeSpanFormat.cs
- CipherData.cs
- TabPanel.cs
- DispatcherExceptionFilterEventArgs.cs
- AdapterUtil.cs
- regiisutil.cs
- ToolStripMenuItemDesigner.cs
- EastAsianLunisolarCalendar.cs
- MdiWindowListItemConverter.cs
- SqlConnectionPoolProviderInfo.cs
- XamlStream.cs
- Property.cs
- HtmlEmptyTagControlBuilder.cs
- UserPreferenceChangingEventArgs.cs
- XPathAncestorIterator.cs
- PrintPreviewControl.cs
- RecognizedPhrase.cs
- BooleanSwitch.cs
- BufferCache.cs
- SafeRsaProviderHandle.cs
- ImageBrush.cs
- RegistryKey.cs
- _LazyAsyncResult.cs
- BindingCollection.cs
- ArraySegment.cs
- BlurEffect.cs
- RowTypePropertyElement.cs
- RuleCache.cs
- SamlAuthorityBinding.cs
- RectangleGeometry.cs
- QueryOperationResponseOfT.cs
- FlowDocumentReader.cs
- CodeAttributeDeclaration.cs
- BufferedOutputStream.cs
- AliasExpr.cs
- CompositionTarget.cs
- SmtpTransport.cs
- AddInPipelineAttributes.cs
- ConstraintConverter.cs
- FontDifferentiator.cs
- control.ime.cs
- ActivityWithResultValueSerializer.cs
- SoapConverter.cs
- DbDataAdapter.cs
- ItemsChangedEventArgs.cs
- UtilityExtension.cs
- ConstructorBuilder.cs
- CultureInfoConverter.cs
- EntityProviderServices.cs
- PrivateFontCollection.cs
- X509Utils.cs
- XmlUrlResolver.cs
- HandlerWithFactory.cs
- RangeValuePattern.cs
- validation.cs
- SecurityTokenAuthenticator.cs
- XmlRootAttribute.cs
- FixedStringLookup.cs
- RegularExpressionValidator.cs
- TypeConverterHelper.cs
- DisposableCollectionWrapper.cs
- SplashScreenNativeMethods.cs
- Span.cs
- TransactionException.cs
- CompositeClientFormatter.cs
- ActiveDocumentEvent.cs
- TransformerTypeCollection.cs
- CodeMethodMap.cs
- CodeMemberMethod.cs
- RecordManager.cs
- WindowsToolbarAsMenu.cs
- JumpTask.cs
- ObjectDataSourceFilteringEventArgs.cs
- TextDecorations.cs
- PasswordPropertyTextAttribute.cs
- GraphicsPath.cs
- UnsettableComboBox.cs
- TextChange.cs
- Pen.cs
- XmlSiteMapProvider.cs
- DictionaryItemsCollection.cs
- SecurityAlgorithmSuiteConverter.cs
- RelationalExpressions.cs
- EdmItemCollection.cs
- RegionIterator.cs
- MasterPage.cs
- ContextProperty.cs
- HyperLink.cs
- AttachedAnnotation.cs