/// <summary>
        ///     Pushes an input event onto the top of the staging area.
        /// </summary>
        /// <param name="input">
        ///     The input event to place on the staging area.  This may not
        ///     be null, and may not already exist in the staging area.
        /// </param>
        /// <param name="promote">
        ///     An existing staging area item to promote the state from.
        /// </param>
        /// <returns>
        ///     The staging area input item that wraps the specified input.
        /// </returns>
        public StagingAreaInputItem PushInput(InputEventArgs input,
                                              StagingAreaInputItem promote) // Note: this should be a bool, and always use the InputItem available on these args.
        {
            StagingAreaInputItem item = new StagingAreaInputItem(input, promote);

            InputManager.CurrentInputManager._currentStagingStack.Push(item);
            
            return item;
        }
        internal StagingAreaInputItem(InputEventArgs input, StagingAreaInputItem promote)
        {
            Input = input;

            if (promote != null && promote._table != null)
            {
                // REFACTOR -- need a hashtable!

                _table = (Hashtable)promote._table.Clone();
            }
        }
Esempio n. 3
0
        internal StagingAreaInputItem(bool isMarker, InputEventArgs input, StagingAreaInputItem promote)
        {
            IsMarker = isMarker;
            Input = input;

            if (promote != null && promote._keys != null)
            {
                // REFACTOR -- need a hashtable!

                _keys = (ArrayList)promote._keys.Clone();
                _values = (ArrayList)promote._values.Clone();
            }
        }
Esempio n. 4
0
        /// <summary>
        ///     Synchronously processes the specified input.
        /// </summary>
        /// <remarks>
        ///     The specified input is processed by all of the filters and
        ///     monitors, and is finally dispatched to the appropriate
        ///     element as an input event.
        /// </remarks>
        /// <returns>
        ///     Whether or not any event generated as a consequence of this
        ///     event was handled.
        /// </returns>
        public bool ProcessInput(InputEventArgs input)
        {
            VerifyAccess();

            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            // Push a marker indicating the portion of the staging area
            // that needs to be processed.
            Stack stk = new Stack();

            // Push the input to be processed onto the staging area.
            stk.Push(new StagingAreaInputItem(input, null));

            _stagingArea.Enqueue(stk);

            // Post a work item to continue processing the staging area
            // in case someone pushes a dispatcher frame in the middle
            // of input processing.
            DispatcherFrame frame = Dispatcher.CurrentFrame;
            if (frame != null)
            {
                if (!_frameStagingArea.Contains(frame))
                {
                    _frameStagingArea.Add(frame);
                    Dispatcher.BeginInvoke(_continueProcessingStagingAreaCallback, frame);
                }
            }

            return true;
        }
Esempio n. 5
0
        /// <summary>
        ///     Synchronously processes the specified input.
        /// </summary>
        /// <remarks>
        ///     The specified input is processed by all of the filters and
        ///     monitors, and is finally dispatched to the appropriate
        ///     element as an input event.
        /// </remarks>
        /// <returns>
        ///     Whether or not any event generated as a consequence of this
        ///     event was handled.
        /// </returns>
        public bool ProcessInput(InputEventArgs input)
        {
            VerifyAccess();

            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            // Push a marker indicating the portion of the staging area
            // that needs to be processed.
            _stagingArea.Push(new StagingAreaInputItem(true, null, null));

            // Push the input to be processed onto the staging area.
            _stagingArea.Push(new StagingAreaInputItem(false, input, null));

            // Post a work item to continue processing the staging area
            // in case someone pushes a dispatcher frame in the middle
            // of input processing.
            if (!_continueProcessingStagingArea)
            {
                Dispatcher.BeginInvoke(_continueProcessingStagingAreaCallback, true);
                _continueProcessingStagingArea = true;
            }

            // Now drain the staging area up to the marker we pushed.
            bool handled = (bool)ProcessStagingArea(false);
            return handled;
        }
        private object ProcessStagingArea(object postContinue)
        {
            bool handled = false;

            // NOTE -- avalon caches the XXXEventArgs.  In our system, the costs are different,
            // so it is probably cheaper for us to just create them, since everything gets created
            // on the heap anyways, and IL is expensive.  we should reconsider this if
            // its a performance impact.

            // 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.

            _continueProcessingStagingArea = true;

            try
            {
                while (_stagingArea.Count > 0)
                {
                    _currentStagingStack = _stagingArea.Dequeue() as Stack;

                    do
                    {
                        StagingAreaInputItem item = (StagingAreaInputItem)_currentStagingStack.Pop();

                        // Pre-Process the input.  This could modify the staging
                        // area, and it could cancel the processing of this
                        // input event.
                        //

                        bool fCanceled = false;

                        int devType = (int)item.Input._inputDevice.DeviceType;

                        if (InputDeviceEvents[devType]._preProcessInput != null)
                        {
                            PreProcessInputEventArgs preProcessInputEventArgs;
                            InputDeviceEvents[devType]._preProcessInput(this, preProcessInputEventArgs = new PreProcessInputEventArgs(item));

                            fCanceled = preProcessInputEventArgs._canceled;
                        }

                        if (!fCanceled)
                        {
                            // Pre-Notify the input.
                            //
                            if (InputDeviceEvents[devType]._preNotifyInput != null)
                            {
                                InputDeviceEvents[devType]._preNotifyInput(this, new NotifyInputEventArgs(item));
                            }

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

                            // Some input events are explicitly associated with
                            // an element.  Those that are not instead are associated with
                            // the target of the input device for this event.
                            UIElement eventSource = input._source as UIElement;

                            if (eventSource == null && input._inputDevice != null)
                            {
                                eventSource = input._inputDevice.Target;
                            }

                            if (eventSource != null)
                            {
                                eventSource.RaiseEvent(input);
                            }

                            // Post-Notify the input.
                            //
                            if (InputDeviceEvents[devType]._postNotifyInput != null)
                            {
                                InputDeviceEvents[devType]._postNotifyInput(this, new NotifyInputEventArgs(item));
                            }

                            // Post-Process the input.  This could modify the staging
                            // area.
                            if (InputDeviceEvents[devType]._postProcessInput != null)
                            {
                                InputDeviceEvents[devType]._postProcessInput(this, new ProcessInputEventArgs(item));
                            }

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

                                    _currentStagingStack.Push(new StagingAreaInputItem(inputReport, item));
                                }
                            }

                            if (input.Handled)
                            {
                                handled = true;
                            }
                        }
                    }while(_currentStagingStack.Count > 0);
                }
            }
            finally
            {
                _continueProcessingStagingArea = false;

                // It is possible that we can be re-entered by a nested
                // dispatcher frame.  Continue processing the staging
                // area if we need to.
                if (_stagingArea.Count > 0)
                {
                    _continueProcessingStagingArea = true;
                    // Before we actually start to drain the staging area, we need
                    // to post a work item to process more input.  This enables us
                    // to process more input if we enter a nested pump.
                    Dispatcher.BeginInvoke(_continueProcessingStagingAreaCallback, true);
                }
            }

            return(handled);
        }
Esempio n. 7
0
        private object ProcessStagingArea(object postContinue)
        {
            bool handled = false;

            // NOTE -- avalon caches the XXXEventArgs.  In our system, the costs are different,
            // so it is probably cheaper for us to just create them, since everything gets created
            // on the heap anyways, and IL is expensive.  we should reconsider this if
            // its a performance impact.

            // 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.

            while (_stagingArea.Count > 0)
            {
                StagingAreaInputItem item = (StagingAreaInputItem)_stagingArea.Pop();

                // 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.
                // 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 you 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.
                //

                bool fCanceled = false;

                int devType = (int)item.Input._inputDevice.DeviceType;

                if (InputDeviceEvents[devType]._preProcessInput != null)
                {
                    PreProcessInputEventArgs preProcessInputEventArgs;
                    InputDeviceEvents[devType]._preProcessInput(this, preProcessInputEventArgs = new PreProcessInputEventArgs(item));

                    fCanceled = preProcessInputEventArgs._canceled;
                }

                if (!fCanceled)
                {
                    // Pre-Notify the input.
                    //
                    if (InputDeviceEvents[devType]._preNotifyInput != null)
                    {
                        InputDeviceEvents[devType]._preNotifyInput(this, new NotifyInputEventArgs(item));
                    }

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

                    // Some input events are explicitly associated with
                    // an element.  Those that are not instead are associated with
                    // the target of the input device for this event.
                    UIElement eventSource = input._source as UIElement;

                    if (eventSource == null && input._inputDevice != null)
                    {
                        eventSource = input._inputDevice.Target;
                    }

                    if (eventSource != null)
                    {
                        eventSource.RaiseEvent(input);
                    }

                    // Post-Notify the input.
                    //
                    if (InputDeviceEvents[devType]._postNotifyInput != null)
                    {
                        InputDeviceEvents[devType]._postNotifyInput(this, new NotifyInputEventArgs(item));
                    }

                    // Post-Process the input.  This could modify the staging
                    // area.
                    if (InputDeviceEvents[devType]._postProcessInput != null)
                    {
                        InputDeviceEvents[devType]._postProcessInput(this, new ProcessInputEventArgs(item));

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

                                _stagingArea.Push(new StagingAreaInputItem(false, inputReport, item));
                            }
                        }
                    }

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

            if ((bool)postContinue == true)
            {
                _continueProcessingStagingArea = false;

                // It is possible that we can be re-entered by a nested
                // dispatcher frame.  Continue processing the staging
                // area if we need to.
                if (_stagingArea.Count > 0)
                {
                    // Before we actually start to drain the staging area, we need
                    // to post a work item to process more input.  This enables us
                    // to process more input if we enter a nested pump.
                    Dispatcher.BeginInvoke(_continueProcessingStagingAreaCallback, true);
                    _continueProcessingStagingArea = true;

                    // Now fall through to synchronously drain the staging area.
                }
            }

            return(handled);
        }