Beispiel #1
0
        /// <summary>
        /// Retrieves the StylusDevice associated with the cursor id.
        /// </summary>
        /// <param name="cursorId">The id of the StylusDevice to retrieve</param>
        /// <returns>The StylusDevice associated with the id</returns>
        internal PointerStylusDevice GetStylusByCursorId(uint cursorId)
        {
            PointerStylusDevice stylus = null;

            _stylusDeviceMap.TryGetValue(cursorId, out stylus);
            return(stylus);
        }
Beispiel #2
0
        /// <summary>
        /// Retrieve the StylusDevice associated with the cursor id
        /// </summary>
        /// <param name="cursorId">The cursor id</param>
        /// <returns>The StylusDevice associated with the device id</returns>
        internal PointerStylusDevice GetStylusDeviceByCursorId(uint cursorId)
        {
            PointerStylusDevice stylus = null;

            foreach (var tablet in _tabletDeviceMap.Values)
            {
                if ((stylus = tablet.GetStylusByCursorId(cursorId)) != null)
                {
                    break;
                }
            }

            return(stylus);
        }
        internal PointerFlickEngine(PointerStylusDevice stylusDevice)
        {
            _stylusDevice = stylusDevice;

            _timePeriod             = 8;
            _timePeriodAlpha        = .001;
            _collectingData         = false;
            _analyzingData          = false;
            _previousFlickDataValid = false;
            _allowPressFlicks       = true;

            Reset();

            SetTolerance(.5);
        }
Beispiel #4
0
        /// <summary>
        /// Initializes the interaction engine
        /// </summary>
        /// <param name="stylusDevice"></param>
        /// <param name="configuration"></param>
        internal PointerInteractionEngine(PointerStylusDevice stylusDevice, List <UnsafeNativeMethods.INTERACTION_CONTEXT_CONFIGURATION> configuration = null)
        {
            _stylusDevice = stylusDevice;

            // Only create a flick engine for Pen devices
            if (_stylusDevice.TabletDevice.Type == TabletDeviceType.Stylus)
            {
                // Currently disabled pending decision about flick support in Windows 10 RS3
                //_flickEngine = new PointerFlickEngine(_stylusDevice);
            }

            // Create our interaction context for gesture recognition
            IntPtr interactionContext = IntPtr.Zero;

            UnsafeNativeMethods.CreateInteractionContext(out interactionContext);
            _interactionContext = new SecurityCriticalDataForSet <IntPtr>(interactionContext);

            if (configuration == null)
            {
                configuration = DefaultConfiguration;
            }

            if (_interactionContext.Value != IntPtr.Zero)
            {
                // We do not want to filter specific pointers
                UnsafeNativeMethods.SetPropertyInteractionContext(_interactionContext.Value,
                                                                  UnsafeNativeMethods.INTERACTION_CONTEXT_PROPERTY.INTERACTION_CONTEXT_PROPERTY_FILTER_POINTERS,
                                                                  Convert.ToUInt32(false));

                // Use screen measurements here as this makes certain math easier for us
                UnsafeNativeMethods.SetPropertyInteractionContext(_interactionContext.Value,
                                                                  UnsafeNativeMethods.INTERACTION_CONTEXT_PROPERTY.INTERACTION_CONTEXT_PROPERTY_MEASUREMENT_UNITS,
                                                                  (UInt32)UnsafeNativeMethods.InteractionMeasurementUnits.Screen);

                // Configure the context
                UnsafeNativeMethods.SetInteractionConfigurationInteractionContext(_interactionContext.Value, (uint)configuration.Count, configuration.ToArray());

                // Store the delegate so it can be accessed over time
                _callbackDelegate = Callback;

                // Register for interaction notifications
                UnsafeNativeMethods.RegisterOutputCallbackInteractionContext(_interactionContext.Value, _callbackDelegate);
            }
        }
Beispiel #5
0
        private void BuildStylusDevices()
        {
            UInt32 cursorCount = 0;

            List <PointerStylusDevice> pointerStylusDevices = new List <PointerStylusDevice>();

            if (UnsafeNativeMethods.GetPointerDeviceCursors(_deviceInfo.Device, ref cursorCount, null))
            {
                UnsafeNativeMethods.POINTER_DEVICE_CURSOR_INFO[] cursors = new UnsafeNativeMethods.POINTER_DEVICE_CURSOR_INFO[cursorCount];

                if (UnsafeNativeMethods.GetPointerDeviceCursors(_deviceInfo.Device, ref cursorCount, cursors))
                {
                    foreach (var cursor in cursors)
                    {
                        PointerStylusDevice stylus = new PointerStylusDevice(this, cursor);

                        _stylusDeviceMap.Add(stylus.CursorId, stylus);
                        pointerStylusDevices.Add(stylus);
                    }
                }
            }

            _stylusDevices = new StylusDeviceCollection(pointerStylusDevices.ToArray());
        }
        /// <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);
        }
Beispiel #7
0
 internal PointerTouchDevice(PointerStylusDevice stylusDevice)
     : base(stylusDevice)
 {
     _stylusDevice = stylusDevice;
 }
        /// <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;
            }
        }
        /// <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);
                }
            }
        }