Esempio n. 1
0
        internal void Update(HwndPointerInputProvider provider, PresentationSource inputSource,
                             PointerData pointerData, RawStylusInputReport rsir)
        {
            _lastEventTimeTicks = Environment.TickCount;

            _inputSource = new SecurityCriticalDataClass <PresentationSource>(inputSource);

            _pointerData = pointerData;

            // First get the initial stylus points.  Raw data from pointer input comes in screen coordinates, keep that here since that is what we expect.
            _currentStylusPoints = new StylusPointCollection(rsir.StylusPointDescription, rsir.GetRawPacketData(), GetTabletToElementTransform(null), Matrix.Identity);

            // If a plugin has modified these points, we need to fixup the points with the new input
            if (rsir?.RawStylusInput?.StylusPointsModified ?? false)
            {
                // Note that RawStylusInput.Target (of type StylusPluginCollection)
                // guarantees that ViewToElement is invertible.
                GeneralTransform transformToElement = rsir.RawStylusInput.Target.ViewToElement.Inverse;

                Debug.Assert(transformToElement != null);

                _currentStylusPoints = rsir.RawStylusInput.GetStylusPoints(transformToElement);
            }

            // Store the current hwnd provider so we know for what hwnd we are processing this message
            CurrentPointerProvider = provider;

            if (PointerTabletDevice.Type == TabletDeviceType.Touch)
            {
                // If we are a touch device, sync the ActiveSource
                TouchDevice.ChangeActiveSource(_inputSource.Value);
            }
        }
        private void DetectFlick(RawStylusInputReport rsir)
        {
            // Make sure the flick engine has the latest data if applicable.
            _flickEngine?.Update(rsir);

            // If we have received an up then we should check if
            // we can still be a flick.  If this is true, then fire a flick.
            if (rsir.Actions == RawStylusActions.Up &&
                (_flickEngine?.Result?.CanBeFlick ?? false))
            {
                //

                InteractionDetected?.Invoke(this,
                                            new RawStylusSystemGestureInputReport(
                                                InputMode.Foreground,
                                                Environment.TickCount,
                                                _stylusDevice.CriticalActiveSource,
                                                (Func <StylusPointDescription>)null,
                                                -1,
                                                -1,
                                                SystemGesture.Flick,
                                                Convert.ToInt32(_flickEngine.Result.TabletStart.X),
                                                Convert.ToInt32(_flickEngine.Result.TabletStart.Y),
                                                0));

                _firedFlick = true;
            }
        }
Esempio n. 3
0
        internal override void Synchronize()
        {
            // Simulate a stylus move (if we are current stylus, inrange, visuals still valid to update
            // and has moved).
            if (InRange && _inputSource != null && _inputSource.Value != null &&
                _inputSource.Value.CompositionTarget != null && !_inputSource.Value.CompositionTarget.IsDisposed)
            {
                Point rawScreenPoint = new Point(_pointerData.Info.ptPixelLocationRaw.X, _pointerData.Info.ptPixelLocationRaw.Y);
                Point ptDevice       = PointUtil.ScreenToClient(rawScreenPoint, _inputSource.Value);

                // GlobalHitTest always returns an IInputElement, so we are sure to have one.
                IInputElement stylusOver     = Input.StylusDevice.GlobalHitTest(_inputSource.Value, ptDevice);
                bool          fOffsetChanged = false;

                if (_stylusOver == stylusOver)
                {
                    Point ptOffset = GetPosition(stylusOver);
                    fOffsetChanged = MS.Internal.DoubleUtil.AreClose(ptOffset.X, _rawElementRelativePosition.X) == false || MS.Internal.DoubleUtil.AreClose(ptOffset.Y, _rawElementRelativePosition.Y) == false;
                }

                if (fOffsetChanged || _stylusOver != stylusOver)
                {
                    int timeStamp = Environment.TickCount;

                    if (_currentStylusPoints != null &&
                        _currentStylusPoints.Count > 0 &&
                        StylusPointDescription.AreCompatible(PointerTabletDevice.StylusPointDescription, _currentStylusPoints.Description))
                    {
                        StylusPoint stylusPoint = _currentStylusPoints[_currentStylusPoints.Count - 1];
                        int[]       data        = stylusPoint.GetPacketData();

                        // get back to the correct coordinate system
                        Matrix m = _tabletDevice.TabletToScreen;
                        m.Invert();
                        Point ptTablet = ptDevice * m;

                        data[0] = (int)ptTablet.X;
                        data[1] = (int)ptTablet.Y;

                        RawStylusInputReport report = new RawStylusInputReport(InputMode.Foreground,
                                                                               timeStamp,
                                                                               _inputSource.Value,
                                                                               InAir ? RawStylusActions.InAirMove : RawStylusActions.Move,
                                                                               () => { return(PointerTabletDevice.StylusPointDescription); },
                                                                               TabletDevice.Id,
                                                                               Id,
                                                                               data);


                        report.Synchronized = true;

                        InputReportEventArgs inputReportEventArgs = new InputReportEventArgs(StylusDevice, report);
                        inputReportEventArgs.RoutedEvent = InputManager.PreviewInputReportEvent;

                        InputManager.Current.ProcessInput(inputReportEventArgs);
                    }
                }
            }
        }
        /// <summary>
        /// </summary>
        internal StylusPlugInCollection InvokeStylusPluginCollectionForMouse(RawStylusInputReport inputReport, IInputElement directlyOver, StylusPlugInCollection currentPlugInCollection)
        {
            StylusPlugInCollection newPlugInCollection = null;

            // 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);

                // Indicate we've used a stylus plugin
                StylusLogic.CurrentStylusLogic.Statistics.FeaturesUsed |= Tracing.StylusTraceLogger.FeatureFlags.StylusPluginsUsed;
            }
            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);
                }

                // (Comment not applicable until RTI back in) We are on the RTI thread, just call directly.
                newPlugInCollection.FireRawStylusInput(rawStylusInput);

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

                // Fire custom data events (always confirmed for mouse)
                foreach (RawStylusInputCustomData customData in rawStylusInput.CustomDataList)
                {
                    customData.Owner.FireCustomData(customData.Data, inputReport.Actions, true);
                }
            }

            return(newPlugInCollection);
        }
Esempio n. 5
0
        internal override void UpdateEventStylusPoints(RawStylusInputReport report, bool resetIfNoOverride)
        {
            if (report.RawStylusInput != null && report.RawStylusInput.StylusPointsModified)
            {
                GeneralTransform transformToElement = report.RawStylusInput.Target.ViewToElement.Inverse;
                //note that RawStylusInput.Target (of type StylusPluginCollection)
                //guarantees that ViewToElement is invertible
                Debug.Assert(transformToElement != null);

                _currentStylusPoints = report.RawStylusInput.GetStylusPoints(transformToElement);
            }
            else if (resetIfNoOverride)
            {
                _currentStylusPoints =
                    new StylusPointCollection(report.StylusPointDescription,
                                              report.GetRawPacketData(),
                                              GetTabletToElementTransform(null),
                                              Matrix.Identity);
            }
        }
        internal void Update(RawStylusInputReport rsir)
        {
            try
            {
                // Queue up the latest message for processing
                UnsafeNativeMethods.BufferPointerPacketsInteractionContext(_interactionContext.Value, 1, new UnsafeNativeMethods.POINTER_INFO[] { _stylusDevice.CurrentPointerInfo });

                // Hover processing should occur directly from message receipt.
                // Do this prior to the IC engine processing so HoverEnter/Leave has priority.
                DetectHover();

                //
                DetectFlick(rsir);

                // Fire processing of the queued messages
                UnsafeNativeMethods.ProcessBufferedPacketsInteractionContext(_interactionContext.Value);
            }
            catch
            {
            }
        }
        /////////////////////////////////////////////////////////////////////
        /// <summary>
        ///     [TBS]
        /// </summary>
        /// <param name="report">[TBS]</param>
        /// <param name="tabletToElementTransform">[TBS]</param>
        /// <param name="targetPlugInCollection">[TBS]</param>
        internal RawStylusInput(
            RawStylusInputReport    report,
            GeneralTransform        tabletToElementTransform,
            StylusPlugInCollection targetPlugInCollection)
        {
            if (report == null)
            {
                throw new ArgumentNullException("report");
            }
            if (tabletToElementTransform.Inverse == null)
            {
                throw new ArgumentException(SR.Get(SRID.Stylus_MatrixNotInvertable), "tabletToElementTransform");
            }
            if (targetPlugInCollection == null)
            {
                throw new ArgumentNullException("targetPlugInCollection");
            }

            // We should always see this GeneralTransform is frozen since we access this from multiple threads.
            System.Diagnostics.Debug.Assert(tabletToElementTransform.IsFrozen);
            _report                 = report;
            _tabletToElementTransform  = tabletToElementTransform;
            _targetPlugInCollection = targetPlugInCollection;
        }
Esempio n. 8
0
        /////////////////////////////////////////////////////////////////////
        /// <summary>
        ///     [TBS]
        /// </summary>
        /// <param name="report">[TBS]</param>
        /// <param name="tabletToElementTransform">[TBS]</param>
        /// <param name="targetPlugInCollection">[TBS]</param>
        internal RawStylusInput(
            RawStylusInputReport report,
            GeneralTransform tabletToElementTransform,
            StylusPlugInCollection targetPlugInCollection)
        {
            if (report == null)
            {
                throw new ArgumentNullException("report");
            }
            if (tabletToElementTransform.Inverse == null)
            {
                throw new ArgumentException(SR.Get(SRID.Stylus_MatrixNotInvertable), "tabletToElementTransform");
            }
            if (targetPlugInCollection == null)
            {
                throw new ArgumentNullException("targetPlugInCollection");
            }

            // We should always see this GeneralTransform is frozen since we access this from multiple threads.
            System.Diagnostics.Debug.Assert(tabletToElementTransform.IsFrozen);
            _report = report;
            _tabletToElementTransform = tabletToElementTransform;
            _targetPlugInCollection   = targetPlugInCollection;
        }
        /// <summary>
        /// Target a plugin collection that either has capture or passes a hit test.
        /// raw input.
        /// </summary>
        /// <param name="inputReport">The raw input to process</param>
        /// <returns>The appropriate collection target</returns>
        internal StylusPlugInCollection TargetPlugInCollection(RawStylusInputReport inputReport)
        {
            StylusPlugInCollection pic = null;

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

            bool elementHasCapture = false;

            pic = stylusDevice.GetCapturedPlugInCollection(ref elementHasCapture);

            int pointLength = inputReport.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 * stylusDevice.TabletDevice.TabletDeviceImpl.TabletToScreen;
                ptTablet.X = (int)Math.Round(ptTablet.X);                                   // Make sure we snap to whole window pixels.
                ptTablet.Y = (int)Math.Round(ptTablet.Y);
                ptTablet  *= inputReport.InputSource.CompositionTarget.TransformFromDevice; // change to measured units now.

                pic = HittestPlugInCollection(ptTablet);                                    // Use cached rectangles for UIElements.
            }

            return(pic);
        }
Esempio n. 10
0
        /// <summary>
        /// Processes the latest WM_POINTER message and forwards it to the WPF input stack.
        /// </summary>
        /// <param name="pointerId">The id of the pointer message</param>
        /// <param name="action">The stylus action being done</param>
        /// <param name="timestamp">The time (in ticks) the message arrived</param>
        /// <returns>True if successfully processed (handled), false otherwise</returns>
        private bool ProcessMessage(uint pointerId, RawStylusActions action, int timestamp)
        {
            bool handled = false;

            // Acquire all pointer data needed
            PointerData data = new PointerData(pointerId);

            // Only process touch or pen messages, do not process mouse or touchpad
            if (data.IsValid &&
                (data.Info.pointerType == UnsafeNativeMethods.POINTER_INPUT_TYPE.PT_TOUCH ||
                 data.Info.pointerType == UnsafeNativeMethods.POINTER_INPUT_TYPE.PT_PEN))
            {
                uint cursorId = 0;

                if (UnsafeNativeMethods.GetPointerCursorId(pointerId, ref cursorId))
                {
                    IntPtr deviceId = data.Info.sourceDevice;

                    // If we cannot acquire the latest tablet and stylus then wait for the
                    // next message.
                    if (!UpdateCurrentTabletAndStylus(deviceId, cursorId))
                    {
                        return(false);
                    }

                    // Convert move to InAirMove if applicable
                    if (action == RawStylusActions.Move &&
                        (!data.Info.pointerFlags.HasFlag(UnsafeNativeMethods.POINTER_FLAGS.POINTER_FLAG_INCONTACT) &&
                         data.Info.pointerFlags.HasFlag(UnsafeNativeMethods.POINTER_FLAGS.POINTER_FLAG_INRANGE)))
                    {
                        action = RawStylusActions.InAirMove;
                    }

                    // Generate a raw input to send to the input manager to start the event chain in PointerLogic
                    RawStylusInputReport rsir =
                        new RawStylusInputReport(
                            InputMode.Foreground,
                            timestamp,
                            _source.Value,
                            action,
                            () => { return(_currentTabletDevice.StylusPointDescription); },
                            _currentTabletDevice.Id,
                            _currentStylusDevice.Id,
                            GenerateRawStylusData(data, _currentTabletDevice))
                    {
                        StylusDevice = _currentStylusDevice.StylusDevice,
                    };

                    // Send the input report to the stylus plugins if we're not doing a drag and the window
                    // is currently enabled.
                    if (!_pointerLogic.Value.InDragDrop && IsWindowEnabled)
                    {
                        PointerStylusPlugInManager manager;

                        if (_pointerLogic.Value.PlugInManagers.TryGetValue(_source.Value, out manager))
                        {
                            manager.InvokeStylusPluginCollection(rsir);
                        }
                    }

                    // Update the data in the stylus device with the latest pointer data
                    _currentStylusDevice.Update(this, _source.Value, data, rsir);

                    // Call the StylusDevice to process and fire any interactions that
                    // might have resulted from the input.  If the originating inputs
                    // have been handled, we don't want to generate any gestures.
                    _currentStylusDevice.UpdateInteractions(rsir);

                    InputReportEventArgs irea = new InputReportEventArgs(_currentStylusDevice.StylusDevice, rsir)
                    {
                        RoutedEvent = InputManager.PreviewInputReportEvent,
                    };

                    // Now send the input report
                    InputManager.UnsecureCurrent.ProcessInput(irea);

                    // If this is not a primary pointer input, we don't want to
                    // allow it to go to DefWindowProc, so we should handle it.
                    // This ensures that primary pointer to mouse promotions
                    // will occur in multi-touch scenarios.
                    // We don't use the results of the input processing here as doing
                    // so could possibly cause some messages of a pointer chain as
                    // being handled, and some as being unhandled.  This results in
                    // undefined behavior in the WM_POINTER stack.
                    // <see cref="https://msdn.microsoft.com/en-us/library/windows/desktop/hh454923(v=vs.85).aspx"/>
                    handled = !_currentStylusDevice.IsPrimary;
                }
            }

            return(handled);
        }
Esempio n. 11
0
 internal void UpdateInteractions(RawStylusInputReport rsir)
 {
     _interactionEngine.Update(rsir);
 }
        private void ProcessPacket(RawStylusInputReport rsir, bool initial)
        {
            UpdateTimePeriod(rsir.Timestamp, initial);

            if (!_collectingData)
            {
                return;
            }

            Point tabletPoint = rsir.GetLastTabletPoint();

            // Get the device coordinates in HiMetric
            Point physPoint = GetPhysicalCoordinates(tabletPoint);

            if (initial)
            {
                _flickStartPhysical = physPoint;
                _flickStartTablet   = tabletPoint;
                _elapsedTime        = 0;

                SetStableRect();
            }
            else
            {
                _elapsedTime += _timePeriod;
            }

            if (!_movedEnoughFromPenDown)
            {
                if (_lastPhysicalPointValid)
                {
                    double dist = Distance(_lastPhysicalPoint, physPoint);
                    _distance += dist;

                    // If at any time a fair distance is moved from packet to packet
                    // or the entire distance traveled thus far is greater than the side
                    // of m_rcdrag, we say the pen has moved enough and start the flick
                    // detection
                    if ((dist > PreciseFlickMinimumVelocity) || (dist >= _flickMaximumStationaryDisplacementX))
                    {
                        _movedEnoughFromPenDown = true;
                    }
                }

                if (!_movedEnoughFromPenDown)
                {
                    // If the pen has left the m_rcDrag rect or if adequate time
                    // has elapsed, start the flick detection
                    if (!_drag.Contains(physPoint) || (_elapsedTime > 3000))
                    {
                        _movedEnoughFromPenDown = true;
                    }
                }

                _lastPhysicalPoint      = physPoint;
                _lastPhysicalPointValid = true;
            }

            if (_movedEnoughFromPenDown && !_analyzingData)
            {
                CheckWithThreshold(physPoint);
            }

            if (_analyzingData)
            {
                AddPoint(physPoint, tabletPoint);
            }
        }
        internal void Update(RawStylusInputReport rsir, bool initial = false)
        {
            // Do not process non-Pen input
            if (_stylusDevice.TabletDevice.Type != TabletDeviceType.Stylus)
            {
                return;
            }

            switch (rsir.Actions)
            {
            case RawStylusActions.Down:
            {
                // Always reset on a down.  Pens have one contact point so any down must be
                // a new pointer and requires fresh tracking.
                Reset();

                // From this point on we can use inputs from manipulation tracked against the
                // current pointer id in order to tell if we need to update flick information.
                _collectingData = true;

                ProcessPacket(rsir, true);

                if (_analyzingData)
                {
                    Analyze(decide: false);
                }
            }
            break;

            case RawStylusActions.Up:
            {
                if (_canDetectFlick)
                {
                    ProcessPacket(rsir, false);

                    if (_analyzingData)
                    {
                        Analyze(decide: true);
                    }
                    else
                    {
                        // Set Flick Result To Can't Be Flick
                    }
                }

                _collectingData = false;
                _analyzingData  = false;
            }
            break;

            case RawStylusActions.Move:
            {
                if (_canDetectFlick)
                {
                    ProcessPacket(rsir, initial);

                    if (_analyzingData)
                    {
                        Analyze(decide: false);
                    }
                }
            }
            break;
            }
        }
Esempio n. 14
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);
                    }
                }
            }
        }
Esempio n. 15
0
        /// <summary>
        /// Calls the appropriate plugin collection for the raw input.
        /// </summary>
        /// <remarks>
        /// This would normally be called on the RTI thread.  As we do not have one right now, we just call this in the
        /// Hwnd input provider in order to keep similar semantics to how the WISP stack accomplishes this.  When the RTI is
        /// re-implemented, we need to ensure this gets called from there exclusively.
        /// </remarks>
        internal void InvokeStylusPluginCollection(RawStylusInputReport inputReport)
        {
            // Find PenContexts object for this inputReport.
            StylusPlugInCollection pic = null;

            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
            }

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

            StylusPlugInCollection currentPic = stylusDevice.CurrentVerifiedTarget;

            // 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(GetTabletToViewTransform(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);

                // Indicate we've used a stylus plugin
                StylusLogic.CurrentStylusLogic.Statistics.FeaturesUsed |= Tracing.StylusTraceLogger.FeatureFlags.StylusPluginsUsed;
                stylusDevice.CurrentVerifiedTarget = null;
            }

            if (pic != null)
            {
                // NOTE: Comment not applicable without RTI.  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(GetTabletToViewTransform(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)
                {
                    stylusDevice.CurrentVerifiedTarget = pic;
                    pic.FireEnterLeave(true, rawStylusInput, false);
                }

                // Send the input
                pic.FireRawStylusInput(rawStylusInput);

                // Indicate we've used a stylus plugin
                StylusLogic.CurrentStylusLogic.Statistics.FeaturesUsed |= Tracing.StylusTraceLogger.FeatureFlags.StylusPluginsUsed;
            }
        }
Esempio n. 16
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);
                }
            }
        }