Пример #1
0
        internal HwndStylusInputProvider(HwndSource source)
        {
            InputManager inputManager = InputManager.Current;
            StylusLogic  stylusLogic  = inputManager.StylusLogic;

            IntPtr sourceHandle;

            (new UIPermission(PermissionState.Unrestricted)).Assert();
            try //Blessed Assert this is for RegisterInputManager and RegisterHwndforinput
            {
                // Register ourselves as an input provider with the input manager.
                _site = new SecurityCriticalDataClass <InputProviderSite>(inputManager.RegisterInputProvider(this));

                sourceHandle = source.Handle;
            }
            finally
            {
                UIPermission.RevertAssert();
            }

            stylusLogic.RegisterHwndForInput(inputManager, source);
            _source      = new SecurityCriticalDataClass <HwndSource>(source);
            _stylusLogic = new SecurityCriticalDataClass <StylusLogic>(stylusLogic);

            // Enables multi-touch input
            UnsafeNativeMethods.SetProp(new HandleRef(this, sourceHandle), "MicrosoftTabletPenServiceProperty", new HandleRef(null, new IntPtr(MultiTouchEnabledFlag)));
        }
Пример #2
0
        internal PointerStylusDevice(PointerTabletDevice tabletDevice, UnsafeNativeMethods.POINTER_DEVICE_CURSOR_INFO cursorInfo)
        {
            _cursorInfo   = cursorInfo;
            _tabletDevice = tabletDevice;
            _pointerLogic = StylusLogic.GetCurrentStylusLogicAs <PointerLogic>();

            // Touch devices have a special set of handling code
            if (tabletDevice.Type == TabletDeviceType.Touch)
            {
                TouchDevice = new PointerTouchDevice(this);
            }

            _interactionEngine = new PointerInteractionEngine(this);

            _interactionEngine.InteractionDetected += HandleInteraction;

            List <StylusButton> buttons = new List <StylusButton>();

            // Create a button collection for this StylusDevice based off the button properties stored in the tablet
            // This needs to be done as each button instance has a StylusDevice owner that it uses to access the raw
            // data in the StylusDevice.
            foreach (var prop in _tabletDevice.DeviceInfo.StylusPointProperties)
            {
                if (prop.IsButton)
                {
                    StylusButton button = new StylusButton(StylusPointPropertyIds.GetStringRepresentation(prop.Id), prop.Id);
                    button.SetOwner(this);
                    buttons.Add(button);
                }
            }

            _stylusButtons = new StylusButtonCollection(buttons);
        }
        internal override void UpdateState(UIElement element)
        {
            bool unhookPenContexts = true;

            // Disable processing of the queue during blocking operations to prevent unrelated reentrancy
            // which a call to Lock() can cause.
            using (element.Dispatcher.DisableProcessing())
            {
                // See if we should be enabled
                if (element.IsVisible && element.IsEnabled && element.IsHitTestVisible)
                {
                    PresentationSource presentationSource = PresentationSource.CriticalFromVisual(element as Visual);

                    if (presentationSource != null)
                    {
                        unhookPenContexts = false;

                        // Are we currently hooked up?  If not then hook up.
                        if (_penContexts == null)
                        {
                            InputManager inputManager = (InputManager)element.Dispatcher.InputManager;
                            PenContexts  penContexts  = StylusLogic.GetCurrentStylusLogicAs <WispLogic>().GetPenContextsFromHwnd(presentationSource);

                            // _penContexts must be non null or don't do anything.
                            if (penContexts != null)
                            {
                                _penContexts = penContexts;

                                lock (penContexts.SyncRoot)
                                {
                                    penContexts.AddStylusPlugInCollection(Wrapper);

                                    foreach (StylusPlugIn spi in Wrapper)
                                    {
                                        spi.InvalidateIsActiveForInput(); // Uses _penContexts being set to determine active state.
                                    }
                                    // NTRAID:WINDOWSOS#1677277-2006/06/05-WAYNEZEN,
                                    // Normally the Rect will be updated when we receive the LayoutUpdate.
                                    // However there could be a race condition which the LayoutUpdate gets received
                                    // before the properties like IsVisible being set.
                                    // So we should always force to call OnLayoutUpdated whenever the input is active.
                                    Wrapper.OnLayoutUpdated(this.Wrapper, EventArgs.Empty);
                                }
                            }
                        }
                    }
                }

                if (unhookPenContexts)
                {
                    Unhook();
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Creates a new input provider for a particular source that handles WM_POINTER messages
        /// </summary>
        /// <param name="source">The source to handle messages for</param>
        internal HwndPointerInputProvider(HwndSource source)
        {
            _site = new SecurityCriticalDataClass <InputProviderSite>(InputManager.Current.RegisterInputProvider(this));

            _source       = new SecurityCriticalDataClass <HwndSource>(source);
            _pointerLogic = new SecurityCriticalDataClass <PointerLogic>(StylusLogic.GetCurrentStylusLogicAs <PointerLogic>());

            // Register the stylus plugin manager
            _pointerLogic.Value.PlugInManagers[_source.Value] = new PointerStylusPlugInManager(_source.Value);

            // Store if this window is enabled or disabled
            int style = MS.Win32.UnsafeNativeMethods.GetWindowLong(new HandleRef(this, source.CriticalHandle), MS.Win32.NativeMethods.GWL_STYLE);

            IsWindowEnabled = (style & MS.Win32.NativeMethods.WS_DISABLED) == 0;
        }
Пример #5
0
        internal override void UpdateState(UIElement element)
        {
            bool unhook = true;

            // See if we should be enabled
            if (element.IsVisible && element.IsEnabled && element.IsHitTestVisible)
            {
                PresentationSource presentationSource = PresentationSource.CriticalFromVisual(element as Visual);

                if (presentationSource != null)
                {
                    unhook = false;

                    // Are we currently hooked up?  If not then hook up.
                    if (_manager == null)
                    {
                        _manager = StylusLogic.GetCurrentStylusLogicAs <PointerLogic>().PlugInManagers[presentationSource];

                        // _manager must be non null or don't do anything.
                        if (_manager != null)
                        {
                            _manager.AddStylusPlugInCollection(Wrapper);

                            foreach (StylusPlugIn spi in Wrapper)
                            {
                                spi.InvalidateIsActiveForInput();
                            }
                            //
                            // Normally the Rect will be updated when we receive the LayoutUpdate.
                            // However there could be a race condition which the LayoutUpdate gets received
                            // before the properties like IsVisible being set.
                            // So we should always force to call OnLayoutUpdated whenever the input is active.
                            Wrapper.OnLayoutUpdated(this.Wrapper, EventArgs.Empty);
                        }
                    }
                }
            }

            if (unhook)
            {
                Unhook();
            }
        }
Пример #6
0
        /////////////////////////////////////////////////////////////////////
        internal HwndStylusInputProvider(HwndSource source)
        {
            InputManager inputManager = InputManager.Current;

            _stylusLogic = new SecurityCriticalDataClass <WispLogic>(StylusLogic.GetCurrentStylusLogicAs <WispLogic>());

            IntPtr sourceHandle;

            // Register ourselves as an input provider with the input manager.
            _site = new SecurityCriticalDataClass <InputProviderSite>(inputManager.RegisterInputProvider(this));

            sourceHandle = source.Handle;

            _stylusLogic.Value.RegisterHwndForInput(inputManager, source);
            _source = new SecurityCriticalDataClass <HwndSource>(source);

            // Enables multi-touch input
            UnsafeNativeMethods.SetProp(new HandleRef(this, sourceHandle), "MicrosoftTabletPenServiceProperty", new HandleRef(null, new IntPtr(MultiTouchEnabledFlag)));
        }
Пример #7
0
        internal void SynchronizeReverseInheritPropertyFlags(DependencyObject oldParent, bool isCoreParent)
        {
            if (IsKeyboardFocusWithin)
            {
                Keyboard.PrimaryDevice.ReevaluateFocusAsync(this, oldParent, isCoreParent);
            }

            // Reevelauate the stylus properties first to guarentee that our property change
            // notifications fire before mouse properties.
            if (IsStylusOver)
            {
                StylusLogic.CurrentStylusLogicReevaluateStylusOver(this, oldParent, isCoreParent);
            }

            if (IsStylusCaptureWithin)
            {
                StylusLogic.CurrentStylusLogicReevaluateCapture(this, oldParent, isCoreParent);
            }

            if (IsMouseOver)
            {
                Mouse.PrimaryDevice.ReevaluateMouseOver(this, oldParent, isCoreParent);
            }

            if (IsMouseCaptureWithin)
            {
                Mouse.PrimaryDevice.ReevaluateCapture(this, oldParent, isCoreParent);
            }

            if (AreAnyTouchesOver)
            {
                TouchDevice.ReevaluateDirectlyOver(this, oldParent, isCoreParent);
            }

            if (AreAnyTouchesCapturedWithin)
            {
                TouchDevice.ReevaluateCapturedWithin(this, oldParent, isCoreParent);
            }
        }
Пример #8
0
        internal WispTabletDeviceCollection()
        {
            WispLogic stylusLogic = StylusLogic.GetCurrentStylusLogicAs <WispLogic>();
            bool      enabled     = stylusLogic.Enabled;

            if (!enabled)
            {
                enabled = ShouldEnableTablets();
            }

            // If enabled or we are a tabletpc (vista sets dynamically if digitizers present) then enable the pen!
            if (enabled)
            {
                UpdateTablets(); // Create the tablet device collection!

                // Enable stylus input on all hwnds if we have not yet done so.
                if (!stylusLogic.Enabled)
                {
                    stylusLogic.EnableCore();
                }
            }
        }
Пример #9
0
        internal IntPtr FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            IntPtr result = IntPtr.Zero;

            // It is possible to be re-entered during disposal.  Just return.
            if (null == _source || null == _source.Value)
            {
                return(result);
            }

            switch (msg)
            {
            case WindowMessage.WM_ENABLE:
                _stylusLogic.Value.OnWindowEnableChanged(hwnd, (int)NativeMethods.IntPtrToInt32(wParam) == 0);
                break;

            case WindowMessage.WM_TABLET_QUERYSYSTEMGESTURESTATUS:
                handled = true;

                NativeMethods.POINT pt1 = new NativeMethods.POINT(
                    NativeMethods.SignedLOWORD(lParam),
                    NativeMethods.SignedHIWORD(lParam));
                SafeNativeMethods.ScreenToClient(new HandleRef(this, hwnd), pt1);
                Point ptClient1 = new Point(pt1.x, pt1.y);

                IInputElement inputElement = StylusDevice.LocalHitTest(_source.Value, ptClient1);
                if (inputElement != null)
                {
                    // walk up the parent chain
                    DependencyObject elementCur             = (DependencyObject)inputElement;
                    bool             isPressAndHoldEnabled  = Stylus.GetIsPressAndHoldEnabled(elementCur);
                    bool             isFlicksEnabled        = Stylus.GetIsFlicksEnabled(elementCur);
                    bool             isTapFeedbackEnabled   = Stylus.GetIsTapFeedbackEnabled(elementCur);
                    bool             isTouchFeedbackEnabled = Stylus.GetIsTouchFeedbackEnabled(elementCur);

                    uint flags = 0;

                    if (!isPressAndHoldEnabled)
                    {
                        flags |= TABLET_PRESSANDHOLD_DISABLED;
                    }

                    if (!isTapFeedbackEnabled)
                    {
                        flags |= TABLET_TAPFEEDBACK_DISABLED;
                    }

                    if (isTouchFeedbackEnabled)
                    {
                        flags |= TABLET_TOUCHUI_FORCEON;
                    }
                    else
                    {
                        flags |= TABLET_TOUCHUI_FORCEOFF;
                    }

                    if (!isFlicksEnabled)
                    {
                        flags |= TABLET_FLICKS_DISABLED;
                    }

                    result = new IntPtr(flags);
                }
                break;

            case WindowMessage.WM_TABLET_FLICK:
                handled = true;

                int flickData = NativeMethods.IntPtrToInt32(wParam);

                // We always handle any scroll actions if we are enabled.  We do this when we see the SystemGesture Flick come through.
                // Note: Scrolling happens on window flicked on even if it is not the active window.
                if (_stylusLogic != null && _stylusLogic.Value.Enabled && (StylusLogic.GetFlickAction(flickData) == 1))
                {
                    result = new IntPtr(0x0001);     // tell UIHub the flick has already been handled.
                }
                break;
            }

            if (handled && EventTrace.IsEnabled(EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info))
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientInputMessage, EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info,
                                                    (_source.Value.CompositionTarget != null ? _source.Value.CompositionTarget.Dispatcher.GetHashCode() : 0),
                                                    hwnd.ToInt64(),
                                                    msg,
                                                    (int)wParam,
                                                    (int)lParam);
            }

            return(result);
        }
Пример #10
0
 internal WispStylusTouchDevice(StylusDeviceBase stylusDevice)
     : base(stylusDevice)
 {
     _stylusLogic     = StylusLogic.GetCurrentStylusLogicAs <WispLogic>();
     PromotingToOther = true;
 }
Пример #11
0
        /// <summary>
        /// Used in order to allow StylusPlugins to affect mouse inputs as well as touch.
        /// </summary>
        internal static void InvokePlugInsForMouse(ProcessInputEventArgs e)
        {
            if (!e.StagingItem.Input.Handled)
            {
                // if we see a preview mouse event that is not generated by a stylus
                // then send on to plugin
                if ((e.StagingItem.Input.RoutedEvent != Mouse.PreviewMouseDownEvent) &&
                    (e.StagingItem.Input.RoutedEvent != Mouse.PreviewMouseUpEvent) &&
                    (e.StagingItem.Input.RoutedEvent != Mouse.PreviewMouseMoveEvent) &&
                    (e.StagingItem.Input.RoutedEvent != InputManager.InputReportEvent))
                {
                    return;
                }

                // record the mouse capture for later reference..
                MouseDevice        mouseDevice;
                PresentationSource source;
                bool             leftButtonDown;
                bool             rightButtonDown;
                RawStylusActions stylusActions = RawStylusActions.None;
                int timestamp;

                // See if we need to deal sending a leave due to this PresentationSource being Deactivated
                // If not then we just return and do nothing.
                if (e.StagingItem.Input.RoutedEvent == InputManager.InputReportEvent)
                {
                    if (_activeMousePlugInCollection?.Element == null)
                    {
                        return;
                    }

                    InputReportEventArgs input = e.StagingItem.Input as InputReportEventArgs;

                    if (input.Report.Type != InputType.Mouse)
                    {
                        return;
                    }

                    RawMouseInputReport mouseInputReport = (RawMouseInputReport)input.Report;

                    if ((mouseInputReport.Actions & RawMouseActions.Deactivate) != RawMouseActions.Deactivate)
                    {
                        return;
                    }

                    mouseDevice = InputManager.UnsecureCurrent.PrimaryMouseDevice;

                    // Mouse set directly over to null when truly deactivating.
                    if (mouseDevice == null || mouseDevice.DirectlyOver != null)
                    {
                        return;
                    }

                    leftButtonDown  = mouseDevice.LeftButton == MouseButtonState.Pressed;
                    rightButtonDown = mouseDevice.RightButton == MouseButtonState.Pressed;
                    timestamp       = mouseInputReport.Timestamp;

                    // Get presentationsource from element.
                    source = PresentationSource.CriticalFromVisual(_activeMousePlugInCollection.Element as Visual);
                }
                else
                {
                    MouseEventArgs mouseEventArgs = e.StagingItem.Input as MouseEventArgs;
                    mouseDevice     = mouseEventArgs.MouseDevice;
                    leftButtonDown  = mouseDevice.LeftButton == MouseButtonState.Pressed;
                    rightButtonDown = mouseDevice.RightButton == MouseButtonState.Pressed;

                    // Only look at mouse input reports that truly come from a mouse (and is not an up or deactivate) and it
                    // must be pressed state if a move (we don't fire stylus inair moves currently)
                    if (mouseEventArgs.StylusDevice != null &&
                        e.StagingItem.Input.RoutedEvent != Mouse.PreviewMouseUpEvent)
                    {
                        return;
                    }

                    if (e.StagingItem.Input.RoutedEvent == Mouse.PreviewMouseMoveEvent)
                    {
                        if (!leftButtonDown)
                        {
                            return;
                        }
                        stylusActions = RawStylusActions.Move;
                    }
                    if (e.StagingItem.Input.RoutedEvent == Mouse.PreviewMouseDownEvent)
                    {
                        MouseButtonEventArgs mouseButtonEventArgs = mouseEventArgs as MouseButtonEventArgs;
                        if (mouseButtonEventArgs.ChangedButton != MouseButton.Left)
                        {
                            return;
                        }
                        stylusActions = RawStylusActions.Down;
                    }
                    if (e.StagingItem.Input.RoutedEvent == Mouse.PreviewMouseUpEvent)
                    {
                        MouseButtonEventArgs mouseButtonEventArgs = mouseEventArgs as MouseButtonEventArgs;
                        if (mouseButtonEventArgs.ChangedButton != MouseButton.Left)
                        {
                            return;
                        }
                        stylusActions = RawStylusActions.Up;
                    }
                    timestamp = mouseEventArgs.Timestamp;

                    Visual directlyOverVisual = mouseDevice.DirectlyOver as Visual;
                    if (directlyOverVisual == null)
                    {
                        return;
                    }

                    //
                    // Take the presentation source which is associated to the directly over element.
                    source = PresentationSource.CriticalFromVisual(directlyOverVisual);
                }

                if ((source != null) &&
                    (source.CompositionTarget != null) &&
                    !source.CompositionTarget.IsDisposed)
                {
                    IInputElement directlyOver = mouseDevice.DirectlyOver;
                    int           packetStatus = (leftButtonDown ? 1 : 0) | (rightButtonDown ? 9 : 0); // pen tip down == 1, barrel = 8
                    Point         ptClient     = mouseDevice.GetPosition(source.RootVisual as IInputElement);
                    ptClient = source.CompositionTarget.TransformToDevice.Transform(ptClient);

                    int   buttons = (leftButtonDown ? 1 : 0) | (rightButtonDown ? 3 : 0);
                    int[] data    = { (int)ptClient.X, (int)ptClient.Y, packetStatus, buttons };
                    RawStylusInputReport inputReport = new RawStylusInputReport(
                        InputMode.Foreground,
                        timestamp,
                        source,
                        stylusActions,
                        () => { return(MousePointDescription); },
                        0, 0,
                        data);

                    PointerStylusPlugInManager manager =
                        StylusLogic.GetCurrentStylusLogicAs <PointerLogic>()?.GetManagerForSource(source);

                    // Avoid re-entrancy due to lock() being used.
                    using (Dispatcher.CurrentDispatcher.DisableProcessing())
                    {
                        // Call plugins (does enter/leave and FireCustomData as well)
                        _activeMousePlugInCollection = manager?.InvokeStylusPluginCollectionForMouse(inputReport, directlyOver, _activeMousePlugInCollection);
                    }
                }
            }
        }
Пример #12
0
        /// <summary>
        /// Verifies that the call to the stylus plugin on the RTI thread was valid against the current visual tree.
        /// If this verification fails, we will rebuild and resend the raw input and custom data in order to inform
        /// the target collections of the error and fix it.
        /// </summary>
        /// <remarks>
        /// This is a remnant of verifying hits to the collections based on the UI thread calling this
        /// after the real time input thread has previously called a collection.  This is due to the RTI thread
        /// not being 100% synchronous with the visual tree in terms of hitting the collections.  This is sort of
        /// redundant right now, but needs to be here when we re-implement the RTI.
        /// </remarks>
        internal void VerifyStylusPlugInCollectionTarget(RawStylusInputReport rawStylusInputReport)
        {
            switch (rawStylusInputReport.Actions)
            {
            case RawStylusActions.Down:
            case RawStylusActions.Move:
            case RawStylusActions.Up:
                break;

            default:
                return;     // do nothing if not Down, Move or Up.
            }

            PointerLogic pointerLogic = StylusLogic.GetCurrentStylusLogicAs <PointerLogic>();

            RawStylusInput originalRSI = rawStylusInputReport.RawStylusInput;
            // See if we have a plugin for the target of this input.
            StylusPlugInCollection targetPIC    = null;
            StylusPlugInCollection targetRtiPIC = (originalRSI != null) ? originalRSI.Target : null;
            bool updateEventPoints = false;

            // Make sure we use UIElement for target if non NULL and hit ContentElement.
            UIElement newTarget = InputElement.GetContainingUIElement(rawStylusInputReport.StylusDevice.DirectlyOver as DependencyObject) as UIElement;

            if (newTarget != null)
            {
                targetPIC = FindPlugInCollection(newTarget);
            }

            // Make sure any lock() calls do not reenter on us.
            using (Dispatcher.CurrentDispatcher.DisableProcessing())
            {
                // See if we hit the wrong PlugInCollection on the pen thread and clean things up if we did.
                if (targetRtiPIC != null && targetRtiPIC != targetPIC && originalRSI != null)
                {
                    // Fire custom data not confirmed events for both pre and post since bad target...
                    foreach (RawStylusInputCustomData customData in originalRSI.CustomDataList)
                    {
                        customData.Owner.FireCustomData(customData.Data, rawStylusInputReport.Actions, false);
                    }

                    updateEventPoints = originalRSI.StylusPointsModified;

                    // Clear RawStylusInput data.
                    rawStylusInputReport.RawStylusInput = null;
                }

                // See if we need to build up an RSI to send to the plugincollection (due to a mistarget).
                bool sendRawStylusInput = false;
                if (targetPIC != null && rawStylusInputReport.RawStylusInput == null)
                {
                    // NOTE: (This applies when RTI is back in) 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(rawStylusInputReport.StylusDevice.As <PointerStylusDevice>().GetTabletToElementTransform(null)); // this gives matrix in measured units (not device)
                    transformTabletToView.Children.Add(targetPIC.ViewToElement);                                                                        // Make it relative to the element.
                    transformTabletToView.Freeze();                                                                                                     // Must be frozen for multi-threaded access.

                    RawStylusInput rawStylusInput = new RawStylusInput(rawStylusInputReport, transformTabletToView, targetPIC);
                    rawStylusInputReport.RawStylusInput = rawStylusInput;
                    sendRawStylusInput = true;
                }

                PointerStylusDevice stylusDevice = rawStylusInputReport.StylusDevice.As <PointerStylusDevice>();

                // Now fire the confirmed enter/leave events as necessary.
                StylusPlugInCollection currentTarget = stylusDevice.CurrentVerifiedTarget;
                if (targetPIC != currentTarget)
                {
                    if (currentTarget != null)
                    {
                        // Fire leave event.  If we never had a plugin for this event then create a temp one.
                        if (originalRSI == null)
                        {
                            GeneralTransformGroup transformTabletToView = new GeneralTransformGroup();
                            transformTabletToView.Children.Add(stylusDevice.GetTabletToElementTransform(null)); // this gives matrix in measured units (not device)
                            transformTabletToView.Children.Add(currentTarget.ViewToElement);                    // Make it relative to the element.
                            transformTabletToView.Freeze();                                                     // Must be frozen for multi-threaded access.
                            originalRSI = new RawStylusInput(rawStylusInputReport, transformTabletToView, currentTarget);
                        }
                        currentTarget.FireEnterLeave(false, originalRSI, true);
                    }

                    if (targetPIC != null)
                    {
                        // Fire Enter event
                        targetPIC.FireEnterLeave(true, rawStylusInputReport.RawStylusInput, true);

                        // Indicate we've used a stylus plugin
                        pointerLogic.Statistics.FeaturesUsed |= Tracing.StylusTraceLogger.FeatureFlags.StylusPluginsUsed;
                    }

                    // Update the verified target.
                    stylusDevice.CurrentVerifiedTarget = targetPIC;
                }

                // Now fire RawStylusInput if needed to the right plugincollection.
                if (sendRawStylusInput)
                {
                    // We are on the pen thread, just call directly.
                    targetPIC.FireRawStylusInput(rawStylusInputReport.RawStylusInput);
                    updateEventPoints = (updateEventPoints || rawStylusInputReport.RawStylusInput.StylusPointsModified);

                    // Indicate we've used a stylus plugin
                    pointerLogic.Statistics.FeaturesUsed |= Tracing.StylusTraceLogger.FeatureFlags.StylusPluginsUsed;
                }

                // Now fire PrePreviewCustomData events.
                if (targetPIC != null)
                {
                    // Send custom data pre event
                    foreach (RawStylusInputCustomData customData in rawStylusInputReport.RawStylusInput.CustomDataList)
                    {
                        customData.Owner.FireCustomData(customData.Data, rawStylusInputReport.Actions, true);
                    }
                }

                // VerifyRawTarget might resend to correct plugins or may have hit the wrong plugincollection.  The StylusPackets
                // may be overriden in those plugins so we need to call UpdateEventStylusPoints to update things.
                if (updateEventPoints)
                {
                    rawStylusInputReport.StylusDevice.As <PointerStylusDevice>().UpdateEventStylusPoints(rawStylusInputReport, true);
                }
            }
        }