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 / PenContexts.cs / 1 / PenContexts.cs
using System; using System.Collections; using System.Collections.Generic; using System.Windows.Threading; using System.Windows; using System.Windows.Input; using System.Windows.Media; using System.Security ; using MS.Internal ; using MS.Win32; using MS.Utility; using System.Runtime.InteropServices; using System.Security.Permissions; using Microsoft.Internal; using System.Windows.Input.StylusPlugIns; using System.Windows.Interop; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using MS.Internal.PresentationCore; // SecurityHelper namespace System.Windows.Input { ///////////////////////////////////////////////////////////////////////// internal sealed class PenContexts { ///////////////////////////////////////////////////////////////////////// ////// Critical - InputManager ctor is critical, ergo this is critical data. /// Called by Stylus.RegisterHwndForInput. /// TreatAsSafe boundary is Stylus.RegisterHwndForInput called when a window is created. /// [SecurityCritical] internal PenContexts(StylusLogic stylusLogic, PresentationSource inputSource) { HwndSource hwndSource = inputSource as HwndSource; if(hwndSource == null || IntPtr.Zero == (hwndSource).CriticalHandle) { throw new InvalidOperationException(SR.Get(SRID.Stylus_PenContextFailure)); } _stylusLogic = stylusLogic; _inputSource = new SecurityCriticalData(hwndSource); } ///////////////////////////////////////////////////////////////////////// /// /// Critical - Calls SecurityCritical code (TabletDevices.CreateContexts and PenContext.Enable) and accesses /// SecurityCritical data (_inputSource.Value and _contexts). /// Called by Stylus.EnableCore, Stylus.RegisterHwndForInput, Stylus.OnScreenMeasurementsChanged. /// TreatAsSafe boundry is Stylus.EnableCore, Stylus.RegisterHwndForInput /// and HwndWrapperHook class (via HwndSource.InputFilterMessage when /// a WM_DISPLAYCHANGE is processed by HwndStylusInputProvider). /// [SecurityCritical] internal void Enable() { if (_contexts == null) { // create contexts _contexts = _stylusLogic.TabletDevices.CreateContexts(_inputSource.Value.CriticalHandle, this); foreach(PenContext context in _contexts) { context.Enable(); } } } ////// Critical - Accesses SecurityCritical data (_contexts). /// Called by Stylus.UnregisterHwndForInput and Dispose. /// TreatAsSafe boundry is Stylus.UnregisterHwndForInput /// and HwndStylusInputProvider.Dispose(bool). /// [SecurityCritical] internal void Disable(bool shutdownWorkerThread) { if (_contexts != null) { foreach(PenContext context in _contexts) { context.Disable(shutdownWorkerThread); } _contexts = null; // release refs on PenContext objects } } internal bool IsWindowDisabled { get { return _isWindowDisabled; } set { _isWindowDisabled = value; } } internal Point DestroyedLocation { get { return _destroyedLocation; } set { _destroyedLocation = value; } } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code ProcessInput. /// Called by PenContext.FirePenDown. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnPenDown(PenContext penContext, int tabletDeviceId, int stylusPointerId, int[] data, int timestamp) { ProcessInput(RawStylusActions.Down, penContext, tabletDeviceId, stylusPointerId, data, timestamp); } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code ProcessInput. /// Called by PenContext.FirePenUp. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnPenUp(PenContext penContext, int tabletDeviceId, int stylusPointerId, int[] data, int timestamp) { ProcessInput(RawStylusActions.Up, penContext, tabletDeviceId, stylusPointerId, data, timestamp); } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code ProcessInput. /// Called by PenContext.FirePackets. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnPackets(PenContext penContext, int tabletDeviceId, int stylusPointerId, int[] data, int timestamp) { ProcessInput(RawStylusActions.Move, penContext, tabletDeviceId, stylusPointerId, data, timestamp); } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code ProcessInput. /// Called by PenContext.FirePackets. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnInAirPackets(PenContext penContext, int tabletDeviceId, int stylusPointerId, int[] data, int timestamp) { ProcessInput(RawStylusActions.InAirMove, penContext, tabletDeviceId, stylusPointerId, data, timestamp); } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code ProcessInput. /// Called by PenContext.FirePenInRange. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnPenInRange(PenContext penContext, int tabletDeviceId, int stylusPointerId, int[] data, int timestamp) { ProcessInput(RawStylusActions.InRange, penContext, tabletDeviceId, stylusPointerId, data, timestamp); } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code ProcessInput. /// Called by PenContext.FirePenOutOfRange. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnPenOutOfRange(PenContext penContext, int tabletDeviceId, int stylusPointerId, int timestamp) { ProcessInput(RawStylusActions.OutOfRange, penContext, tabletDeviceId, stylusPointerId, new int[]{}, timestamp); } ///////////////////////////////////////////////////////////////////// ////// Critical: Uses critical data _inputSource and calls SecurityCritical code /// StylusLogic.ProcessSystemEvent. /// Called by PenContext.FireSystemGesture. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnSystemEvent(PenContext penContext, int tabletDeviceId, int stylusPointerId, int timestamp, SystemGesture id, int gestureX, int gestureY, int buttonState) { _stylusLogic.ProcessSystemEvent(penContext, tabletDeviceId, stylusPointerId, timestamp, id, gestureX, gestureY, buttonState, _inputSource.Value); } ///////////////////////////////////////////////////////////////////// ////// Critical: Uses critical data _inputSource and calls SecurityCritical /// code StylusLogic.ProcessInput. /// Called by OnPenDown, OnPenUp, OnPackets, OnInAirPackets, OnPenInRange and OnPenOutOfRange. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] void ProcessInput( RawStylusActions actions, PenContext penContext, int tabletDeviceId, int stylusPointerId, int[] data, int timestamp) { // (all events but SystemEvent go thru here) _stylusLogic.ProcessInput( actions, penContext, tabletDeviceId, stylusPointerId, data, timestamp, _inputSource.Value); } ///////////////////////////////////////////////////////////////////////// ////// Critical since it accesses SecurityCritical data _contexts and /// returns SecurityCritical data PenContext. /// [SecurityCritical] internal PenContext GetTabletDeviceIDPenContext(int tabletDeviceId) { if (_contexts != null) { for (int i = 0; i < _contexts.Length; i++) { PenContext context = _contexts[i]; if (context.TabletDeviceId == tabletDeviceId) return context; } } return null; } ///////////////////////////////////////////////////////////////////////// ////// Critical since it accesses SecurityCritical data _contexts. /// [SecurityCritical] internal bool ConsiderInRange(int timestamp) { if (_contexts != null) { for (int i = 0; i < _contexts.Length; i++) { PenContext context = _contexts[i]; // We consider it InRange if we have a queued up context event or // the timestamp - LastInRangeTime <= 500 (seen one in the last 500ms) // Here's some info on how this works... // int.MaxValue - int.MinValue = -1 (subtracting any negative # from MaxValue keeps this negative) // int.MinValue - int.MaxValue = 1 (subtracting any positive # from MinValue keeps this positive) // So subtracting wrapping values will return proper sign depending on which was earlier. // We do have the assumption that these values will be relative close in time. If the // time wraps we'll say yet but the only harm is that we may defer a mouse move event temporarily // which won't cause any harm. if (context.QueuedInRangeCount > 0 || (Math.Abs(unchecked(timestamp - context.LastInRangeTime)) <= 500)) return true; } } return false; } ///////////////////////////////////////////////////////////////////// ////// This method adds the specified pen context index in response /// to the WM_TABLET_ADDED notification /// ////// Critical - Calls SecurityCritical code (Disable and TabletDevice.CreateContext) /// and accesses SecurityCritical data (_contexts). /// Called by Stylus.OnTabletAdded. /// TreatAsSafe boundary is HwndWrapperHook class (via HwndSource.InputFilterMessage). /// [SecurityCritical] internal void AddContext(uint index) { // We only tear down the old context when PenContexts are enabled without being // dispose and we have a valid index. Otherwise, no-op here. if (_contexts != null && index <= _contexts.Length && _inputSource.Value.CriticalHandle != IntPtr.Zero) { PenContext[] ctxs = new PenContext[_contexts.Length + 1]; uint preCopyCount = index; uint postCopyCount = (uint)_contexts.Length - index; Array.Copy(_contexts, 0, ctxs, 0, preCopyCount); PenContext newContext = _stylusLogic.TabletDevices[(int)index].CreateContext(_inputSource.Value.CriticalHandle, this); ctxs[index] = newContext; Array.Copy(_contexts, index, ctxs, index+1, postCopyCount); _contexts = ctxs; newContext.Enable(); } } ///////////////////////////////////////////////////////////////////// ////// This method removes the specified pen context index in response /// to the WM_TABLET_REMOVED notification /// ////// Critical - Calls SecurityCritical code (Disable and PenContext constructor) and /// accesses SecurityCritical data (_contexts). /// Called by Stylus.OnTabletRemoved. /// TreatAsSafe boundary is HwndWrapperHook class (via HwndSource.InputFilterMessage). /// [SecurityCritical] internal void RemoveContext(uint index) { // We only tear down the old context when PenContexts are enabled without being // dispose and we have a valid index. Otherwise, no-op here. if (_contexts != null && index < _contexts.Length) { PenContext removeCtx = _contexts[index]; PenContext[] ctxs = new PenContext[_contexts.Length - 1]; uint preCopyCount = index; uint postCopyCount = (uint)_contexts.Length - index - 1; Array.Copy(_contexts, 0, ctxs, 0, preCopyCount); Array.Copy(_contexts, index+1, ctxs, index, postCopyCount); removeCtx.Disable(false); // shut down this context. _contexts = ctxs; } } ///////////////////////////////////////////////////////////////////// internal object SyncRoot { get { return __rtiLock; } } internal void AddStylusPlugInCollection(StylusPlugInCollection pic) { // must be called from inside of lock(__rtiLock) // insert in ZOrder _plugInCollectionList.Insert(FindZOrderIndex(pic), pic); } internal void RemoveStylusPlugInCollection(StylusPlugInCollection pic) { // must be called from inside of lock(__rtiLock) _plugInCollectionList.Remove(pic); } internal int FindZOrderIndex(StylusPlugInCollection spicAdding) { //should be called inside of lock(__rtiLock) DependencyObject spicAddingVisual = spicAdding.Element as Visual; int i; for (i=0; i < _plugInCollectionList.Count; i++) { // first see if parent of node, if it is then we can just scan till we find the // first non parent and we're done DependencyObject curV = _plugInCollectionList[i].Element as Visual; if (VisualTreeHelper.IsAncestorOf(spicAddingVisual, curV)) { i++; while (i < _plugInCollectionList.Count) { curV = _plugInCollectionList[i].Element as Visual; if (!VisualTreeHelper.IsAncestorOf(spicAddingVisual, curV)) break; // done i++; } return i; } else { // Look to see if spicAddingVisual is higher in ZOrder than i, if so then we're done DependencyObject commonParent = VisualTreeHelper.FindCommonAncestor(spicAddingVisual, curV); // If no common parent found then we must have multiple plugincollection elements // that have been removed from the visual tree and we haven't been notified yet of // that change. In this case just ignore this plugincollection element and go to // the next. if (commonParent == null) continue; // If curV is the commonParent we find then we're done. This new plugin should be // above this one. if (curV == commonParent) return i; // now find first child for each under that common visual that these fall under (not they must be different or common parent is sort of busted. while (VisualTreeHelper.GetParentInternal(spicAddingVisual) != commonParent) spicAddingVisual = VisualTreeHelper.GetParentInternal(spicAddingVisual); while (VisualTreeHelper.GetParentInternal(curV) != commonParent) curV = VisualTreeHelper.GetParentInternal(curV); // now see which is higher in zorder int count = VisualTreeHelper.GetChildrenCount(commonParent); for (int j = 0; j < count; j++) { DependencyObject child = VisualTreeHelper.GetChild(commonParent, j); if (child == spicAddingVisual) return i; else if (child == curV) break; // look at next index in _piList. } } } return i; // this wasn't higher so return last index. } ////// Critical - Calls into security critical code TargetPlugInCollection. /// Called by StylusLogic.CallPluginsForMouse. /// TreatAsSafe boundary is mainly PenThread.ThreadProc and HwndWrapperHook class (via HwndSource.InputFilterMessage). /// It can also be called via anyone with priviledge to call InputManager.ProcessInput(). /// [SecurityCritical] internal StylusPlugInCollection InvokeStylusPluginCollectionForMouse(RawStylusInputReport inputReport, IInputElement directlyOver, StylusPlugInCollection currentPlugInCollection) { StylusPlugInCollection newPlugInCollection = null; // lock to make sure only one event is processed at a time and no changes to state can // be made until we finish routing this event. lock(__rtiLock) { //Debug.Assert(inputReport.Actions == RawStylusActions.Down || // inputReport.Actions == RawStylusActions.Up || // inputReport.Actions == RawStylusActions.Move); // Find new target plugin collection if (directlyOver != null) { UIElement uiElement = InputElement.GetContainingUIElement(directlyOver as DependencyObject) as UIElement; if (uiElement != null) { newPlugInCollection = FindPlugInCollection(uiElement); } } // Fire Leave event to old pluginCollection if we need to. if (currentPlugInCollection != null && currentPlugInCollection != newPlugInCollection) { // NOTE: input report points for mouse are in avalon measured units and not device! RawStylusInput tempRawStylusInput = new RawStylusInput(inputReport, currentPlugInCollection.ViewToElement, currentPlugInCollection); currentPlugInCollection.FireEnterLeave(false, tempRawStylusInput, true); } if (newPlugInCollection != null) { // NOTE: input report points for mouse are in avalon measured units and not device! RawStylusInput rawStylusInput = new RawStylusInput(inputReport, newPlugInCollection.ViewToElement, newPlugInCollection); inputReport.RawStylusInput = rawStylusInput; if (newPlugInCollection != currentPlugInCollection) { newPlugInCollection.FireEnterLeave(true, rawStylusInput, true); } // We are on the pen thread, just call directly. newPlugInCollection.FireRawStylusInput(rawStylusInput); // Fire custom data events (always confirmed for mouse) foreach (RawStylusInputCustomData customData in rawStylusInput.CustomDataList) { customData.Owner.FireCustomData(customData.Data, inputReport.Actions, true); } } } return newPlugInCollection; } ////// Critical - Calls into security critical code TargetPlugInCollection. /// Called by StylusLogic.InvokeStylusPluginCollection. /// TreatAsSafe boundary is mainly PenThread.ThreadProc and HwndWrapperHook class (via HwndSource.InputFilterMessage). /// It can also be called via anyone with priviledge to call InputManager.ProcessInput(). /// [SecurityCritical] internal void InvokeStylusPluginCollection(RawStylusInputReport inputReport) { // Find PenContexts object for this inputReport. StylusPlugInCollection pic = null; // lock to make sure only one event is processed at a time and no changes to state can // be made until we finish routing this event. lock(__rtiLock) { switch (inputReport.Actions) { case RawStylusActions.Down: case RawStylusActions.Move: case RawStylusActions.Up: // Figure out current target plugincollection. pic = TargetPlugInCollection(inputReport); break; default: return; // Nothing to do unless one of the above events } StylusPlugInCollection currentPic = inputReport.StylusDevice.CurrentNonVerifiedTarget; // Fire Leave event if we need to. if (currentPic != null && currentPic != pic) { // Create new RawStylusInput to send GeneralTransformGroup transformTabletToView = new GeneralTransformGroup(); transformTabletToView.Children.Add(new MatrixTransform(_stylusLogic.GetTabletToViewTransform(inputReport.StylusDevice.TabletDevice))); // this gives matrix in measured units (not device) transformTabletToView.Children.Add(currentPic.ViewToElement); // Make it relative to the element. transformTabletToView.Freeze(); // Must be frozen for multi-threaded access. RawStylusInput tempRawStylusInput = new RawStylusInput(inputReport, transformTabletToView, currentPic); currentPic.FireEnterLeave(false, tempRawStylusInput, false); inputReport.StylusDevice.CurrentNonVerifiedTarget = null; } if (pic != null) { // NOTE: PenContext info will not change (it gets rebuilt instead so keeping ref is fine) // The transformTabletToView matrix and plugincollection rects though can change based // off of layout events which is why we need to lock this. GeneralTransformGroup transformTabletToView = new GeneralTransformGroup(); transformTabletToView.Children.Add(new MatrixTransform(_stylusLogic.GetTabletToViewTransform(inputReport.StylusDevice.TabletDevice))); // this gives matrix in measured units (not device) transformTabletToView.Children.Add(pic.ViewToElement); // Make it relative to the element. transformTabletToView.Freeze(); // Must be frozen for multi-threaded access. RawStylusInput rawStylusInput = new RawStylusInput(inputReport, transformTabletToView, pic); inputReport.RawStylusInput = rawStylusInput; if (pic != currentPic) { inputReport.StylusDevice.CurrentNonVerifiedTarget = pic; pic.FireEnterLeave(true, rawStylusInput, false); } // We are on the pen thread, just call directly. pic.FireRawStylusInput(rawStylusInput); } } // lock(__rtiLock) } ////// Critical - InputReport.InputSource has a LinkDemand so we need to be SecurityCritical. /// Called by InvokeStylusPluginCollection. /// TreatAsSafe boundary is mainly PenThread.ThreadProc and HwndWrapperHook class (via HwndSource.InputFilterMessage). /// It can also be called via anyone with priviledge to call InputManager.ProcessInput(). /// [SecurityCritical] internal StylusPlugInCollection TargetPlugInCollection(RawStylusInputReport inputReport) { // Caller must make call to this routine inside of lock(__rtiLock)! StylusPlugInCollection pic = null; // We should only be called when not on the application thread! System.Diagnostics.Debug.Assert(!inputReport.StylusDevice.CheckAccess()); // We're on the pen thread so can't touch visual tree. Use capturedPlugIn (if capture on) or cached rects. bool elementHasCapture = false; pic = inputReport.StylusDevice.GetCapturedPlugInCollection(ref elementHasCapture); int pointLength = inputReport.PenContext.StylusPointDescription.GetInputArrayLengthPerPoint(); // Make sure that the captured Plugin Collection is still in the list. CaptureChanges are // deferred so there is a window where the stylus device is not updated yet. This protects us // from using a bogus plugin collecton for an element that is in an invalid state. if (elementHasCapture && !_plugInCollectionList.Contains(pic)) { elementHasCapture = false; // force true hittesting to be done! } if (!elementHasCapture && inputReport.Data != null && inputReport.Data.Length >= pointLength) { int[] data = inputReport.Data; System.Diagnostics.Debug.Assert(data.Length % pointLength == 0); Point ptTablet = new Point(data[data.Length - pointLength], data[data.Length - pointLength + 1]); // Note: the StylusLogic data inside DeviceUnitsFromMeasurUnits is protected by __rtiLock. ptTablet = ptTablet * inputReport.StylusDevice.TabletDevice.TabletToScreen; ptTablet.X = (int)Math.Round(ptTablet.X); // Make sure we snap to whole window pixels. ptTablet.Y = (int)Math.Round(ptTablet.Y); ptTablet = _stylusLogic.MeasureUnitsFromDeviceUnits(ptTablet); // change to measured units now. pic = HittestPlugInCollection(ptTablet); // Use cached rectangles for UIElements. } return pic; } ///////////////////////////////////////////////////////////////////// // NOTE: this should only be called inside of app Dispatcher internal StylusPlugInCollection FindPlugInCollection(UIElement element) { // Since we are only called on app Dispatcher this cannot change out from under us. // System.Diagnostics.Debug.Assert(_stylusLogic.Dispatcher.CheckAccess()); foreach (StylusPlugInCollection plugInCollection in _plugInCollectionList) { // If same element or element is child of the plugincollection element than say we hit it. if (plugInCollection.Element == element || (plugInCollection.Element as Visual).IsAncestorOf(element as Visual)) { return plugInCollection; } } return null; } ///////////////////////////////////////////////////////////////////// // NOTE: this is called on pen thread (outside of apps Dispatcher) StylusPlugInCollection HittestPlugInCollection(Point pt) { // Caller must make call to this routine inside of lock(__rtiLock)! foreach (StylusPlugInCollection plugInCollection in _plugInCollectionList) { if (plugInCollection.IsHit(pt)) { return plugInCollection; } } return null; } ///////////////////////////////////////////////////////////////////// ////// Critical - PresentationSource is critical /// internal SecurityCriticalData_inputSource; /// /// Critical to prevent accidental spread to transparent code /// [SecurityCritical] StylusLogic _stylusLogic; object __rtiLock = new object(); List_plugInCollectionList = new List (); /// /// Critical to prevent accidental spread to transparent code /// [SecurityCritical] PenContext[] _contexts; bool _isWindowDisabled; Point _destroyedLocation = new Point(0,0); } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. using System; using System.Collections; using System.Collections.Generic; using System.Windows.Threading; using System.Windows; using System.Windows.Input; using System.Windows.Media; using System.Security ; using MS.Internal ; using MS.Win32; using MS.Utility; using System.Runtime.InteropServices; using System.Security.Permissions; using Microsoft.Internal; using System.Windows.Input.StylusPlugIns; using System.Windows.Interop; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using MS.Internal.PresentationCore; // SecurityHelper namespace System.Windows.Input { ///////////////////////////////////////////////////////////////////////// internal sealed class PenContexts { ///////////////////////////////////////////////////////////////////////// ////// Critical - InputManager ctor is critical, ergo this is critical data. /// Called by Stylus.RegisterHwndForInput. /// TreatAsSafe boundary is Stylus.RegisterHwndForInput called when a window is created. /// [SecurityCritical] internal PenContexts(StylusLogic stylusLogic, PresentationSource inputSource) { HwndSource hwndSource = inputSource as HwndSource; if(hwndSource == null || IntPtr.Zero == (hwndSource).CriticalHandle) { throw new InvalidOperationException(SR.Get(SRID.Stylus_PenContextFailure)); } _stylusLogic = stylusLogic; _inputSource = new SecurityCriticalData(hwndSource); } ///////////////////////////////////////////////////////////////////////// /// /// Critical - Calls SecurityCritical code (TabletDevices.CreateContexts and PenContext.Enable) and accesses /// SecurityCritical data (_inputSource.Value and _contexts). /// Called by Stylus.EnableCore, Stylus.RegisterHwndForInput, Stylus.OnScreenMeasurementsChanged. /// TreatAsSafe boundry is Stylus.EnableCore, Stylus.RegisterHwndForInput /// and HwndWrapperHook class (via HwndSource.InputFilterMessage when /// a WM_DISPLAYCHANGE is processed by HwndStylusInputProvider). /// [SecurityCritical] internal void Enable() { if (_contexts == null) { // create contexts _contexts = _stylusLogic.TabletDevices.CreateContexts(_inputSource.Value.CriticalHandle, this); foreach(PenContext context in _contexts) { context.Enable(); } } } ////// Critical - Accesses SecurityCritical data (_contexts). /// Called by Stylus.UnregisterHwndForInput and Dispose. /// TreatAsSafe boundry is Stylus.UnregisterHwndForInput /// and HwndStylusInputProvider.Dispose(bool). /// [SecurityCritical] internal void Disable(bool shutdownWorkerThread) { if (_contexts != null) { foreach(PenContext context in _contexts) { context.Disable(shutdownWorkerThread); } _contexts = null; // release refs on PenContext objects } } internal bool IsWindowDisabled { get { return _isWindowDisabled; } set { _isWindowDisabled = value; } } internal Point DestroyedLocation { get { return _destroyedLocation; } set { _destroyedLocation = value; } } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code ProcessInput. /// Called by PenContext.FirePenDown. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnPenDown(PenContext penContext, int tabletDeviceId, int stylusPointerId, int[] data, int timestamp) { ProcessInput(RawStylusActions.Down, penContext, tabletDeviceId, stylusPointerId, data, timestamp); } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code ProcessInput. /// Called by PenContext.FirePenUp. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnPenUp(PenContext penContext, int tabletDeviceId, int stylusPointerId, int[] data, int timestamp) { ProcessInput(RawStylusActions.Up, penContext, tabletDeviceId, stylusPointerId, data, timestamp); } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code ProcessInput. /// Called by PenContext.FirePackets. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnPackets(PenContext penContext, int tabletDeviceId, int stylusPointerId, int[] data, int timestamp) { ProcessInput(RawStylusActions.Move, penContext, tabletDeviceId, stylusPointerId, data, timestamp); } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code ProcessInput. /// Called by PenContext.FirePackets. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnInAirPackets(PenContext penContext, int tabletDeviceId, int stylusPointerId, int[] data, int timestamp) { ProcessInput(RawStylusActions.InAirMove, penContext, tabletDeviceId, stylusPointerId, data, timestamp); } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code ProcessInput. /// Called by PenContext.FirePenInRange. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnPenInRange(PenContext penContext, int tabletDeviceId, int stylusPointerId, int[] data, int timestamp) { ProcessInput(RawStylusActions.InRange, penContext, tabletDeviceId, stylusPointerId, data, timestamp); } ///////////////////////////////////////////////////////////////////// ////// Critical - Calls SecurityCritical code ProcessInput. /// Called by PenContext.FirePenOutOfRange. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnPenOutOfRange(PenContext penContext, int tabletDeviceId, int stylusPointerId, int timestamp) { ProcessInput(RawStylusActions.OutOfRange, penContext, tabletDeviceId, stylusPointerId, new int[]{}, timestamp); } ///////////////////////////////////////////////////////////////////// ////// Critical: Uses critical data _inputSource and calls SecurityCritical code /// StylusLogic.ProcessSystemEvent. /// Called by PenContext.FireSystemGesture. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] internal void OnSystemEvent(PenContext penContext, int tabletDeviceId, int stylusPointerId, int timestamp, SystemGesture id, int gestureX, int gestureY, int buttonState) { _stylusLogic.ProcessSystemEvent(penContext, tabletDeviceId, stylusPointerId, timestamp, id, gestureX, gestureY, buttonState, _inputSource.Value); } ///////////////////////////////////////////////////////////////////// ////// Critical: Uses critical data _inputSource and calls SecurityCritical /// code StylusLogic.ProcessInput. /// Called by OnPenDown, OnPenUp, OnPackets, OnInAirPackets, OnPenInRange and OnPenOutOfRange. /// TreatAsSafe boundary is PenThread.ThreadProc. /// [SecurityCritical] void ProcessInput( RawStylusActions actions, PenContext penContext, int tabletDeviceId, int stylusPointerId, int[] data, int timestamp) { // (all events but SystemEvent go thru here) _stylusLogic.ProcessInput( actions, penContext, tabletDeviceId, stylusPointerId, data, timestamp, _inputSource.Value); } ///////////////////////////////////////////////////////////////////////// ////// Critical since it accesses SecurityCritical data _contexts and /// returns SecurityCritical data PenContext. /// [SecurityCritical] internal PenContext GetTabletDeviceIDPenContext(int tabletDeviceId) { if (_contexts != null) { for (int i = 0; i < _contexts.Length; i++) { PenContext context = _contexts[i]; if (context.TabletDeviceId == tabletDeviceId) return context; } } return null; } ///////////////////////////////////////////////////////////////////////// ////// Critical since it accesses SecurityCritical data _contexts. /// [SecurityCritical] internal bool ConsiderInRange(int timestamp) { if (_contexts != null) { for (int i = 0; i < _contexts.Length; i++) { PenContext context = _contexts[i]; // We consider it InRange if we have a queued up context event or // the timestamp - LastInRangeTime <= 500 (seen one in the last 500ms) // Here's some info on how this works... // int.MaxValue - int.MinValue = -1 (subtracting any negative # from MaxValue keeps this negative) // int.MinValue - int.MaxValue = 1 (subtracting any positive # from MinValue keeps this positive) // So subtracting wrapping values will return proper sign depending on which was earlier. // We do have the assumption that these values will be relative close in time. If the // time wraps we'll say yet but the only harm is that we may defer a mouse move event temporarily // which won't cause any harm. if (context.QueuedInRangeCount > 0 || (Math.Abs(unchecked(timestamp - context.LastInRangeTime)) <= 500)) return true; } } return false; } ///////////////////////////////////////////////////////////////////// ////// This method adds the specified pen context index in response /// to the WM_TABLET_ADDED notification /// ////// Critical - Calls SecurityCritical code (Disable and TabletDevice.CreateContext) /// and accesses SecurityCritical data (_contexts). /// Called by Stylus.OnTabletAdded. /// TreatAsSafe boundary is HwndWrapperHook class (via HwndSource.InputFilterMessage). /// [SecurityCritical] internal void AddContext(uint index) { // We only tear down the old context when PenContexts are enabled without being // dispose and we have a valid index. Otherwise, no-op here. if (_contexts != null && index <= _contexts.Length && _inputSource.Value.CriticalHandle != IntPtr.Zero) { PenContext[] ctxs = new PenContext[_contexts.Length + 1]; uint preCopyCount = index; uint postCopyCount = (uint)_contexts.Length - index; Array.Copy(_contexts, 0, ctxs, 0, preCopyCount); PenContext newContext = _stylusLogic.TabletDevices[(int)index].CreateContext(_inputSource.Value.CriticalHandle, this); ctxs[index] = newContext; Array.Copy(_contexts, index, ctxs, index+1, postCopyCount); _contexts = ctxs; newContext.Enable(); } } ///////////////////////////////////////////////////////////////////// ////// This method removes the specified pen context index in response /// to the WM_TABLET_REMOVED notification /// ////// Critical - Calls SecurityCritical code (Disable and PenContext constructor) and /// accesses SecurityCritical data (_contexts). /// Called by Stylus.OnTabletRemoved. /// TreatAsSafe boundary is HwndWrapperHook class (via HwndSource.InputFilterMessage). /// [SecurityCritical] internal void RemoveContext(uint index) { // We only tear down the old context when PenContexts are enabled without being // dispose and we have a valid index. Otherwise, no-op here. if (_contexts != null && index < _contexts.Length) { PenContext removeCtx = _contexts[index]; PenContext[] ctxs = new PenContext[_contexts.Length - 1]; uint preCopyCount = index; uint postCopyCount = (uint)_contexts.Length - index - 1; Array.Copy(_contexts, 0, ctxs, 0, preCopyCount); Array.Copy(_contexts, index+1, ctxs, index, postCopyCount); removeCtx.Disable(false); // shut down this context. _contexts = ctxs; } } ///////////////////////////////////////////////////////////////////// internal object SyncRoot { get { return __rtiLock; } } internal void AddStylusPlugInCollection(StylusPlugInCollection pic) { // must be called from inside of lock(__rtiLock) // insert in ZOrder _plugInCollectionList.Insert(FindZOrderIndex(pic), pic); } internal void RemoveStylusPlugInCollection(StylusPlugInCollection pic) { // must be called from inside of lock(__rtiLock) _plugInCollectionList.Remove(pic); } internal int FindZOrderIndex(StylusPlugInCollection spicAdding) { //should be called inside of lock(__rtiLock) DependencyObject spicAddingVisual = spicAdding.Element as Visual; int i; for (i=0; i < _plugInCollectionList.Count; i++) { // first see if parent of node, if it is then we can just scan till we find the // first non parent and we're done DependencyObject curV = _plugInCollectionList[i].Element as Visual; if (VisualTreeHelper.IsAncestorOf(spicAddingVisual, curV)) { i++; while (i < _plugInCollectionList.Count) { curV = _plugInCollectionList[i].Element as Visual; if (!VisualTreeHelper.IsAncestorOf(spicAddingVisual, curV)) break; // done i++; } return i; } else { // Look to see if spicAddingVisual is higher in ZOrder than i, if so then we're done DependencyObject commonParent = VisualTreeHelper.FindCommonAncestor(spicAddingVisual, curV); // If no common parent found then we must have multiple plugincollection elements // that have been removed from the visual tree and we haven't been notified yet of // that change. In this case just ignore this plugincollection element and go to // the next. if (commonParent == null) continue; // If curV is the commonParent we find then we're done. This new plugin should be // above this one. if (curV == commonParent) return i; // now find first child for each under that common visual that these fall under (not they must be different or common parent is sort of busted. while (VisualTreeHelper.GetParentInternal(spicAddingVisual) != commonParent) spicAddingVisual = VisualTreeHelper.GetParentInternal(spicAddingVisual); while (VisualTreeHelper.GetParentInternal(curV) != commonParent) curV = VisualTreeHelper.GetParentInternal(curV); // now see which is higher in zorder int count = VisualTreeHelper.GetChildrenCount(commonParent); for (int j = 0; j < count; j++) { DependencyObject child = VisualTreeHelper.GetChild(commonParent, j); if (child == spicAddingVisual) return i; else if (child == curV) break; // look at next index in _piList. } } } return i; // this wasn't higher so return last index. } ////// Critical - Calls into security critical code TargetPlugInCollection. /// Called by StylusLogic.CallPluginsForMouse. /// TreatAsSafe boundary is mainly PenThread.ThreadProc and HwndWrapperHook class (via HwndSource.InputFilterMessage). /// It can also be called via anyone with priviledge to call InputManager.ProcessInput(). /// [SecurityCritical] internal StylusPlugInCollection InvokeStylusPluginCollectionForMouse(RawStylusInputReport inputReport, IInputElement directlyOver, StylusPlugInCollection currentPlugInCollection) { StylusPlugInCollection newPlugInCollection = null; // lock to make sure only one event is processed at a time and no changes to state can // be made until we finish routing this event. lock(__rtiLock) { //Debug.Assert(inputReport.Actions == RawStylusActions.Down || // inputReport.Actions == RawStylusActions.Up || // inputReport.Actions == RawStylusActions.Move); // Find new target plugin collection if (directlyOver != null) { UIElement uiElement = InputElement.GetContainingUIElement(directlyOver as DependencyObject) as UIElement; if (uiElement != null) { newPlugInCollection = FindPlugInCollection(uiElement); } } // Fire Leave event to old pluginCollection if we need to. if (currentPlugInCollection != null && currentPlugInCollection != newPlugInCollection) { // NOTE: input report points for mouse are in avalon measured units and not device! RawStylusInput tempRawStylusInput = new RawStylusInput(inputReport, currentPlugInCollection.ViewToElement, currentPlugInCollection); currentPlugInCollection.FireEnterLeave(false, tempRawStylusInput, true); } if (newPlugInCollection != null) { // NOTE: input report points for mouse are in avalon measured units and not device! RawStylusInput rawStylusInput = new RawStylusInput(inputReport, newPlugInCollection.ViewToElement, newPlugInCollection); inputReport.RawStylusInput = rawStylusInput; if (newPlugInCollection != currentPlugInCollection) { newPlugInCollection.FireEnterLeave(true, rawStylusInput, true); } // We are on the pen thread, just call directly. newPlugInCollection.FireRawStylusInput(rawStylusInput); // Fire custom data events (always confirmed for mouse) foreach (RawStylusInputCustomData customData in rawStylusInput.CustomDataList) { customData.Owner.FireCustomData(customData.Data, inputReport.Actions, true); } } } return newPlugInCollection; } ////// Critical - Calls into security critical code TargetPlugInCollection. /// Called by StylusLogic.InvokeStylusPluginCollection. /// TreatAsSafe boundary is mainly PenThread.ThreadProc and HwndWrapperHook class (via HwndSource.InputFilterMessage). /// It can also be called via anyone with priviledge to call InputManager.ProcessInput(). /// [SecurityCritical] internal void InvokeStylusPluginCollection(RawStylusInputReport inputReport) { // Find PenContexts object for this inputReport. StylusPlugInCollection pic = null; // lock to make sure only one event is processed at a time and no changes to state can // be made until we finish routing this event. lock(__rtiLock) { switch (inputReport.Actions) { case RawStylusActions.Down: case RawStylusActions.Move: case RawStylusActions.Up: // Figure out current target plugincollection. pic = TargetPlugInCollection(inputReport); break; default: return; // Nothing to do unless one of the above events } StylusPlugInCollection currentPic = inputReport.StylusDevice.CurrentNonVerifiedTarget; // Fire Leave event if we need to. if (currentPic != null && currentPic != pic) { // Create new RawStylusInput to send GeneralTransformGroup transformTabletToView = new GeneralTransformGroup(); transformTabletToView.Children.Add(new MatrixTransform(_stylusLogic.GetTabletToViewTransform(inputReport.StylusDevice.TabletDevice))); // this gives matrix in measured units (not device) transformTabletToView.Children.Add(currentPic.ViewToElement); // Make it relative to the element. transformTabletToView.Freeze(); // Must be frozen for multi-threaded access. RawStylusInput tempRawStylusInput = new RawStylusInput(inputReport, transformTabletToView, currentPic); currentPic.FireEnterLeave(false, tempRawStylusInput, false); inputReport.StylusDevice.CurrentNonVerifiedTarget = null; } if (pic != null) { // NOTE: PenContext info will not change (it gets rebuilt instead so keeping ref is fine) // The transformTabletToView matrix and plugincollection rects though can change based // off of layout events which is why we need to lock this. GeneralTransformGroup transformTabletToView = new GeneralTransformGroup(); transformTabletToView.Children.Add(new MatrixTransform(_stylusLogic.GetTabletToViewTransform(inputReport.StylusDevice.TabletDevice))); // this gives matrix in measured units (not device) transformTabletToView.Children.Add(pic.ViewToElement); // Make it relative to the element. transformTabletToView.Freeze(); // Must be frozen for multi-threaded access. RawStylusInput rawStylusInput = new RawStylusInput(inputReport, transformTabletToView, pic); inputReport.RawStylusInput = rawStylusInput; if (pic != currentPic) { inputReport.StylusDevice.CurrentNonVerifiedTarget = pic; pic.FireEnterLeave(true, rawStylusInput, false); } // We are on the pen thread, just call directly. pic.FireRawStylusInput(rawStylusInput); } } // lock(__rtiLock) } ////// Critical - InputReport.InputSource has a LinkDemand so we need to be SecurityCritical. /// Called by InvokeStylusPluginCollection. /// TreatAsSafe boundary is mainly PenThread.ThreadProc and HwndWrapperHook class (via HwndSource.InputFilterMessage). /// It can also be called via anyone with priviledge to call InputManager.ProcessInput(). /// [SecurityCritical] internal StylusPlugInCollection TargetPlugInCollection(RawStylusInputReport inputReport) { // Caller must make call to this routine inside of lock(__rtiLock)! StylusPlugInCollection pic = null; // We should only be called when not on the application thread! System.Diagnostics.Debug.Assert(!inputReport.StylusDevice.CheckAccess()); // We're on the pen thread so can't touch visual tree. Use capturedPlugIn (if capture on) or cached rects. bool elementHasCapture = false; pic = inputReport.StylusDevice.GetCapturedPlugInCollection(ref elementHasCapture); int pointLength = inputReport.PenContext.StylusPointDescription.GetInputArrayLengthPerPoint(); // Make sure that the captured Plugin Collection is still in the list. CaptureChanges are // deferred so there is a window where the stylus device is not updated yet. This protects us // from using a bogus plugin collecton for an element that is in an invalid state. if (elementHasCapture && !_plugInCollectionList.Contains(pic)) { elementHasCapture = false; // force true hittesting to be done! } if (!elementHasCapture && inputReport.Data != null && inputReport.Data.Length >= pointLength) { int[] data = inputReport.Data; System.Diagnostics.Debug.Assert(data.Length % pointLength == 0); Point ptTablet = new Point(data[data.Length - pointLength], data[data.Length - pointLength + 1]); // Note: the StylusLogic data inside DeviceUnitsFromMeasurUnits is protected by __rtiLock. ptTablet = ptTablet * inputReport.StylusDevice.TabletDevice.TabletToScreen; ptTablet.X = (int)Math.Round(ptTablet.X); // Make sure we snap to whole window pixels. ptTablet.Y = (int)Math.Round(ptTablet.Y); ptTablet = _stylusLogic.MeasureUnitsFromDeviceUnits(ptTablet); // change to measured units now. pic = HittestPlugInCollection(ptTablet); // Use cached rectangles for UIElements. } return pic; } ///////////////////////////////////////////////////////////////////// // NOTE: this should only be called inside of app Dispatcher internal StylusPlugInCollection FindPlugInCollection(UIElement element) { // Since we are only called on app Dispatcher this cannot change out from under us. // System.Diagnostics.Debug.Assert(_stylusLogic.Dispatcher.CheckAccess()); foreach (StylusPlugInCollection plugInCollection in _plugInCollectionList) { // If same element or element is child of the plugincollection element than say we hit it. if (plugInCollection.Element == element || (plugInCollection.Element as Visual).IsAncestorOf(element as Visual)) { return plugInCollection; } } return null; } ///////////////////////////////////////////////////////////////////// // NOTE: this is called on pen thread (outside of apps Dispatcher) StylusPlugInCollection HittestPlugInCollection(Point pt) { // Caller must make call to this routine inside of lock(__rtiLock)! foreach (StylusPlugInCollection plugInCollection in _plugInCollectionList) { if (plugInCollection.IsHit(pt)) { return plugInCollection; } } return null; } ///////////////////////////////////////////////////////////////////// ////// Critical - PresentationSource is critical /// internal SecurityCriticalData_inputSource; /// /// Critical to prevent accidental spread to transparent code /// [SecurityCritical] StylusLogic _stylusLogic; object __rtiLock = new object(); List_plugInCollectionList = new List (); /// /// Critical to prevent accidental spread to transparent code /// [SecurityCritical] PenContext[] _contexts; bool _isWindowDisabled; Point _destroyedLocation = new Point(0,0); } } // 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
- ListBindableAttribute.cs
- TargetParameterCountException.cs
- InstalledFontCollection.cs
- XslUrlEditor.cs
- ConnectorEditor.cs
- TakeOrSkipWhileQueryOperator.cs
- GB18030Encoding.cs
- SharedPerformanceCounter.cs
- DirectoryObjectSecurity.cs
- XmlILAnnotation.cs
- Helpers.cs
- SwitchExpression.cs
- SolidColorBrush.cs
- TextCompositionEventArgs.cs
- QilVisitor.cs
- GridViewCancelEditEventArgs.cs
- GlyphShapingProperties.cs
- SecUtil.cs
- NonClientArea.cs
- DriveInfo.cs
- DateTimeAutomationPeer.cs
- EntityProviderServices.cs
- EventProviderTraceListener.cs
- EncodingNLS.cs
- RelationshipEndMember.cs
- ExpressionEditorAttribute.cs
- TrackingProfileSerializer.cs
- WorkflowViewStateService.cs
- TreeViewEvent.cs
- NamespaceQuery.cs
- SByteStorage.cs
- ControlAdapter.cs
- EntityContainerEntitySet.cs
- SmiMetaDataProperty.cs
- Suspend.cs
- RegexCode.cs
- AsyncPostBackErrorEventArgs.cs
- LinqDataSourceDisposeEventArgs.cs
- CodeCompiler.cs
- ChannelPool.cs
- ActivityValidator.cs
- QilInvokeLateBound.cs
- mansign.cs
- ResourceDefaultValueAttribute.cs
- ForeignKeyFactory.cs
- CultureInfoConverter.cs
- IdentityNotMappedException.cs
- SqlEnums.cs
- PartialList.cs
- TypeValidationEventArgs.cs
- BooleanStorage.cs
- EntityKeyElement.cs
- XmlElementAttribute.cs
- SecurityUtils.cs
- TrackingDataItemValue.cs
- SpeechAudioFormatInfo.cs
- BitStack.cs
- DescendentsWalkerBase.cs
- RequestCachePolicyConverter.cs
- CodeDelegateInvokeExpression.cs
- TrustDriver.cs
- SecureConversationVersion.cs
- Listbox.cs
- ScriptIgnoreAttribute.cs
- XmlnsCompatibleWithAttribute.cs
- TimersDescriptionAttribute.cs
- Registry.cs
- ConfigUtil.cs
- SuppressIldasmAttribute.cs
- basecomparevalidator.cs
- EndOfStreamException.cs
- LinkDescriptor.cs
- SocketException.cs
- BulletDecorator.cs
- DateTimeHelper.cs
- DynamicActionMessageFilter.cs
- EntityTransaction.cs
- UnsafeNativeMethods.cs
- ProxyWebPartManagerDesigner.cs
- DoWorkEventArgs.cs
- PriorityQueue.cs
- VSWCFServiceContractGenerator.cs
- Effect.cs
- WebSysDescriptionAttribute.cs
- QuaternionAnimationBase.cs
- InvokeCompletedEventArgs.cs
- _IPv4Address.cs
- TextParagraph.cs
- InputDevice.cs
- SortQuery.cs
- SequentialOutput.cs
- AtlasWeb.Designer.cs
- BitmapSizeOptions.cs
- PerfCounters.cs
- KeyMatchBuilder.cs
- ServiceMetadataExtension.cs
- SpotLight.cs
- RequestQueue.cs
- StateBag.cs
- PermissionAttributes.cs