public void PreNotifyInput_Should_Not_Be_Called_If_Cancelled() { bool notified = false; PreProcessInputEventHandler preProcess = (sender, ev) => { ev.Cancel(); }; NotifyInputEventHandler preNotify = (sender, ev) => { notified = true; }; InputElement element = new InputElement(); TestEventArgs e = new TestEventArgs(element); e.RoutedEvent = InputElement.RawEvent; InputManager.Current.PreProcessInput += preProcess; InputManager.Current.PreNotifyInput += preNotify; InputManager.Current.ProcessInput(e); InputManager.Current.PreNotifyInput -= preNotify; InputManager.Current.PreProcessInput -= preProcess; Assert.IsFalse(notified); }
/// <summary> /// To prevent contaminating the system with test side effects /// (basically, to prevent our MockKeyboardDevice from listening and reacting to real /// keyboard input), we need to undo the damage done by the /// base KeyboardDevice's constructor where it subscribes to some events. /// By unsubscribing from these events we make sure our KeyboardDevice /// won't respond to real input and will be used solely to provide the /// desired state of the Shift, Alt and Ctrl modifier keys when asked for. /// </summary> private MockKeyboardDevice() : base(InputManager.Current) { // There's only one global input manager in the system InputManager inputManager = InputManager.Current; // First, unsubscribe our 3 handlers from the InputManager. // 1) // Undo the effect of the following line in the KeyboardDevice ctor: // this._inputManager.Value.PreProcessInput += new PreProcessInputEventHandler(this.PreProcessInput); PreProcessInputEventHandler preProcessInputHandler = GetDelegateForMethod <PreProcessInputEventHandler>(this, "PreProcessInput"); inputManager.PreProcessInput -= preProcessInputHandler; // 2) // Undo the effect of the following line in the KeyboardDevice ctor: // this._inputManager.Value.PreNotifyInput += new NotifyInputEventHandler(this.PreNotifyInput); NotifyInputEventHandler preNotifyInputHandler = GetDelegateForMethod <NotifyInputEventHandler>(this, "PreNotifyInput"); inputManager.PreNotifyInput -= preNotifyInputHandler; // 3) // Undo the effect of the following line in the KeyboardDevice ctor: // this._inputManager.Value.PostProcessInput += new ProcessInputEventHandler(this.PostProcessInput); ProcessInputEventHandler postProcessInputHandler = GetDelegateForMethod <ProcessInputEventHandler>(this, "PostProcessInput"); inputManager.PostProcessInput -= postProcessInputHandler; // Now undo the damage done by creating a new TextServicesManager // this._TsfManager = new SecurityCriticalDataClass<TextServicesManager>(new TextServicesManager(inputManager)); var textServicesManager = this.GetFieldValue("_TsfManager").GetFieldValue("_value"); // this._inputManager.PreProcessInput += new PreProcessInputEventHandler(this.PreProcessInput); preProcessInputHandler = GetDelegateForMethod <PreProcessInputEventHandler>(textServicesManager, "PreProcessInput"); inputManager.PreProcessInput -= preProcessInputHandler; // this._inputManager.PostProcessInput += new ProcessInputEventHandler(this.PostProcessInput); postProcessInputHandler = GetDelegateForMethod <ProcessInputEventHandler>(textServicesManager, "PostProcessInput"); inputManager.PostProcessInput -= postProcessInputHandler; // And finally, revert the changes done by creating a new TextCompositionManager // this._textcompositionManager = new SecurityCriticalData<TextCompositionManager>(new TextCompositionManager(inputManager)); var textCompositionManager = this.GetFieldValue("_textcompositionManager").GetFieldValue("_value"); // this._inputManager.PreProcessInput += new PreProcessInputEventHandler(this.PreProcessInput); preProcessInputHandler = GetDelegateForMethod <PreProcessInputEventHandler>(textCompositionManager, "PreProcessInput"); inputManager.PreProcessInput -= preProcessInputHandler; // his._inputManager.PostProcessInput += new ProcessInputEventHandler(this.PostProcessInput); postProcessInputHandler = GetDelegateForMethod <ProcessInputEventHandler>(textCompositionManager, "PostProcessInput"); inputManager.PostProcessInput -= postProcessInputHandler; }
public void PostNotifyInput_Should_Be_Called() { bool notified = false; NotifyInputEventHandler postNotify = (sender, ev) => { notified = true; }; InputElement element = new InputElement(); TestEventArgs e = new TestEventArgs(element); e.RoutedEvent = InputElement.RawEvent; InputManager.Current.PostNotifyInput += postNotify; InputManager.Current.ProcessInput(e); InputManager.Current.PostNotifyInput -= postNotify; Assert.IsTrue(notified); }
public void PostNotify_Event_Should_Be_Called_With_Mutated_Event() { bool calledWithMutated = false; PreProcessInputEventHandler preProcess = (sender, ev) => { if (ev.StagingItem.Input.RoutedEvent == InputElement.RawEvent) { TestEventArgs mutated = new TestEventArgs(ev.StagingItem.Input.Device.Target); mutated.RoutedEvent = InputElement.MutatedEvent; StagingAreaInputItem stagingItem = CreateStagingItem(mutated); ev.PushInput(stagingItem); ev.Cancel(); } }; NotifyInputEventHandler postNotify = (sender, ev) => { if (ev.StagingItem.Input.RoutedEvent == InputElement.MutatedEvent) { calledWithMutated = true; } }; InputElement element = new InputElement(); TestEventArgs e = new TestEventArgs(element); e.RoutedEvent = InputElement.RawEvent; InputManager.Current.PreProcessInput += preProcess; InputManager.Current.PostNotifyInput += postNotify; InputManager.Current.ProcessInput(e); InputManager.Current.PostNotifyInput += postNotify; InputManager.Current.PreProcessInput -= preProcess; Assert.IsTrue(calledWithMutated); }
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 object ProcessStagingArea(object frame) { bool flag1 = false; try { label_21: if (this._stagingArea.Count > 0) { this._currentStagingStack = this._stagingArea.Dequeue() as Stack; do { StagingAreaInputItem stagingAreaInputItem = (StagingAreaInputItem)this._currentStagingStack.Pop(); bool flag2 = false; int deviceType = (int)stagingAreaInputItem.Input._inputDevice.DeviceType; if (this.InputDeviceEvents[deviceType]._preProcessInput != null) { PreProcessInputEventArgs processInputEventArgs; this.InputDeviceEvents[deviceType]._preProcessInput((object)this, processInputEventArgs = new PreProcessInputEventArgs(stagingAreaInputItem)); flag2 = processInputEventArgs._canceled; } if (!flag2) { NotifyInputEventHandler preNotifyInput = this.InputDeviceEvents[deviceType]._preNotifyInput; if (preNotifyInput != null) { preNotifyInput((object)this, new NotifyInputEventArgs(stagingAreaInputItem)); } InputEventArgs input1 = stagingAreaInputItem.Input; UIElement uiElement = input1._source as UIElement; if (uiElement == null && input1._inputDevice != null) { uiElement = input1._inputDevice.Target; } uiElement?.RaiseEvent((RoutedEventArgs)input1); NotifyInputEventHandler postNotifyInput = this.InputDeviceEvents[deviceType]._postNotifyInput; if (postNotifyInput != null) { postNotifyInput((object)this, new NotifyInputEventArgs(stagingAreaInputItem)); } ProcessInputEventHandler postProcessInput = this.InputDeviceEvents[deviceType]._postProcessInput; if (postProcessInput != null) { postProcessInput((object)this, new ProcessInputEventArgs(stagingAreaInputItem)); } if (stagingAreaInputItem.Input._routedEvent == InputManager.PreviewInputReportEvent && !stagingAreaInputItem.Input.Handled) { InputReportEventArgs input2 = (InputReportEventArgs)stagingAreaInputItem.Input; InputReportEventArgs inputReportEventArgs = new InputReportEventArgs(input2.Device, input2.Report); inputReportEventArgs.RoutedEvent = InputManager.InputReportEvent; this._currentStagingStack.Push((object)new StagingAreaInputItem((InputEventArgs)inputReportEventArgs, stagingAreaInputItem)); } if (input1.Handled) { flag1 = true; } } }while (this._currentStagingStack.Count > 0); goto label_21; } } finally { if (this._stagingArea.Count > 0) { this.Dispatcher.BeginInvoke(this._continueProcessingStagingAreaCallback, (object)this.Dispatcher.CurrentFrame); } this._frameStagingArea.Remove(frame); } return((object)flag1); }