예제 #1
0
        private RawKeyboardInputReport ExtractRawKeyboardInputReport(NotifyInputEventArgs e, RoutedEvent Event)
        {
            RawKeyboardInputReport keyboardInput = null;

            InputReportEventArgs input = e.StagingItem.Input as InputReportEventArgs;

            if (input != null)
            {
                if (input.Report.Type == InputType.Keyboard && input.RoutedEvent == Event)
                {
                    keyboardInput = input.Report as RawKeyboardInputReport;
                }
            }

            return(keyboardInput);
        }
예제 #2
0
        private RawKeyboardActions GetNonRedundantActions(NotifyInputEventArgs e)
        {
            RawKeyboardActions actions;

            // The CLR throws a null-ref exception if it tries to unbox a
            // null.  So we have to special case that.
            object o = e.StagingItem.GetData(_tagNonRedundantActions);

            if (o != null)
            {
                actions = (RawKeyboardActions)o;
            }
            else
            {
                actions = new RawKeyboardActions();
            }

            return(actions);
        }
예제 #3
0
        public bool ProcessInput(InputEventArgs input)
        {
            StagingAreaInputItem stagingItem = new StagingAreaInputItem(input);

            PreProcessInputEventArgs preProcessArgs = new PreProcessInputEventArgs(this, stagingItem);

            if (PreProcessInput != null)
            {
                PreProcessInput(this, preProcessArgs);
            }

            NotifyInputEventArgs notifyArgs = new NotifyInputEventArgs(this, stagingItem);

            if (PreNotifyInput != null)
            {
                PreNotifyInput(this, notifyArgs);
            }

#if notyet
            if (!preProcessArgs.Canceled)
            {
                /* XXX route the event */;
            }
#endif

            if (PostNotifyInput != null)
            {
                PostNotifyInput(this, notifyArgs);
            }

            if (PostProcessInput != null)
            {
                ProcessInputEventArgs processArgs = new ProcessInputEventArgs(this, stagingItem);
                PostProcessInput(this, processArgs);
            }

            return(true);
        }
예제 #4
0
        private void PreNotifyInput(object sender, NotifyInputEventArgs e) 
        {
            RawKeyboardInputReport keyboardInput = ExtractRawKeyboardInputReport(e, InputManager.PreviewInputReportEvent); 
            if(keyboardInput != null) 
            {
                CheckForDisconnectedFocus(); 

                // Activation
                //
                // MITIGATION: KEYBOARD_STATE_OUT_OF_[....] 
                //
                // It is very important that we allow multiple activate events. 
                // This is how we deal with the fact that Win32 sometimes sends 
                // us a WM_SETFOCUS message BEFORE it has updated it's internal
                // internal keyboard state information.  When we get the 
                // WM_SETFOCUS message, we activate the keyboard with the
                // keyboard state (even though it could be wrong).  Then when
                // we get the first "real" keyboard input event, we activate
                // the keyboard again, since Win32 will have updated the 
                // keyboard state correctly by then.
                // 
                if((keyboardInput.Actions & RawKeyboardActions.Activate) == RawKeyboardActions.Activate) 
                {
                    //if active source is null, no need to do special-case handling 
                    if(_activeSource == null)
                    {
                        // we are now active.
                        _activeSource = new SecurityCriticalDataClass<PresentationSource>(keyboardInput.InputSource); 
                    }
                    else if(_activeSource.Value != keyboardInput.InputSource) 
                    { 
                        IKeyboardInputProvider toDeactivate = _activeSource.Value.GetInputProvider(typeof(KeyboardDevice)) as IKeyboardInputProvider;
 
                        // we are now active.
                        _activeSource = new SecurityCriticalDataClass<PresentationSource>(keyboardInput.InputSource);

                        if(toDeactivate != null) 
                        {
                            toDeactivate.NotifyDeactivate(); 
                        } 
                    }
                } 

                // Generally, we need to check against redundant actions.
                // We never prevet the raw event from going through, but we
                // will only generate the high-level events for non-redundant 
                // actions.  We store the set of non-redundant actions in
                // the dictionary of this event. 
 
                // If the input is reporting a key down, the action is never
                // considered redundant. 
                if((keyboardInput.Actions & RawKeyboardActions.KeyDown) == RawKeyboardActions.KeyDown)
                {
                    RawKeyboardActions actions = GetNonRedundantActions(e);
                    actions |= RawKeyboardActions.KeyDown; 
                    e.StagingItem.SetData(_tagNonRedundantActions, actions);
 
                    // Pass along the key that was pressed, and update our state. 
                    Key key = KeyInterop.KeyFromVirtualKey(keyboardInput.VirtualKey);
                    e.StagingItem.SetData(_tagKey, key); 
                    e.StagingItem.SetData(_tagScanCode, new ScanCode(keyboardInput.ScanCode, keyboardInput.IsExtendedKey));

                    // Tell the InputManager that the MostRecentDevice is us.
                    if(_inputManager!=null) 
                        _inputManager.Value.MostRecentInputDevice = this;
                } 
 
                //
                if((keyboardInput.Actions & RawKeyboardActions.KeyUp) == RawKeyboardActions.KeyUp) 
                {
                    RawKeyboardActions actions = GetNonRedundantActions(e);
                    actions |= RawKeyboardActions.KeyUp;
                    e.StagingItem.SetData(_tagNonRedundantActions, actions); 

                    // Pass along the key that was pressed, and update our state. 
                    Key key = KeyInterop.KeyFromVirtualKey(keyboardInput.VirtualKey); 
                    e.StagingItem.SetData(_tagKey, key);
                    e.StagingItem.SetData(_tagScanCode, new ScanCode(keyboardInput.ScanCode, keyboardInput.IsExtendedKey)); 

                    // Tell the InputManager that the MostRecentDevice is us.
                    if(_inputManager!=null)
                        _inputManager.Value.MostRecentInputDevice = this; 
                }
            } 
 
            // On KeyDown, we might need to set the Repeat flag
 
            if(e.StagingItem.Input.RoutedEvent == Keyboard.PreviewKeyDownEvent)
            {
                CheckForDisconnectedFocus();
 
                KeyEventArgs args = (KeyEventArgs) e.StagingItem.Input;
 
                // Is this the same as the previous key?  (Look at the real key, e.g. TextManager 
                // might have changed args.Key it to Key.TextInput.)
 
                if (_previousKey == args.RealKey)
                {
                    // Yes, this is a repeat (we got the keydown for it twice, with no KeyUp in between)
                    args.SetRepeat(true); 
                }
 
                // Otherwise, keep this key to check against next time. 
                else
                { 
                    _previousKey = args.RealKey;
                    args.SetRepeat(false);
                }
            } 

            // On KeyUp, we clear Repeat flag 
            else if(e.StagingItem.Input.RoutedEvent == Keyboard.PreviewKeyUpEvent) 
            {
                CheckForDisconnectedFocus(); 

                KeyEventArgs args = (KeyEventArgs) e.StagingItem.Input;
                args.SetRepeat(false);
 
                // Clear _previousKey, so that down/up/down/up doesn't look like a repeat
                _previousKey = Key.None; 
            } 
        }
예제 #5
0
        private RawKeyboardActions GetNonRedundantActions(NotifyInputEventArgs e) 
        {
            RawKeyboardActions actions; 
 
            // The CLR throws a null-ref exception if it tries to unbox a
            // null.  So we have to special case that. 
            object o = e.StagingItem.GetData(_tagNonRedundantActions);
            if(o != null)
            {
                actions = (RawKeyboardActions) o; 
            }
            else 
            { 
                actions = new RawKeyboardActions();
            } 

            return actions;
        }
예제 #6
0
        private RawKeyboardInputReport ExtractRawKeyboardInputReport(NotifyInputEventArgs e, RoutedEvent Event) 
        { 
            RawKeyboardInputReport keyboardInput = null;
 
            InputReportEventArgs input = e.StagingItem.Input as InputReportEventArgs;
            if(input != null)
            {
                if(input.Report.Type == InputType.Keyboard && input.RoutedEvent == Event) 
                {
                    keyboardInput = input.Report as RawKeyboardInputReport; 
                } 
            }
 
            return keyboardInput;
        }
예제 #7
0
        private bool ProcessStagingArea()
        {
            bool handled = false;

            // For performance reasons, try to reuse the input event args.
            // If we are reentrered, we have to start over with fresh event
            // args, so we clear the member variables before continuing.
            // Also, we cannot simply make an single instance of the
            // PreProcessedInputEventArgs and cast it to NotifyInputEventArgs
            // or ProcessInputEventArgs because a malicious user could upcast
            // the object and call inappropriate methods.
            NotifyInputEventArgs     notifyInputEventArgs     = (_notifyInputEventArgs != null) ? _notifyInputEventArgs : new NotifyInputEventArgs();
            ProcessInputEventArgs    processInputEventArgs    = (_processInputEventArgs != null) ? _processInputEventArgs : new ProcessInputEventArgs();
            PreProcessInputEventArgs preProcessInputEventArgs = (_preProcessInputEventArgs != null) ? _preProcessInputEventArgs : new PreProcessInputEventArgs();

            _notifyInputEventArgs     = null;
            _processInputEventArgs    = null;
            _preProcessInputEventArgs = null;

            // Because we can be reentered, we can't just enumerate over the
            // staging area - that could throw an exception if the queue
            // changes underneath us.  Instead, just loop until we find a
            // frame marker or until the staging area is empty.
            StagingAreaInputItem item = null;

            while ((item = PopInput()) != null)
            {
                // If we found a marker, we have reached the end of a
                // "section" of the staging area.  We just return from
                // the synchronous processing of the staging area.
                // If a dispatcher frame has been pushed by someone, this
                // will not return to the original ProcessInput.  Instead
                // it will unwind to the dispatcher and since we have
                // already pushed a work item to continue processing the
                // input, it will simply call back into us to do more
                // processing.  At which point we will continue to drain
                // the staging area.  This could cause strage behavior,
                // but it is deemed more acceptable than stalling input
                // processing.

                // In the future, in ordre to
                // make sure we all agree on this.  We could also
                // just delay the rest of the staging area until
                // the dispatcher frame finishes.  Unfortunately,
                // this means one could receive an input event for
                // something that happened a long time ago.
                if (item.IsMarker)
                {
                    break;
                }

                // Pre-Process the input.  This could modify the staging
                // area, and it could cancel the processing of this
                // input event.
                //
                // Because we use multi-cast delegates, we always have to
                // create a new multi-cast delegate when we add or remove
                // a handler.  This means we can just call the current
                // multi-cast delegate instance, and it is safe to iterate
                // over, even if we get reentered.
                if (_preProcessInput != null)
                {
                    preProcessInputEventArgs.Reset(item, this);

                    // Invoke the handlers in reverse order so that handlers that
                    // users add are invoked before handlers in the system.
                    Delegate[] handlers = _preProcessInput.GetInvocationList();
                    for (int i = (handlers.Length - 1); i >= 0; i--)
                    {
                        PreProcessInputEventHandler handler = (PreProcessInputEventHandler)handlers[i];
                        handler(this, preProcessInputEventArgs);
                    }
                }

                if (!preProcessInputEventArgs.Canceled)
                {
                    // Pre-Notify the input.
                    //
                    // Because we use multi-cast delegates, we always have to
                    // create a new multi-cast delegate when we add or remove
                    // a handler.  This means we can just call the current
                    // multi-cast delegate instance, and it is safe to iterate
                    // over, even if we get reentered.
                    if (_preNotifyInput != null)
                    {
                        notifyInputEventArgs.Reset(item, this);

                        // Invoke the handlers in reverse order so that handlers that
                        // users add are invoked before handlers in the system.
                        Delegate[] handlers = _preNotifyInput.GetInvocationList();
                        for (int i = (handlers.Length - 1); i >= 0; i--)
                        {
                            NotifyInputEventHandler handler = (NotifyInputEventHandler)handlers[i];
                            handler(this, notifyInputEventArgs);
                        }
                    }

                    // Raise the input event being processed.
                    InputEventArgs input = item.Input;

                    // Some input events are explicitly associated with
                    // an element.  Those that are not are associated with
                    // the target of the input device for this event.
                    DependencyObject eventSource = input.Source as DependencyObject;
                    if (eventSource == null || !InputElement.IsValid(eventSource as IInputElement))
                    {
                        if (input.Device != null)
                        {
                            eventSource = input.Device.Target as DependencyObject;
                        }
                    }

                    // During synchronized input processing, event should be discarded if not listening for this input type.
                    if (_isSynchronizedInput &&
                        SynchronizedInputHelper.IsMappedEvent(input) &&
                        Array.IndexOf(SynchronizedInputEvents, input.RoutedEvent) < 0 &&
                        Array.IndexOf(PairedSynchronizedInputEvents, input.RoutedEvent) < 0)
                    {
                        if (!SynchronizedInputHelper.ShouldContinueListening(input))
                        {
                            // Discard the event
                            _synchronizedInputState = SynchronizedInputStates.Discarded;
                            SynchronizedInputHelper.RaiseAutomationEvents();
                            CancelSynchronizedInput();
                        }
                        else
                        {
                            _synchronizedInputAsyncClearOperation = Dispatcher.BeginInvoke((Action) delegate
                            {
                                // Discard the event
                                _synchronizedInputState = SynchronizedInputStates.Discarded;
                                SynchronizedInputHelper.RaiseAutomationEvents();
                                CancelSynchronizedInput();
                            },
                                                                                           DispatcherPriority.Background);
                        }
                    }
                    else
                    {
                        if (eventSource != null)
                        {
                            if (InputElement.IsUIElement(eventSource))
                            {
                                UIElement e = (UIElement)eventSource;

                                e.RaiseEvent(input, true); // Call the "trusted" flavor of RaiseEvent.
                            }
                            else if (InputElement.IsContentElement(eventSource))
                            {
                                ContentElement ce = (ContentElement)eventSource;

                                ce.RaiseEvent(input, true);// Call the "trusted" flavor of RaiseEvent.
                            }
                            else if (InputElement.IsUIElement3D(eventSource))
                            {
                                UIElement3D e3D = (UIElement3D)eventSource;

                                e3D.RaiseEvent(input, true); // Call the "trusted" flavor of RaiseEvent
                            }

                            // If synchronized input raise appropriate automation event.

                            if (_isSynchronizedInput && SynchronizedInputHelper.IsListening(_listeningElement, input))
                            {
                                if (!SynchronizedInputHelper.ShouldContinueListening(input))
                                {
                                    SynchronizedInputHelper.RaiseAutomationEvents();
                                    CancelSynchronizedInput();
                                }
                                else
                                {
                                    _synchronizedInputAsyncClearOperation = Dispatcher.BeginInvoke((Action) delegate
                                    {
                                        SynchronizedInputHelper.RaiseAutomationEvents();
                                        CancelSynchronizedInput();
                                    },
                                                                                                   DispatcherPriority.Background);
                                }
                            }
                        }
                    }

                    // Post-Notify the input.
                    //
                    // Because we use multi-cast delegates, we always have to
                    // create a new multi-cast delegate when we add or remove
                    // a handler.  This means we can just call the current
                    // multi-cast delegate instance, and it is safe to iterate
                    // over, even if we get reentered.
                    if (_postNotifyInput != null)
                    {
                        notifyInputEventArgs.Reset(item, this);

                        // Invoke the handlers in reverse order so that handlers that
                        // users add are invoked before handlers in the system.
                        Delegate[] handlers = _postNotifyInput.GetInvocationList();
                        for (int i = (handlers.Length - 1); i >= 0; i--)
                        {
                            NotifyInputEventHandler handler = (NotifyInputEventHandler)handlers[i];
                            handler(this, notifyInputEventArgs);
                        }
                    }

                    // Post-Process the input.  This could modify the staging
                    // area.
                    //
                    // Because we use multi-cast delegates, we always have to
                    // create a new multi-cast delegate when we add or remove
                    // a handler.  This means we can just call the current
                    // multi-cast delegate instance, and it is safe to iterate
                    // over, even if we get reentered.
                    if (_postProcessInput != null)
                    {
                        processInputEventArgs.Reset(item, this);

                        RaiseProcessInputEventHandlers(_postProcessInput, processInputEventArgs);

                        // PreviewInputReport --> InputReport
                        if (item.Input.RoutedEvent == InputManager.PreviewInputReportEvent)
                        {
                            if (!item.Input.Handled)
                            {
                                InputReportEventArgs previewInputReport = (InputReportEventArgs)item.Input;

                                InputReportEventArgs inputReport = new InputReportEventArgs(previewInputReport.Device, previewInputReport.Report);
                                inputReport.RoutedEvent = InputManager.InputReportEvent;
                                PushInput(inputReport, item);
                            }
                        }
                    }

                    if (input.Handled)
                    {
                        handled = true;
                    }
                }
            }

            // Store our input event args so that we can use them again, and
            // avoid having to allocate more.
            _notifyInputEventArgs     = notifyInputEventArgs;
            _processInputEventArgs    = processInputEventArgs;
            _preProcessInputEventArgs = preProcessInputEventArgs;

            // Make sure to throw away the contents of the event args so
            // we don't keep refs around to things we don't mean to.
            _notifyInputEventArgs.Reset(null, null);
            _processInputEventArgs.Reset(null, null);
            _preProcessInputEventArgs.Reset(null, null);

            return(handled);
        }
 private void InputManager_PostNotifyInput(object sender, NotifyInputEventArgs e)
 {
     if (this.IsPointerButtonEventItem(e.StagingItem))
     {
         this.handlingPointerButtonEvent = false;
     }
 }
예제 #9
0
 private void PreProcessInput( object sender, NotifyInputEventArgs e )
 {
   if( e.StagingItem.Input is KeyEventArgs )
   {
     this.UpdateKeyModifierTriggerProperties();
   }
 }
예제 #10
0
        private void PreNotifyInput(object sender, NotifyInputEventArgs e)
        {
            RawKeyboardInputReport keyboardInput = ExtractRawKeyboardInputReport(e, InputManager.PreviewInputReportEvent);

            if (keyboardInput != null)
            {
                CheckForDisconnectedFocus();

                // Activation
                //
                // MITIGATION: KEYBOARD_STATE_OUT_OF_SYNC
                //
                // It is very important that we allow multiple activate events.
                // This is how we deal with the fact that Win32 sometimes sends
                // us a WM_SETFOCUS message BEFORE it has updated it's internal
                // internal keyboard state information.  When we get the
                // WM_SETFOCUS message, we activate the keyboard with the
                // keyboard state (even though it could be wrong).  Then when
                // we get the first "real" keyboard input event, we activate
                // the keyboard again, since Win32 will have updated the
                // keyboard state correctly by then.
                //
                if ((keyboardInput.Actions & RawKeyboardActions.Activate) == RawKeyboardActions.Activate)
                {
                    //if active source is null, no need to do special-case handling
                    if (_activeSource == null)
                    {
                        // we are now active.
                        _activeSource = new SecurityCriticalDataClass <PresentationSource>(keyboardInput.InputSource);
                    }
                    else if (_activeSource.Value != keyboardInput.InputSource)
                    {
                        IKeyboardInputProvider toDeactivate = _activeSource.Value.GetInputProvider(typeof(KeyboardDevice)) as IKeyboardInputProvider;

                        // we are now active.
                        _activeSource = new SecurityCriticalDataClass <PresentationSource>(keyboardInput.InputSource);

                        if (toDeactivate != null)
                        {
                            toDeactivate.NotifyDeactivate();
                        }
                    }
                }

                // Generally, we need to check against redundant actions.
                // We never prevet the raw event from going through, but we
                // will only generate the high-level events for non-redundant
                // actions.  We store the set of non-redundant actions in
                // the dictionary of this event.

                // If the input is reporting a key down, the action is never
                // considered redundant.
                if ((keyboardInput.Actions & RawKeyboardActions.KeyDown) == RawKeyboardActions.KeyDown)
                {
                    RawKeyboardActions actions = GetNonRedundantActions(e);
                    actions |= RawKeyboardActions.KeyDown;
                    e.StagingItem.SetData(_tagNonRedundantActions, actions);

                    // Pass along the key that was pressed, and update our state.
                    Key key = KeyInterop.KeyFromVirtualKey(keyboardInput.VirtualKey);
                    e.StagingItem.SetData(_tagKey, key);
                    e.StagingItem.SetData(_tagScanCode, new ScanCode(keyboardInput.ScanCode, keyboardInput.IsExtendedKey));

                    // Tell the InputManager that the MostRecentDevice is us.
                    if (_inputManager != null)
                    {
                        _inputManager.Value.MostRecentInputDevice = this;
                    }
                }

                // We are missing detection for redundant ups
                if ((keyboardInput.Actions & RawKeyboardActions.KeyUp) == RawKeyboardActions.KeyUp)
                {
                    RawKeyboardActions actions = GetNonRedundantActions(e);
                    actions |= RawKeyboardActions.KeyUp;
                    e.StagingItem.SetData(_tagNonRedundantActions, actions);

                    // Pass along the key that was pressed, and update our state.
                    Key key = KeyInterop.KeyFromVirtualKey(keyboardInput.VirtualKey);
                    e.StagingItem.SetData(_tagKey, key);
                    e.StagingItem.SetData(_tagScanCode, new ScanCode(keyboardInput.ScanCode, keyboardInput.IsExtendedKey));

                    // Tell the InputManager that the MostRecentDevice is us.
                    if (_inputManager != null)
                    {
                        _inputManager.Value.MostRecentInputDevice = this;
                    }
                }
            }

            // On KeyDown, we might need to set the Repeat flag

            if (e.StagingItem.Input.RoutedEvent == Keyboard.PreviewKeyDownEvent)
            {
                CheckForDisconnectedFocus();

                KeyEventArgs args = (KeyEventArgs)e.StagingItem.Input;

                // Is this the same as the previous key?  (Look at the real key, e.g. TextManager
                // might have changed args.Key it to Key.TextInput.)

                if (_previousKey == args.RealKey)
                {
                    // Yes, this is a repeat (we got the keydown for it twice, with no KeyUp in between)
                    args.SetRepeat(true);
                }

                // Otherwise, keep this key to check against next time.
                else
                {
                    _previousKey = args.RealKey;
                    args.SetRepeat(false);
                }
            }

            // On KeyUp, we clear Repeat flag
            else if (e.StagingItem.Input.RoutedEvent == Keyboard.PreviewKeyUpEvent)
            {
                CheckForDisconnectedFocus();

                KeyEventArgs args = (KeyEventArgs)e.StagingItem.Input;
                args.SetRepeat(false);

                // Clear _previousKey, so that down/up/down/up doesn't look like a repeat
                _previousKey = Key.None;
            }
        }
예제 #11
0
        private void PlayOrPause4SpaceKey(object sender, NotifyInputEventArgs e)
        {
            if (this.OwnedWindows.Count != 0)
            {
                return;
            }
            if (e.StagingItem.Input.RoutedEvent != Keyboard.KeyDownEvent)
                return;

            var args = e.StagingItem.Input as KeyEventArgs;
            if (args == null || args.Key != Key.Space)
            {
                return;
            }
            args.Handled = true;
            PlayOrPauseOrOpen();
        }
예제 #12
0
        private void PreNotifyInput(object sender, NotifyInputEventArgs e)
        {
            if ( e.StagingItem.Input.RoutedEvent == InputManager.PreviewInputReportEvent )
            {
                InputReportEventArgs inputReportEventArgs = e.StagingItem.Input as InputReportEventArgs;

                if (!inputReportEventArgs.Handled && inputReportEventArgs.Report.Type == InputType.Mouse)
                {
                    RawMouseInputReport rawMouseInputReport = (RawMouseInputReport) inputReportEventArgs.Report;

                    // Generally, we need to check against redundant actions.
                    // We never prevent the raw event from going through, but we
                    // will only generate the high-level events for non-redundant
                    // actions.  We store the set of non-redundant actions in
                    // the dictionary of this event.

                    // Get the current Non-Redundant Actions for this event and
                    // make a copy.  We will compare the original value against the copy
                    // at the end of this function and write it back in if changed.

                    RawMouseActions actions = GetNonRedundantActions(e);
                    RawMouseActions originalActions = actions;

                    _stylusDevice = GetStylusDevice(e.StagingItem);

                    // Normally we only process mouse input that is from our
                    // active presentation source.  The only exception to this is
                    // the activate report, which is how we change the visual
                    // manager that is active.
                    if ((rawMouseInputReport.Actions & RawMouseActions.Activate) == RawMouseActions.Activate)
                    {
                        // System.Console.WriteLine("Initializing the mouse state.");

                        actions |= RawMouseActions.Activate;

                        _positionRelativeToOver.X = 0;
                        _positionRelativeToOver.Y = 0;

                        _lastPosition.X = rawMouseInputReport.X;
                        _lastPosition.Y = rawMouseInputReport.Y;
                        _forceUpdateLastPosition = true;

                        _stylusDevice = inputReportEventArgs.Device as StylusDevice;

                        // if the existing source is null, no need to do any special-case handling
                        if (_inputSource == null)
                        {
                            _inputSource = new SecurityCriticalDataClass<PresentationSource>(rawMouseInputReport.InputSource);
                        }
                        // if the new source is the same as the old source, don't bother doing anything
                        else if (_inputSource.Value != rawMouseInputReport.InputSource)
                        {
                            IMouseInputProvider toDeactivate = _inputSource.Value.GetInputProvider(typeof(MouseDevice)) as IMouseInputProvider;

                            // All mouse information is now restricted to this presentation source.
                            _inputSource = new SecurityCriticalDataClass<PresentationSource>(rawMouseInputReport.InputSource);

                            if (toDeactivate != null)
                            {
                                toDeactivate.NotifyDeactivate();
                            }
                        }
                    }

                    // Only process mouse input that is from our active presentation source.
                    if ((_inputSource != null) && (rawMouseInputReport.InputSource == _inputSource.Value))
                    {
                        // If the input is reporting mouse deactivation, we need
                        // to break any capture we may have.  Note that we only do
                        // this if the presentation source associated with this event
                        // is the same presentation source we are already over.
                        if ((rawMouseInputReport.Actions & RawMouseActions.Deactivate) == RawMouseActions.Deactivate)
                        {
                            // Console.WriteLine("RawMouseActions.Deactivate");
                            Debug.Assert(_mouseOver == null, "_mouseOver should be null because we have called ChangeMouseOver(null) already.");
                            _inputSource = null;

                            ChangeMouseCapture(null, null, CaptureMode.None, e.StagingItem.Input.Timestamp);
                        }

                        if ((rawMouseInputReport.Actions & RawMouseActions.CancelCapture) == RawMouseActions.CancelCapture)
                        {
                            // Console.WriteLine("RawMouseActions.CancelCapture");
                            ChangeMouseCapture(null, null, CaptureMode.None, e.StagingItem.Input.Timestamp);
                        }

                        // If the input is reporting mouse movement, only update the
                        // set of non-redundant actions if the position changed.
                        if ((rawMouseInputReport.Actions & RawMouseActions.AbsoluteMove) == RawMouseActions.AbsoluteMove) // 
                        {
                            //Console.WriteLine("RawMouseActions.AbsoluteMove: X=" + rawMouseInputReport.X + " Y=" + rawMouseInputReport.Y );

                            // Translate the mouse coordinates to both root relative and "mouseOver" relate.
                            // - Note: "mouseOver" in this case is the element the mouse "was" over before this move.
                            bool mouseOverAvailable = false;
                            Point ptClient = new Point(rawMouseInputReport.X, rawMouseInputReport.Y);
                            Point ptRoot = (Point) e.StagingItem.GetData(_tagRootPoint);
                            Point ptRelativeToOver = InputElement.TranslatePoint(ptRoot, rawMouseInputReport.InputSource.RootVisual, (DependencyObject)_mouseOver, out mouseOverAvailable);

                            IInputElement mouseOver = _mouseOver; // assume mouse is still over whatever it was before
                            IInputElement rawMouseOver = (_rawMouseOver != null) ? (IInputElement)_rawMouseOver.Target : null;
                            bool isPhysicallyOver = _isPhysicallyOver;
                            bool isGlobalChange = ArePointsClose(ptClient, _lastPosition) == false;  // determine if the mouse actually physically moved

                            // Invoke Hit Test logic to determine what element the mouse will be over AFTER the move is processed.
                            // - Only do this if:
                            //      - The mouse physcially moved (isGlobalChange)
                            //      - We are simulating a mouse move (_isSynchronize)
                            //      - mouseOver isn't availabe (!mouseOverAvailable)  Could be caused by a degenerate transform.
                            // - This is to mitigate the redundant AbsoluteMove notifications associated with QueryCursor
                            if (isGlobalChange || rawMouseInputReport._isSynchronize || !mouseOverAvailable)
                            {
                                isPhysicallyOver = true;  // assume mouse is physical over element, we'll set it false if it's due to capture

                                switch (_captureMode)
                                {
                                    // In this case there is no capture, so a simple hit test will determine which element becomes "mouseOver"
                                    case CaptureMode.None:
                                        {
                                            if (rawMouseInputReport._isSynchronize)
                                            {
                                                GlobalHitTest(true, ptClient, _inputSource.Value, out mouseOver, out rawMouseOver);
                                            }
                                            else
                                            {
                                                LocalHitTest(true, ptClient, _inputSource.Value, out mouseOver, out rawMouseOver);
                                            }

                                            if (mouseOver == rawMouseOver)
                                            {
                                                // Since they are the same, there is no reason to process rawMouseOver
                                                rawMouseOver = null;
                                            }

                                            // We understand UIElements and ContentElements.
                                            // If we are over something else (like a raw visual)
                                            // find the containing element.
                                            if (!InputElement.IsValid(mouseOver))
                                                mouseOver = InputElement.GetContainingInputElement(mouseOver as DependencyObject);
                                            if ((rawMouseOver != null) && !InputElement.IsValid(rawMouseOver))
                                                rawMouseOver = InputElement.GetContainingInputElement(rawMouseOver as DependencyObject);
                                        }
                                        break;

                                    // In this case, capture is to a specific element, so it will ALWAYS become "mouseOver"
                                    // - however, we do a hit test to see if the mouse is actually physically over the element,
                                    // - if it is not, we toggle isPhysicallyOver
                                    case CaptureMode.Element:
                                        if (rawMouseInputReport._isSynchronize)
                                        {
                                            mouseOver = GlobalHitTest(true, ptClient, _inputSource.Value);
                                        }
                                        else
                                        {
                                            mouseOver = LocalHitTest(true, ptClient, _inputSource.Value);
                                        }

                                        // There is no reason to process rawMouseOver when
                                        // the element should always be the one with mouse capture.
                                        rawMouseOver = null;

                                        if (mouseOver != _mouseCapture)
                                        {
                                            // Always consider the mouse over the capture point.
                                            mouseOver = _mouseCapture;
                                            isPhysicallyOver = false;
                                        }
                                        break;

                                    // In this case, capture is set to an entire subtree.  We use simple hit testing to determine
                                    // which, if any element in the subtree it is over, and set "mouseOver to that element
                                    // If it is not over any specific subtree element, "mouseOver" is set to the root of the subtree.
                                    // - Note: a subtree can span multiple HWNDs
                                    case CaptureMode.SubTree:
                                        {
                                            IInputElement mouseCapture = InputElement.GetContainingInputElement(_mouseCapture as DependencyObject);
                                            if (mouseCapture != null)
                                            {
                                                // We need to re-hit-test to get the "real" UIElement we are over.
                                                // This allows us to have our capture-to-subtree span multiple windows.

                                                // GlobalHitTest always returns an IInputElement, so we are sure to have one.
                                                GlobalHitTest(true, ptClient, _inputSource.Value, out mouseOver, out rawMouseOver);
                                            }

                                            if (mouseOver != null && !InputElement.IsValid(mouseOver) )
                                                mouseOver = InputElement.GetContainingInputElement(mouseOver as DependencyObject);

                                            // Make sure that the element we hit is acutally underneath
                                            // our captured element.  Because we did a global hit test, we
                                            // could have hit an element in a completely different window.
                                            //
                                            // Note that we support the child being in a completely different window.
                                            // So we use the GetUIParent method instead of just looking at
                                            // visual/content parents.
                                            if (mouseOver != null)
                                            {
                                                IInputElement ieTest = mouseOver;
                                                UIElement eTest = null;
                                                ContentElement ceTest = null;
                                                UIElement3D e3DTest = null;

                                                while (ieTest != null && ieTest != mouseCapture)
                                                {
                                                    eTest = ieTest as UIElement;

                                                    if (eTest != null)
                                                    {
                                                        ieTest = InputElement.GetContainingInputElement(eTest.GetUIParent(true));
                                                    }
                                                    else
                                                    {
                                                        ceTest = ieTest as ContentElement; 

                                                        if (ceTest != null)
                                                        {
                                                            ieTest = InputElement.GetContainingInputElement(ceTest.GetUIParent(true));
                                                        }
                                                        else
                                                        {
                                                            e3DTest = ieTest as UIElement3D; // Should never fail.

                                                            ieTest = InputElement.GetContainingInputElement(e3DTest.GetUIParent(true));
                                                        }                                                        
                                                    }
                                                }

                                                // If we missed the capture point, we didn't hit anything.
                                                if (ieTest != mouseCapture)
                                                {
                                                    mouseOver = _mouseCapture;
                                                    isPhysicallyOver = false;

                                                    // Since they are the same, there is no reason to process rawMouseOver
                                                    rawMouseOver = null;
                                                }
                                            }
                                            else
                                            {
                                                // We didn't hit anything.  Consider the mouse over the capture point.
                                                mouseOver = _mouseCapture;
                                                isPhysicallyOver = false;

                                                // Since they are the same, there is no reason to process rawMouseOver
                                                rawMouseOver = null;
                                            }

                                            if (rawMouseOver != null)
                                            {
                                                if (mouseOver == rawMouseOver)
                                                {
                                                    // Since they are the same, there is no reason to process rawMouseOver
                                                    rawMouseOver = null;
                                                }
                                                else if (!InputElement.IsValid(rawMouseOver))
                                                {
                                                    rawMouseOver = InputElement.GetContainingInputElement(rawMouseOver as DependencyObject);
                                                }
                                            }
                                        }
                                        break;
                                }
                            }

                            _isPhysicallyOver = mouseOver == null ? false : isPhysicallyOver;

                            // Now that we've determine what element the mouse is over now (mouseOver)
                            // - we need to check if it's changed

                            bool isMouseOverChange = mouseOver != _mouseOver;

                            // If mouseOver changed, we need to recalculate the ptRelativeToOver, because "Over" changed!

                            if (isMouseOverChange)
                            {
                                ptRelativeToOver = InputElement.TranslatePoint(ptRoot, rawMouseInputReport.InputSource.RootVisual, (DependencyObject)mouseOver);
                            }

                            //Console.WriteLine("RawMouseActions.AbsoluteMove: mouse moved over " + (isMouseOverChange ? "same" : "different") + " element.  old=" + _mouseOver + " new=" + mouseOver);
                            //Console.WriteLine("RawMouseActions.AbsoluteMove: capture=" + _mouseCapture);

                            // Check to see if the local mouse position changed.  This can be
                            // caused by a change to the geometry of the
                            // element we are over or a change in which element
                            // we are over.
                            //
                            bool isLocalChange = isMouseOverChange || ArePointsClose(ptRelativeToOver, _positionRelativeToOver) == false;

                            // Console.WriteLine("RawMouseActions.AbsoluteMove: isGlobalChange=" + isGlobalChange + " isLocalChange=" + isLocalChange);

                            // We only update our cached position (_lastPosition & _positionRelativeToOver )
                            // if we have moved "far enough" allowing small incrementaly moves to accumulate

                            if (isGlobalChange || isLocalChange || _forceUpdateLastPosition)
                            {
                                _forceUpdateLastPosition = false;

                                _lastPosition = ptClient;
                                _positionRelativeToOver = ptRelativeToOver;

                                if (isMouseOverChange)
                                {
                                    ChangeMouseOver(mouseOver, e.StagingItem.Input.Timestamp);
                                }

                                if ((_rawMouseOver == null) && (rawMouseOver != null))
                                {
                                    _rawMouseOver = new WeakReference(rawMouseOver);
                                }
                                else if (_rawMouseOver != null)
                                {
                                    _rawMouseOver.Target = rawMouseOver;
                                }

                                // Console.WriteLine("RawMouseActions.AbsoluteMove: ptRoot=" + ptRoot);

                                actions |= RawMouseActions.AbsoluteMove; // 

                                // In most cases the sequence of messages received from the system are HitTest, SetCursor & MouseMove.
                                // The SetCursor message in this case will be traslated into an Avalon MouseMove & QueryCursor.
                                // The MouseMove message to follow is redundant and is thrown away.
                                // But imagine a case where Capture is taken. Here the system produces only two messages HitTest & MouseMove.
                                // Hence we translate the MouseMove into an Avalon MouseMove & QueryCursor.
                                // Logically MouseMove and QueryCursor go as a pair.
                                actions |= RawMouseActions.QueryCursor;
                            }
                        }

                        // Mouse wheel rotate events are never considered redundant.
                        if ((rawMouseInputReport.Actions & RawMouseActions.VerticalWheelRotate) == RawMouseActions.VerticalWheelRotate)
                        {
                            // Console.WriteLine("RawMouseActions.VerticalWheelRotate");

                            actions |= RawMouseActions.VerticalWheelRotate;

                            // Tell the InputManager that the MostRecentDevice is us.
                            _inputManager.Value.MostRecentInputDevice = this;
                        }

                        // Mouse query cursor events are never considered redundant.
                        if ((rawMouseInputReport.Actions & RawMouseActions.QueryCursor) == RawMouseActions.QueryCursor)
                        {
                            // Console.WriteLine("RawMouseActions.QueryCursor");

                            actions |= RawMouseActions.QueryCursor;
                        }

                        RawMouseActions[] ButtonPressActions =
                        {
                            RawMouseActions.Button1Press,
                            RawMouseActions.Button2Press,
                            RawMouseActions.Button3Press,
                            RawMouseActions.Button4Press,
                            RawMouseActions.Button5Press
                        };

                        RawMouseActions[] ButtonReleaseActions =
                        {
                            RawMouseActions.Button1Release,
                            RawMouseActions.Button2Release,
                            RawMouseActions.Button3Release,
                            RawMouseActions.Button4Release,
                            RawMouseActions.Button5Release
                        };

                        for (int iButton = 0; iButton < 5; iButton++)
                        {
                            if ((rawMouseInputReport.Actions & ButtonPressActions[iButton]) == ButtonPressActions[iButton])
                            {
                                actions |= ButtonPressActions[iButton];

                                // Tell the InputManager that the MostRecentDevice is us.
                                _inputManager.Value.MostRecentInputDevice = this;
                            }

                            if ((rawMouseInputReport.Actions & ButtonReleaseActions[iButton]) == ButtonReleaseActions[iButton])
                            {
                                actions |= ButtonReleaseActions[iButton];

                                // Tell the InputManager that the MostRecentDevice is us.
                                _inputManager.Value.MostRecentInputDevice = this;
                            }
                        }
                    }

                    if (actions != originalActions)
                    {
                        e.StagingItem.SetData(_tagNonRedundantActions, actions);
                    }
                }
            }
            else
            {
                // All mouse event processing should only happen if we still have an active input source.

                if (_inputSource != null)
                {
                    // During the PreviewMouseDown event, we update the click count, if there are
                    // multiple "quick" clicks in approximately the "same" location (as defined
                    // by the hosting environment, aka the registry).
                    if (e.StagingItem.Input.RoutedEvent == Mouse.PreviewMouseDownEvent)
                    {
                        MouseButtonEventArgs mouseButtonArgs = e.StagingItem.Input as MouseButtonEventArgs;
                        StylusDevice stylusDevice = GetStylusDevice(e.StagingItem);
                        Point ptClient = GetClientPosition();

                        _clickCount = CalculateClickCount(mouseButtonArgs.ChangedButton, mouseButtonArgs.Timestamp, stylusDevice, ptClient);
                        if (_clickCount == 1)
                        {
                            // we need to reset out data, since this is the start of the click count process...
                            _lastClick = ptClient;
                            _lastButton = mouseButtonArgs.ChangedButton;
                            _lastClickTime = mouseButtonArgs.Timestamp;
                        }
                        // Put the updated count into the args.
                        mouseButtonArgs.ClickCount = _clickCount;
                    }
                }
            }
        }
예제 #13
0
		void inputManager_PreNotifyInput(object sender, NotifyInputEventArgs e)
		{
			if (e.StagingItem.Input.RoutedEvent == PreviewRawInputEvent)
			{
				RawMultitouchReport report = e.StagingItem.Input as RawMultitouchReport;
				if (report != null && !report.Handled)
				{
					report.Context.OverElement = GetTargetElement(report.Context.Contact.Position, report.Context.Root, report);

					Contact contact;
					if (!report.CleanUp)
					{
						if (ContactsManager.ExistingContacts.TryGetValue(report.Context.Contact.Id, out contact))
							contact.InputArgs = report;
						else
						{
							contact = new Contact(report);
							ContactsManager.ExistingContacts[report.Context.Contact.Id] = contact;
						}
					}
					else
					{
						contact = ContactsManager.ExistingContacts[report.Context.Contact.Id];
						contact.InputArgs = report;
						report.Handled = true;
					}

					UIElementsList mergedList;

					report.Context.ElementsList = BuildElementsList(report, report.Context.OverElement, report.Context.ElementsList, out mergedList);
					if(mergedList != null)
						RaiseEnterLeave(contact, mergedList);

					if(report.CleanUp)
					{
						if (report.Captured != null)
							contact.Capture(null);
						ContactsManager.ExistingContacts.Remove(contact.Id);
					}
				}
			}
			Debug.Assert(e.StagingItem.Input.RoutedEvent != null, "routed event null");
		}
예제 #14
0
		public bool ProcessInput (InputEventArgs input)
		{
			StagingAreaInputItem stagingItem = new StagingAreaInputItem (input);

			PreProcessInputEventArgs preProcessArgs = new PreProcessInputEventArgs(this, stagingItem);
			if (PreProcessInput != null)
				PreProcessInput (this, preProcessArgs);

			NotifyInputEventArgs notifyArgs = new NotifyInputEventArgs(this, stagingItem);
			if (PreNotifyInput != null)
				PreNotifyInput (this, notifyArgs);

#if notyet
			if (!preProcessArgs.Canceled)
				/* XXX route the event */;
#endif

			if (PostNotifyInput != null)
				PostNotifyInput (this, notifyArgs);

			if (PostProcessInput != null) {
				ProcessInputEventArgs processArgs = new ProcessInputEventArgs (this, stagingItem);
				PostProcessInput (this, processArgs);
			}

			return true;
		}
예제 #15
0
        private void PreNotifyInput(object sender, NotifyInputEventArgs e)
        {
            if(e.StagingItem.Input.RoutedEvent == InputManager.PreviewInputReportEvent)
            { 
                InputReportEventArgs inputReportEventArgs = e.StagingItem.Input as InputReportEventArgs;
 
                if(!inputReportEventArgs.Handled && inputReportEventArgs.Report.Type == InputType.Stylus) 
                {
                    RawStylusInputReport rawStylusInputReport = (RawStylusInputReport) inputReportEventArgs.Report; 
                    StylusDevice stylusDevice = rawStylusInputReport.StylusDevice;

                    if (stylusDevice != null)
                    { 
                        // update stylus device state (unless this is exclusively system gesture or
                        // in-range/out-of-range event - which don't carry much info) 
                        switch (rawStylusInputReport.Actions) 
                        {
                            case RawStylusActions.SystemGesture: 
                                stylusDevice.UpdateStateForSystemGesture(
                                    (RawStylusSystemGestureInputReport)rawStylusInputReport);
                                break;
                            case RawStylusActions.OutOfRange: 
                                _lastInRangeTime = Environment.TickCount;
                                stylusDevice.UpdateInRange(false, rawStylusInputReport.PenContext); 
                                UpdateIsStylusInRange(false); 
                                break;
                            case RawStylusActions.InRange: 
                                _lastInRangeTime = Environment.TickCount;
                                stylusDevice.UpdateInRange(true, rawStylusInputReport.PenContext);
                                stylusDevice.UpdateState(rawStylusInputReport);
                                UpdateIsStylusInRange(true); 
                                _lastRawMouseAction = RawMouseActions.None; // make sure we promote a mouse move on next event.
                                break; 
                            default: // InAirMove, Down, Move, Up go through here. 
                                stylusDevice.UpdateState(rawStylusInputReport);
                                break; 
                        }

                        // Can only update Over state if not in a DragDrop operation!!
                        if (!_inDragDrop && !rawStylusInputReport.PenContext.Contexts.IsWindowDisabled && !stylusDevice.IgnoreStroke) 
                        {
                            Point position = stylusDevice.GetRawPosition(null); 
                            position = DeviceUnitsFromMeasureUnits(position); // change back to device coords. 
                            IInputElement target = stylusDevice.FindTarget(stylusDevice.CriticalActiveSource, position);
                            SelectStylusDevice(stylusDevice, target, true); 
                        }
                        else
                        {
                            SelectStylusDevice(stylusDevice, null, false); // don't update over. 
                        }
 
                        // If this is a stylus down and we don't have a valid target then the stylus went down 
                        // on the wrong window (a transparent window handling bug in wisptis).  In this case
                        // we want to ignore all stylus input until after the next stylus up. 
                        if (rawStylusInputReport.Actions == RawStylusActions.Down && stylusDevice.Target == null)
                        {
                            stylusDevice.IgnoreStroke = true;
                        } 

                        // Tell the InputManager that the MostRecentDevice is us. 
                        _inputManager.Value.MostRecentInputDevice = stylusDevice; 

                        // Verify that we sent the real time stylus events to the proper plugincollection. 
                        VerifyStylusPlugInCollectionTarget(rawStylusInputReport);
                    }
                }
            } 

            // During the PreviewStylusDown event, we update the tap count, if there are 
            // multiple "quick" taps in approximately the "same" location (as defined 
            // by the hosting environment, aka the registry).
            if(e.StagingItem.Input.RoutedEvent == Stylus.PreviewStylusDownEvent) 
            {
                StylusEventArgs stylusDownEventArgs = e.StagingItem.Input as StylusDownEventArgs;

                StylusDevice stylusDevice = stylusDownEventArgs.StylusDevice; 

                if (stylusDevice != null) 
                { 
                    Point ptClient = stylusDevice.GetRawPosition(null);
 
                    // determine barrel state...
                    bool bBarrelPressed = false;
                    int barrelPos =
                        stylusDevice.TabletDevice.StylusPointDescription.GetButtonBitPosition(StylusPointProperties.BarrelButton); 
                    if (barrelPos != -1
                        && stylusDevice.StylusButtons[barrelPos].StylusButtonState == StylusButtonState.Down) 
                    { 
                        bBarrelPressed = true;
                    } 

                    Point pPixelPoint = DeviceUnitsFromMeasureUnits(ptClient);
                    Point pLastPixelPoint = DeviceUnitsFromMeasureUnits(stylusDevice.LastTapPoint);
 
                    // How long since the last click? (deals with tickcount wrapping too)
                    //  Here's some info on how this works... 
                    //      int.MaxValue - int.MinValue = -1 (subtracting any negative # from MaxValue keeps this negative) 
                    //      int.MinValue - int.MaxValue = 1 (subtracting any positive # from MinValue keeps this positive)
                    //  So as the values get farther apart from MaxInt and MinInt the difference grows which is what we want. 
                    //  We use Abs to ensure if we get older time coming through here (not expected) we'll do better
                    //  at filtering it out if delta is greater than the double tap time.  We should always see
                    //  MinInt - MaxInt which will produce a positive number when wrapping happens.
                    int  timeSpan = Math.Abs(unchecked(stylusDownEventArgs.Timestamp - stylusDevice.LastTapTime)); 
                    // Is the delta coordinates of this tap close enough to the last tap?
 
                    Size doubleTapSize = stylusDevice.TabletDevice.DoubleTapSize; 
                    bool isSameSpot = (Math.Abs(pPixelPoint.X - pLastPixelPoint.X) < doubleTapSize.Width) &&
                                        (Math.Abs(pPixelPoint.Y - pLastPixelPoint.Y) < doubleTapSize.Height); 

                    // Now check everything to see if this is a multi-click.
                    if (timeSpan < _doubleTapDeltaTime
                        && isSameSpot 
                        && (bBarrelPressed == stylusDevice.LastTapBarrelDown) )
                    { 
                        // Yes, increment the count 
                        stylusDevice.TapCount++;
                    } 
                    else
                    {
                        // No, not a multi-click, reset everything.
                        stylusDevice.TapCount = 1; 
                        stylusDevice.LastTapPoint  = new Point(ptClient.X, ptClient.Y);
                        stylusDevice.LastTapTime = stylusDownEventArgs.Timestamp; 
                        stylusDevice.LastTapBarrelDown = bBarrelPressed; 
                    }
 
                    // Make sure to update the mouse location on stylus down.
                    ProcessMouseMove(stylusDevice, stylusDownEventArgs.Timestamp, false);
                }
            } 
        }