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; } }
private void Callback(IntPtr clientData, ref UnsafeNativeMethods.INTERACTION_CONTEXT_OUTPUT output) { SystemGesture gesture = SystemGesture.None; // Create the appropriate gesture based on interaction output switch (output.interactionId) { case UnsafeNativeMethods.INTERACTION_ID.INTERACTION_ID_TAP: { gesture = SystemGesture.Tap; } break; case UnsafeNativeMethods.INTERACTION_ID.INTERACTION_ID_SECONDARY_TAP: { gesture = SystemGesture.RightTap; } break; case UnsafeNativeMethods.INTERACTION_ID.INTERACTION_ID_HOLD: { _firedHold = true; if (output.interactionFlags.HasFlag(UnsafeNativeMethods.INTERACTION_FLAGS.INTERACTION_FLAG_BEGIN)) { gesture = SystemGesture.HoldEnter; } else { gesture = SystemGesture.HoldLeave; } } break; case UnsafeNativeMethods.INTERACTION_ID.INTERACTION_ID_MANIPULATION: { gesture = DetectDragOrFlick(output); } break; } if (gesture != SystemGesture.None) { InteractionDetected?.Invoke(this, new RawStylusSystemGestureInputReport( InputMode.Foreground, Environment.TickCount, _stylusDevice.CriticalActiveSource, (Func <StylusPointDescription>)null, -1, -1, gesture, Convert.ToInt32(output.x), Convert.ToInt32(output.y), 0)); } }
private void DetectHover() { // Hover only applies to Pen if (_stylusDevice.TabletDevice.Type == TabletDeviceType.Stylus) { SystemGesture gesture = SystemGesture.None; if (_stylusDevice.IsNew) { // Any new stylus should automatically await hover _hoverState = HoverState.AwaitingHover; } switch (_hoverState) { case HoverState.AwaitingHover: { if (_stylusDevice.InAir) { // If we see an InAir while awaiting, start timing _hoverStartTicks = _stylusDevice.TimeStamp; _hoverState = HoverState.TimingHover; } } break; case HoverState.TimingHover: { if (_stylusDevice.InAir) { if (_stylusDevice.TimeStamp < _hoverStartTicks) { // We looped over in ticks, just retry using the new ticks as the start. // At worst this doubles the hover time, but it is rare and simplifies logic. _hoverStartTicks = _stylusDevice.TimeStamp; } else if (_stylusDevice.TimeStamp - _hoverStartTicks > HoverActivationThresholdTicks) { // We should now activate a hover, so send HoverEnter and switch state gesture = SystemGesture.HoverEnter; _hoverState = HoverState.InHover; } } else if (_stylusDevice.IsDown) { // The device is no longer in air so cancel _hoverState = HoverState.HoverCancelled; } } break; case HoverState.HoverCancelled: { if (_stylusDevice.InAir) { // If we are back in air post cancellation, we might need to trigger another hover // so restart the state machine _hoverState = HoverState.AwaitingHover; } } break; case HoverState.InHover: { if (_stylusDevice.IsDown || !_stylusDevice.InRange) { // We are cancelling a hover so send HoverLeave and switch state. gesture = SystemGesture.HoverLeave; _hoverState = HoverState.HoverCancelled; } } break; } if (gesture != SystemGesture.None) { InteractionDetected?.Invoke(this, new RawStylusSystemGestureInputReport( InputMode.Foreground, Environment.TickCount, _stylusDevice.CriticalActiveSource, (Func <StylusPointDescription>)null, -1, -1, gesture, Convert.ToInt32(_stylusDevice.RawStylusPoint.X), Convert.ToInt32(_stylusDevice.RawStylusPoint.Y), 0)); } } }