/// <summary> /// Focuses the keyboard on a particular element. /// </summary> /// <param name="element"> /// The element to focus the keyboard on. /// </param> public IInputElement Focus(IInputElement element) { DependencyObject oFocus = null; bool forceToNullIfFailed = false; // Validate that if elt is either a UIElement or a ContentElement. if (element != null) { if (!InputElement.IsValid(element)) { #pragma warning suppress 6506 // element is obviously not null throw new InvalidOperationException(SR.Get(SRID.Invalid_IInputElement, element.GetType())); } oFocus = (DependencyObject)element; } // If no element is given for focus, use the root of the active source. if (oFocus == null && _activeSource != null) { oFocus = _activeSource.Value.RootVisual as DependencyObject; forceToNullIfFailed = true; } Focus(oFocus, true, true, forceToNullIfFailed); return((IInputElement)_focus); }
private static void EnsureValid(ref IInputElement element) { // We understand UIElements and ContentElements. // If we are over something else (like a raw visual) find the containing element. if ((element != null) && !InputElement.IsValid(element)) { element = InputElement.GetContainingInputElement(element as DependencyObject); } }
private static IInputElement FilterInputElement(IInputElement elem) { // We only support UIElement, ContentElement, and UIElement3D if ((elem != null) && InputElement.IsValid(elem)) { return(elem); } return(null); }
internal bool CriticalCanExecute(object parameter, IInputElement target, bool trusted, out bool continueRouting) { // We only support UIElement, ContentElement, and UIElement3D if ((target != null) && !InputElement.IsValid(target)) { throw new InvalidOperationException(SR.Get(SRID.Invalid_IInputElement, target.GetType())); } if (target == null) { target = FilterInputElement(Keyboard.FocusedElement); } return(CanExecuteImpl(parameter, target, trusted, out continueRouting)); }
public void Execute(object parameter, IInputElement target) { // We only support UIElement, ContentElement and UIElement3D if ((target != null) && !InputElement.IsValid(target)) { throw new InvalidOperationException(SR.Get(SRID.Invalid_IInputElement, target.GetType())); } if (target == null) { target = FilterInputElement(Keyboard.FocusedElement); } ExecuteImpl(parameter, target, false); }
/// <summary> /// Constructs an instance of the KeyboardFocusChangedEventArgs class. /// </summary> /// <param name="keyboard"> /// The logical keyboard device associated with this event. /// </param> /// <param name="timestamp"> /// The time when the input occured. /// </param> /// <param name="oldFocus"> /// The element that previously had focus. /// </param> /// <param name="newFocus"> /// The element that now has focus. /// </param> public KeyboardFocusChangedEventArgs(KeyboardDevice keyboard, int timestamp, IInputElement oldFocus, IInputElement newFocus) : base(keyboard, timestamp) { if (oldFocus != null && !InputElement.IsValid(oldFocus)) { throw new InvalidOperationException(SR.Get(SRID.Invalid_IInputElement, oldFocus.GetType())); } if (newFocus != null && !InputElement.IsValid(newFocus)) { throw new InvalidOperationException(SR.Get(SRID.Invalid_IInputElement, newFocus.GetType())); } _oldFocus = oldFocus; _newFocus = newFocus; }
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); }