PenContexts.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Input / Stylus / PenContexts.cs / 1305600 / 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

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK