コード例 #1
0
 // When called, InputManager will get into synchronized input processing mode.
 internal static bool StartListeningSynchronizedInput(DependencyObject d, SynchronizedInputType inputType)
 {
     lock (_synchronizedInputLock)
     {
         if (_isSynchronizedInput)
         {
             return(false);
         }
         else
         {
             _isSynchronizedInput           = true;
             _synchronizedInputState        = SynchronizedInputStates.NoOpportunity;
             _listeningElement              = d;
             _synchronizedInputType         = inputType;
             _synchronizedInputEvents       = SynchronizedInputHelper.MapInputTypeToRoutedEvents(inputType);
             _pairedSynchronizedInputEvents = SynchronizedInputHelper.MapInputTypeToRoutedEvents(SynchronizedInputHelper.GetPairedInputType(inputType));
             return(true);
         }
     }
 }
コード例 #2
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);
        }