Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / System / Windows / Input / KeyboardDevice.cs / 1 / KeyboardDevice.cs
using System; using System.Collections; using System.Security; using System.Security.Permissions; using System.Windows; using System.Windows.Media; using System.Windows.Threading; using MS.Internal; using MS.Internal.PresentationCore; // SecurityHelper using MS.Win32; // VK translation. using System.Windows.Automation.Peers; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; #pragma warning disable 1634, 1691 // suppressing PreSharp warnings namespace System.Windows.Input { ////// The KeyboardDevice class represents the mouse device to the /// members of a context. /// public abstract class KeyboardDevice : InputDevice { ////// Critical: This code creates critical data(_tsfManager,_textcompositionManager) and stores critical data (inputManager) /// TreatAsSafe: Although it creates critical data there are demand on the critical data and the constructor is safe /// [SecurityCritical,SecurityTreatAsSafe] protected KeyboardDevice(InputManager inputManager) { _inputManager = new SecurityCriticalDataClass(inputManager); _inputManager.Value.PreProcessInput += new PreProcessInputEventHandler(PreProcessInput); _inputManager.Value.PreNotifyInput += new NotifyInputEventHandler(PreNotifyInput); _inputManager.Value.PostProcessInput += new ProcessInputEventHandler(PostProcessInput); _isEnabledChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsEnabledChanged); _isVisibleChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsVisibleChanged); _focusableChangedEventHandler = new DependencyPropertyChangedEventHandler(OnFocusableChanged); _reevaluateFocusCallback = new DispatcherOperationCallback(ReevaluateFocusCallback); _reevaluateFocusOperation = null; // _TsfManager = new SecurityCriticalDataClass (new TextServicesManager(inputManager)); _textcompositionManager = new SecurityCriticalData (new TextCompositionManager(inputManager)); } /// /// Gets the current state of the specified key from the device from the underlying system /// /// /// Key to get the state of /// ////// The state of the specified key /// protected abstract KeyStates GetKeyStatesFromSystem( Key key ); ////// Returns the element that input from this device is sent to. /// public override IInputElement Target { get { //VerifyAccess(); if(null != ForceTarget) return ForceTarget; return FocusedElement; } } internal IInputElement ForceTarget { get { return (IInputElement) _forceTarget; } set { _forceTarget = value as DependencyObject; } } ////// Returns the PresentationSource that is reporting input for this device. /// ////// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// ////// Critical - accesses critical data ( _activeSource) /// PublicOK - there is a demand. /// public override PresentationSource ActiveSource { [SecurityCritical ] get { SecurityHelper.DemandUnrestrictedUIPermission(); //VerifyAccess(); if (_activeSource != null) { return _activeSource.Value; } return null; } } ////// Returns the element that the keyboard is focused on. /// public IInputElement FocusedElement { get { // VerifyAccess(); return (IInputElement) _focus; } } ////// Focuses the keyboard on a particular element. /// /// /// The element to focus the keyboard on. /// public IInputElement Focus(IInputElement element) { // VerifyAccess(); // Validate that if elt is either a UIElement or a ContentElement. DependencyObject oFocus = null; 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; } Focus(oFocus, true, true); return (IInputElement) _focus; } ////// Critical: This code calls into PresentationSource. which is not safe to expose. /// Additonally it retrieves the keyboard input provider /// TreatAsSafe: Moving focus within an app is safe and this does not expose /// the critical data. /// [SecurityCritical,SecurityTreatAsSafe] private void Focus(DependencyObject focus, bool askOld, bool askNew) { bool forceToNullIfFailed = false; // If no element is given for focus, use the root of the active source. if(focus == null && _activeSource != null) { focus = _activeSource.Value.RootVisual as UIElement; forceToNullIfFailed = true; } // Make sure that the element is valid for receiving focus. bool isValid = true; if(focus != null) { isValid = Keyboard.IsFocusable(focus); if(!isValid && forceToNullIfFailed) { focus = null; isValid = true; } } if(isValid) { // Get the keyboard input provider that provides input for the active source. IKeyboardInputProvider keyboardInputProvider = null; DependencyObject containingVisual = InputElement.GetContainingVisual(focus); if(containingVisual != null) { PresentationSource source = PresentationSource.CriticalFromVisual(containingVisual); if (source != null) { keyboardInputProvider = (IKeyboardInputProvider)source.GetInputProvider(typeof(KeyboardDevice)); } } // Start the focus-change operation. TryChangeFocus(focus, keyboardInputProvider, askOld, askNew, forceToNullIfFailed); } } ////// Returns the set of modifier keys currently pressed as determined by querying our keyboard state cache /// public ModifierKeys Modifiers { get { // VerifyAccess(); ModifierKeys modifiers = ModifierKeys.None; if(IsKeyDown_private(Key.LeftAlt) || IsKeyDown_private(Key.RightAlt)) { modifiers |= ModifierKeys.Alt; } if(IsKeyDown_private(Key.LeftCtrl) || IsKeyDown_private(Key.RightCtrl)) { modifiers |= ModifierKeys.Control; } if(IsKeyDown_private(Key.LeftShift) || IsKeyDown_private(Key.RightShift)) { modifiers |= ModifierKeys.Shift; } return modifiers; } } ////// There is a proscription against using Enum.IsDefined(). (it is slow) /// so we write these PRIVATE validate routines instead. /// private void Validate_Key(Key key) { if( 256 <= (int)key || (int)key <= 0) throw new System.ComponentModel.InvalidEnumArgumentException("key"); } ////// This is the core private method that returns whether or not the specified key /// is down. It does it without the extra argument validation and context checks. /// private bool IsKeyDown_private(Key key) { return ( ( GetKeyStatesFromSystem(key) & KeyStates.Down ) == KeyStates.Down ); } ////// Returns whether or not the specified key is down. /// public bool IsKeyDown(Key key) { // VerifyAccess(); Validate_Key(key); return IsKeyDown_private(key); } ////// Returns whether or not the specified key is up. /// public bool IsKeyUp(Key key) { // VerifyAccess(); Validate_Key(key); return (!IsKeyDown_private(key)); } ////// Returns whether or not the specified key is toggled. /// public bool IsKeyToggled(Key key) { // VerifyAccess(); Validate_Key(key); return( ( GetKeyStatesFromSystem(key) & KeyStates.Toggled ) == KeyStates.Toggled ); } ////// Returns the state of the specified key. /// public KeyStates GetKeyStates(Key key) { // VerifyAccess(); Validate_Key(key); return GetKeyStatesFromSystem(key); } ////// Critical:This entity is not safe to give out /// internal TextServicesManager TextServicesManager { [SecurityCritical,SecurityTreatAsSafe] get { SecurityHelper.DemandUnrestrictedUIPermission(); return _TsfManager.Value; } } ////// Critical:This entity is not safe to give out /// internal TextCompositionManager TextCompositionManager { [SecurityCritical,SecurityTreatAsSafe] get { SecurityHelper.DemandUnrestrictedUIPermission(); return _textcompositionManager.Value; } } ////// Critical: This code accesses critical data (inputManager) and /// causes a change of focus. /// TreatAsSafe:This code is safe to expose /// [SecurityCritical,SecurityTreatAsSafe] private void TryChangeFocus(DependencyObject newFocus, IKeyboardInputProvider keyboardInputProvider, bool askOld, bool askNew, bool forceToNullIfFailed) { bool changeFocus = true; int timeStamp = Environment.TickCount ; DependencyObject oldFocus = _focus; // This is required, used below to see if focus has been delegated if(newFocus != _focus) { // If requested, and there is currently something with focus // Send the PreviewLostKeyboardFocus event to see if the object losing focus want to cancel it. // - no need to check "changeFocus" here as it was just previously unconditionally set to true if(askOld && _focus != null) { KeyboardFocusChangedEventArgs previewLostFocus = new KeyboardFocusChangedEventArgs(this, timeStamp, (IInputElement)_focus, (IInputElement)newFocus); previewLostFocus.RoutedEvent=Keyboard.PreviewLostKeyboardFocusEvent; previewLostFocus.Source= _focus; if(_inputManager != null) _inputManager.Value.ProcessInput(previewLostFocus); // if(previewLostFocus.Handled) { changeFocus = false; } } // If requested, and there is an object to specified to take focus // Send the PreviewGotKeyboardFocus event to see if the object gaining focus want to cancel it. // - must also check "changeFocus", no point in checking if the "previewLostFocus" event // above already cancelled it if(askNew && changeFocus && newFocus != null) { KeyboardFocusChangedEventArgs previewGotFocus = new KeyboardFocusChangedEventArgs(this, timeStamp, (IInputElement)_focus, (IInputElement)newFocus); previewGotFocus.RoutedEvent=Keyboard.PreviewGotKeyboardFocusEvent; previewGotFocus.Source= newFocus; if(_inputManager != null) _inputManager.Value.ProcessInput(previewGotFocus); // if(previewGotFocus.Handled) { changeFocus = false; } } // If we are setting the focus to an element, see if the InputProvider // can take focus for us. if(changeFocus && newFocus != null) { if (keyboardInputProvider != null && Keyboard.IsFocusable(newFocus)) { changeFocus = keyboardInputProvider.AcquireFocus(); } else { changeFocus = false; } } // If the ChangeFocus operation was cancelled or the AcquireFocus operation failed // and the "ForceToNullIfFailed" flag was set, we set focus to null if( !changeFocus && forceToNullIfFailed && oldFocus == _focus /* Focus is not delegated */ ) { // focus might be delegated (e.g. during PreviewGotKeyboardFocus) // without actually changing, if it was already on the delegated // element (see bug 1794057). We can't test for this directly, // but if focus is within the desired element we'll assume this // is what happened. IInputElement newFocusElement = newFocus as IInputElement; if (newFocusElement == null || !newFocusElement.IsKeyboardFocusWithin) { newFocus = null; changeFocus = true; } } // If both the old and new focus elements allowed it, and the // InputProvider has acquired it, go ahead and change our internal // sense of focus to the desired element. if(changeFocus) { ChangeFocus(newFocus, timeStamp); } } } ////// Critical: This code accesses critical data (inputManager,_TsfManager,_inputManager) and /// is not OK to expose /// TreatAsSafe: This changes focus within an app /// [SecurityCritical,SecurityTreatAsSafe] private void ChangeFocus(DependencyObject focus, int timestamp) { DependencyObject o = null; if(focus != _focus) { // Update the critical pieces of data. DependencyObject oldFocus = _focus; _focus = focus; _focusRootVisual = InputElement.GetRootVisual(focus); using(Dispatcher.DisableProcessing()) // Disable reentrancy due to locks taken { // Adjust the handlers we use to track everything. if(oldFocus != null) { o = oldFocus; if (InputElement.IsUIElement(o)) { ((UIElement)o).IsEnabledChanged -= _isEnabledChangedEventHandler; ((UIElement)o).IsVisibleChanged -= _isVisibleChangedEventHandler; ((UIElement)o).FocusableChanged -= _focusableChangedEventHandler; } else if (InputElement.IsContentElement(o)) { ((ContentElement)o).IsEnabledChanged -= _isEnabledChangedEventHandler; // NOTE: there is no IsVisible property for ContentElements. ((ContentElement)o).FocusableChanged -= _focusableChangedEventHandler; } else { ((UIElement3D)o).IsEnabledChanged -= _isEnabledChangedEventHandler; ((UIElement3D)o).IsVisibleChanged -= _isVisibleChangedEventHandler; ((UIElement3D)o).FocusableChanged -= _focusableChangedEventHandler; } } if(_focus != null) { o = _focus; if (InputElement.IsUIElement(o)) { ((UIElement)o).IsEnabledChanged += _isEnabledChangedEventHandler; ((UIElement)o).IsVisibleChanged += _isVisibleChangedEventHandler; ((UIElement)o).FocusableChanged += _focusableChangedEventHandler; } else if (InputElement.IsContentElement(o)) { ((ContentElement)o).IsEnabledChanged += _isEnabledChangedEventHandler; // NOTE: there is no IsVisible property for ContentElements. ((ContentElement)o).FocusableChanged += _focusableChangedEventHandler; } else { ((UIElement3D)o).IsEnabledChanged += _isEnabledChangedEventHandler; ((UIElement3D)o).IsVisibleChanged += _isVisibleChangedEventHandler; ((UIElement3D)o).FocusableChanged += _focusableChangedEventHandler; } } } // Oddly enough, update the FocusWithinProperty properties first. This is // so any callbacks will see the more-common FocusWithinProperty properties // set correctly. UIElement.FocusWithinProperty.OnOriginValueChanged(oldFocus, _focus, ref _focusTreeState); // Invalidate the IsKeyboardFocused properties. if(oldFocus != null) { o = oldFocus; o.SetValue(UIElement.IsKeyboardFocusedPropertyKey, false); // Same property for ContentElements } if(_focus != null) { // Invalidate the IsKeyboardFocused property. o = _focus; o.SetValue(UIElement.IsKeyboardFocusedPropertyKey, true); // Same property for ContentElements } // Call TestServicesManager change the focus of the InputMethod is enable/disabled accordingly // so it's ready befere the GotKeyboardFocusEvent handler is invoked. if (_TsfManager != null) _TsfManager.Value.Focus(_focus); // InputLanguageManager checks the preferred input languages. // This should before GotEvent because the preferred input language // should be set at the event handler. InputLanguageManager.Current.Focus(_focus, oldFocus); // Send the LostKeyboardFocus and GotKeyboardFocus events. if(oldFocus != null) { KeyboardFocusChangedEventArgs lostFocus = new KeyboardFocusChangedEventArgs(this, timestamp, (IInputElement) oldFocus, (IInputElement) focus); lostFocus.RoutedEvent=Keyboard.LostKeyboardFocusEvent; lostFocus.Source= oldFocus; if(_inputManager != null) _inputManager.Value.ProcessInput(lostFocus); } if(_focus != null) { KeyboardFocusChangedEventArgs gotFocus = new KeyboardFocusChangedEventArgs(this, timestamp, (IInputElement) oldFocus, (IInputElement) _focus); gotFocus.RoutedEvent=Keyboard.GotKeyboardFocusEvent; gotFocus.Source= _focus; if(_inputManager!=null) _inputManager.Value.ProcessInput(gotFocus); } // InputMethod checks the preferred ime state. // The preferred input methods should be applied after Cicero TIP gots SetFocus callback. InputMethod.Current.GotKeyboardFocus(_focus); //Could be also built-in into IsKeyboardFocused_Changed static on UIElement and ContentElement //However the Automation likes to go immediately back on us so it would be better be last one... AutomationPeer.RaiseFocusChangedEventHelper((IInputElement)_focus); } } private void OnIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) { // The element with focus just became disabled. // // We can't leave focus on a disabled element, so move it. ReevaluateFocusAsync(null, null, false); } private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { // The element with focus just became non-visible (collapsed or hidden). // // We can't leave focus on a non-visible element, so move it. ReevaluateFocusAsync(null, null, false); } private void OnFocusableChanged(object sender, DependencyPropertyChangedEventArgs e) { // The element with focus just became unfocusable. // // We can't leave focus on an unfocusable element, so move it. ReevaluateFocusAsync(null, null, false); } ////// Determines if we can remain focused on the element we think has focus /// ////// Queues an invocation of ReevaluateFocusCallback to do the actual work. /// - that way if the object that had focus has only been temporarily /// removed, disable, etc. and will eventually be valid again, we /// avoid needlessly killing focus. /// internal void ReevaluateFocusAsync(DependencyObject element, DependencyObject oldParent, bool isCoreParent) { if(element != null) { if(isCoreParent) { FocusTreeState.SetCoreParent(element, oldParent); } else { FocusTreeState.SetLogicalParent(element, oldParent); } } // It would be best to re-evaluate anything dependent on the hit-test results // immediately after layout & rendering are complete. Unfortunately this can // lead to an infinite loop. Consider the following scenario: // // If the mouse is over an element, hide it. // // This never resolves to a "correct" state. When the mouse moves over the // element, the element is hidden, so the mouse is no longer over it, so the // element is shown, but that means the mouse is over it again. Repeat. // // We push our re-evaluation to a priority lower than input processing so that // the user can change the input device to avoid the infinite loops, or close // the app if nothing else works. // if(_reevaluateFocusOperation == null) { Dispatcher.BeginInvoke(DispatcherPriority.Input, _reevaluateFocusCallback, null); } } ////// Determines if we can remain focused on the element we think has focus /// ////// Invoked asynchronously by ReevaluateFocusAsync. /// Confirms that the element we think has focus is: /// - still enabled /// - still visible /// - still in the tree /// ////// Critical: accesses critical data ( _activeSource) /// TreatAsSafe: Moving focus within an app is safe and this does not expose /// the critical data. /// [SecurityCritical,SecurityTreatAsSafe] private object ReevaluateFocusCallback(object arg) { _reevaluateFocusOperation = null; if( _focus == null ) { return null; } bool moveFocus = false; DependencyObject moveFocusTo = null; // // Search for a node in the tree that is still connected to the // active presentation source and that is valid for focus. // if(moveFocus == false && _activeSource != null) { PresentationSource presentationSource = null; DependencyObject element = _focus; while(element != null) { DependencyObject visualContainer = InputElement.GetContainingVisual(element); if(visualContainer != null) { presentationSource = PresentationSource.CriticalFromVisual(visualContainer); if(presentationSource != null) { if(Keyboard.IsFocusable(element)) { break; } } } element = DeferredElementTreeState.GetCoreParent(element, _focusTreeState); } if(presentationSource == null) { // We did not find any presentation source. We must kill focus. moveFocus = true; moveFocusTo = null; } else if(presentationSource == _activeSource.Value) { if(element == _focus) { // The focus element is still good. moveFocus = false; } else { // We found a node still plugged into the active presentation // source, but it was some ancestor of the focused element. moveFocus = true; moveFocusTo = element; } } else { // We found a presentation source, but it is not the active one. // Try to move the focus to the active presentation source root. moveFocus = true; moveFocusTo = _activeSource.Value.RootVisual; } } else { // No active presentation source, we must kill focus. moveFocus = true; moveFocusTo = null; } if(moveFocus) { // Find the nearest element that is still connected to the tree. DependencyObject oldFocus = _focus; Focus(moveFocusTo, false, true); if(oldFocus == _focus) { // The focus change was rejected. Force focus to null. Focus(null, false, true); } } else { // Refresh FocusWithinProperty so that ReverseInherited Flags are updated. // // We only need to do this is there is any information about the old // tree state. if(_focusTreeState != null && !_focusTreeState.IsEmpty) { UIElement.FocusWithinProperty.OnOriginValueChanged(_focus, _focus, ref _focusTreeState); } } return null; } ////// Critical: accesses e.StagingItem.Input /// [SecurityCritical] private void PreProcessInput(object sender, PreProcessInputEventArgs e) { RawKeyboardInputReport keyboardInput = ExtractRawKeyboardInputReport(e, InputManager.PreviewInputReportEvent); if(keyboardInput != null) { // Claim the input for the keyboard. e.StagingItem.Input.Device = this; } } ////// Critical: This code can be used for input spoofing, /// It also stores critical data InputSource /// accesses e.StagingItem.Input /// [SecurityCritical] 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(keyboardInput.InputSource); } else if(_activeSource.Value != keyboardInput.InputSource) { IKeyboardInputProvider toDeactivate = _activeSource.Value.GetInputProvider(typeof(KeyboardDevice)) as IKeyboardInputProvider; // we are now active. _activeSource = new SecurityCriticalDataClass (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; } } /// /// Critical - calls critical functions PushInput, KeyEventArgs.UnsafeInputSource /// and KeyEventArgs ctor. /// accesses e.StagingItem.Input /// [SecurityCritical] private void PostProcessInput(object sender, ProcessInputEventArgs e) { // PreviewKeyDown --> KeyDown if(e.StagingItem.Input.RoutedEvent == Keyboard.PreviewKeyDownEvent) { CheckForDisconnectedFocus(); if(!e.StagingItem.Input.Handled) { KeyEventArgs previewKeyDown = (KeyEventArgs) e.StagingItem.Input; // Dig out the real key. bool isSystemKey = false; bool isImeProcessed = false; Key key = previewKeyDown.Key; if (key == Key.System) { isSystemKey = true; key = previewKeyDown.RealKey; } if (key == Key.ImeProcessed) { isImeProcessed = true; key = previewKeyDown.RealKey; } KeyEventArgs keyDown = new KeyEventArgs(this, previewKeyDown.UnsafeInputSource, previewKeyDown.Timestamp, key); keyDown.SetRepeat( previewKeyDown.IsRepeat ); // Mark the new event as SystemKey as appropriate. if (isSystemKey) { keyDown.MarkSystem(); } // Mark the new event as ImeProcessed as appropriate. if (isImeProcessed) { keyDown.MarkImeProcessed(); } keyDown.RoutedEvent=Keyboard.KeyDownEvent; keyDown.ScanCode = previewKeyDown.ScanCode; keyDown.IsExtendedKey = previewKeyDown.IsExtendedKey; e.PushInput(keyDown, e.StagingItem); } } // PreviewKeyUp --> KeyUp if(e.StagingItem.Input.RoutedEvent == Keyboard.PreviewKeyUpEvent) { CheckForDisconnectedFocus(); if(!e.StagingItem.Input.Handled) { KeyEventArgs previewKeyUp = (KeyEventArgs) e.StagingItem.Input; // Dig out the real key. bool isSystemKey = false; bool isImeProcessed = false; Key key = previewKeyUp.Key; if (key == Key.System) { isSystemKey = true; key = previewKeyUp.RealKey; } if (key == Key.ImeProcessed) { isImeProcessed = true; key = previewKeyUp.RealKey; } KeyEventArgs keyUp = new KeyEventArgs(this, previewKeyUp.UnsafeInputSource, previewKeyUp.Timestamp, key); // Mark the new event as SystemKey as appropriate. if (isSystemKey) { keyUp.MarkSystem(); } // Mark the new event as ImeProcessed as appropriate. if (isImeProcessed) { keyUp.MarkImeProcessed(); } keyUp.RoutedEvent=Keyboard.KeyUpEvent; keyUp.ScanCode = previewKeyUp.ScanCode; keyUp.IsExtendedKey = previewKeyUp.IsExtendedKey; e.PushInput(keyUp, e.StagingItem); } } RawKeyboardInputReport keyboardInput = ExtractRawKeyboardInputReport(e, InputManager.InputReportEvent); if(keyboardInput != null) { CheckForDisconnectedFocus(); if(!e.StagingItem.Input.Handled) { // In general, this is where we promote the non-redundant // reported actions to our premier events. RawKeyboardActions actions = GetNonRedundantActions(e); // Raw --> PreviewKeyDown if((actions & RawKeyboardActions.KeyDown) == RawKeyboardActions.KeyDown) { Key key = (Key) e.StagingItem.GetData(_tagKey); if(key != Key.None) { KeyEventArgs previewKeyDown = new KeyEventArgs(this, keyboardInput.InputSource, keyboardInput.Timestamp, key); ScanCode scanCode = (ScanCode)e.StagingItem.GetData(_tagScanCode); previewKeyDown.ScanCode = scanCode.Code; previewKeyDown.IsExtendedKey = scanCode.IsExtended; if (keyboardInput.IsSystemKey) { previewKeyDown.MarkSystem(); } previewKeyDown.RoutedEvent=Keyboard.PreviewKeyDownEvent; e.PushInput(previewKeyDown, e.StagingItem); } } // Raw --> PreviewKeyUp if((actions & RawKeyboardActions.KeyUp) == RawKeyboardActions.KeyUp) { Key key = (Key) e.StagingItem.GetData(_tagKey); if(key != Key.None) { KeyEventArgs previewKeyUp = new KeyEventArgs(this, keyboardInput.InputSource, keyboardInput.Timestamp, key); ScanCode scanCode = (ScanCode)e.StagingItem.GetData(_tagScanCode); previewKeyUp.ScanCode = scanCode.Code; previewKeyUp.IsExtendedKey = scanCode.IsExtended; if (keyboardInput.IsSystemKey) { previewKeyUp.MarkSystem(); } previewKeyUp.RoutedEvent=Keyboard.PreviewKeyUpEvent; e.PushInput(previewKeyUp, e.StagingItem); } } } // Deactivate if((keyboardInput.Actions & RawKeyboardActions.Deactivate) == RawKeyboardActions.Deactivate) { if(IsActive) { _activeSource = null; // Even if handled, a keyboard deactivate results in a lost focus. ChangeFocus(null, e.StagingItem.Input.Timestamp); } } } } ////// Critical: accesses the StagingInput /// [SecurityCritical] 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; } 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; } // private bool CheckForDisconnectedFocus() { bool wasDisconnected = false; if(InputElement.GetRootVisual (_focus as DependencyObject) != _focusRootVisual) { wasDisconnected = true; Focus (null); } return wasDisconnected; } ////// Critical: accesses critical data (_inputSource) /// TreatAsSafe: doesn't expose critical data, just returns true/false. /// internal bool IsActive { [SecurityCritical, SecurityTreatAsSafe] get { return _activeSource != null && _activeSource.Value != null; } } private DeferredElementTreeState FocusTreeState { get { if (_focusTreeState == null) { _focusTreeState = new DeferredElementTreeState(); } return _focusTreeState; } } private SecurityCriticalDataClass_inputManager; private SecurityCriticalDataClass _activeSource; private DependencyObject _focus; private DeferredElementTreeState _focusTreeState; private DependencyObject _forceTarget; private DependencyObject _focusRootVisual; private Key _previousKey; private DependencyPropertyChangedEventHandler _isEnabledChangedEventHandler; private DependencyPropertyChangedEventHandler _isVisibleChangedEventHandler; private DependencyPropertyChangedEventHandler _focusableChangedEventHandler; private DispatcherOperationCallback _reevaluateFocusCallback; private DispatcherOperation _reevaluateFocusOperation; // Data tags for information we pass around the staging area. private object _tagNonRedundantActions = new object(); private object _tagKey = new object(); private object _tagScanCode = new object(); private class ScanCode { internal ScanCode(int code, bool isExtended) { _code = code; _isExtended = isExtended; } internal int Code {get {return _code;}} internal bool IsExtended {get {return _isExtended;}} private readonly int _code; private readonly bool _isExtended; } // private SecurityCriticalData _textcompositionManager; // TextServicesManager handles KeyDown -> IME composition conversion. /// /// This data is risky to give out since it is got under an elevation /// and can be used for risky operations /// private SecurityCriticalDataClass_TsfManager; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. using System; using System.Collections; using System.Security; using System.Security.Permissions; using System.Windows; using System.Windows.Media; using System.Windows.Threading; using MS.Internal; using MS.Internal.PresentationCore; // SecurityHelper using MS.Win32; // VK translation. using System.Windows.Automation.Peers; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; #pragma warning disable 1634, 1691 // suppressing PreSharp warnings namespace System.Windows.Input { /// /// The KeyboardDevice class represents the mouse device to the /// members of a context. /// public abstract class KeyboardDevice : InputDevice { ////// Critical: This code creates critical data(_tsfManager,_textcompositionManager) and stores critical data (inputManager) /// TreatAsSafe: Although it creates critical data there are demand on the critical data and the constructor is safe /// [SecurityCritical,SecurityTreatAsSafe] protected KeyboardDevice(InputManager inputManager) { _inputManager = new SecurityCriticalDataClass(inputManager); _inputManager.Value.PreProcessInput += new PreProcessInputEventHandler(PreProcessInput); _inputManager.Value.PreNotifyInput += new NotifyInputEventHandler(PreNotifyInput); _inputManager.Value.PostProcessInput += new ProcessInputEventHandler(PostProcessInput); _isEnabledChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsEnabledChanged); _isVisibleChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsVisibleChanged); _focusableChangedEventHandler = new DependencyPropertyChangedEventHandler(OnFocusableChanged); _reevaluateFocusCallback = new DispatcherOperationCallback(ReevaluateFocusCallback); _reevaluateFocusOperation = null; // _TsfManager = new SecurityCriticalDataClass (new TextServicesManager(inputManager)); _textcompositionManager = new SecurityCriticalData (new TextCompositionManager(inputManager)); } /// /// Gets the current state of the specified key from the device from the underlying system /// /// /// Key to get the state of /// ////// The state of the specified key /// protected abstract KeyStates GetKeyStatesFromSystem( Key key ); ////// Returns the element that input from this device is sent to. /// public override IInputElement Target { get { //VerifyAccess(); if(null != ForceTarget) return ForceTarget; return FocusedElement; } } internal IInputElement ForceTarget { get { return (IInputElement) _forceTarget; } set { _forceTarget = value as DependencyObject; } } ////// Returns the PresentationSource that is reporting input for this device. /// ////// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// ////// Critical - accesses critical data ( _activeSource) /// PublicOK - there is a demand. /// public override PresentationSource ActiveSource { [SecurityCritical ] get { SecurityHelper.DemandUnrestrictedUIPermission(); //VerifyAccess(); if (_activeSource != null) { return _activeSource.Value; } return null; } } ////// Returns the element that the keyboard is focused on. /// public IInputElement FocusedElement { get { // VerifyAccess(); return (IInputElement) _focus; } } ////// Focuses the keyboard on a particular element. /// /// /// The element to focus the keyboard on. /// public IInputElement Focus(IInputElement element) { // VerifyAccess(); // Validate that if elt is either a UIElement or a ContentElement. DependencyObject oFocus = null; 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; } Focus(oFocus, true, true); return (IInputElement) _focus; } ////// Critical: This code calls into PresentationSource. which is not safe to expose. /// Additonally it retrieves the keyboard input provider /// TreatAsSafe: Moving focus within an app is safe and this does not expose /// the critical data. /// [SecurityCritical,SecurityTreatAsSafe] private void Focus(DependencyObject focus, bool askOld, bool askNew) { bool forceToNullIfFailed = false; // If no element is given for focus, use the root of the active source. if(focus == null && _activeSource != null) { focus = _activeSource.Value.RootVisual as UIElement; forceToNullIfFailed = true; } // Make sure that the element is valid for receiving focus. bool isValid = true; if(focus != null) { isValid = Keyboard.IsFocusable(focus); if(!isValid && forceToNullIfFailed) { focus = null; isValid = true; } } if(isValid) { // Get the keyboard input provider that provides input for the active source. IKeyboardInputProvider keyboardInputProvider = null; DependencyObject containingVisual = InputElement.GetContainingVisual(focus); if(containingVisual != null) { PresentationSource source = PresentationSource.CriticalFromVisual(containingVisual); if (source != null) { keyboardInputProvider = (IKeyboardInputProvider)source.GetInputProvider(typeof(KeyboardDevice)); } } // Start the focus-change operation. TryChangeFocus(focus, keyboardInputProvider, askOld, askNew, forceToNullIfFailed); } } ////// Returns the set of modifier keys currently pressed as determined by querying our keyboard state cache /// public ModifierKeys Modifiers { get { // VerifyAccess(); ModifierKeys modifiers = ModifierKeys.None; if(IsKeyDown_private(Key.LeftAlt) || IsKeyDown_private(Key.RightAlt)) { modifiers |= ModifierKeys.Alt; } if(IsKeyDown_private(Key.LeftCtrl) || IsKeyDown_private(Key.RightCtrl)) { modifiers |= ModifierKeys.Control; } if(IsKeyDown_private(Key.LeftShift) || IsKeyDown_private(Key.RightShift)) { modifiers |= ModifierKeys.Shift; } return modifiers; } } ////// There is a proscription against using Enum.IsDefined(). (it is slow) /// so we write these PRIVATE validate routines instead. /// private void Validate_Key(Key key) { if( 256 <= (int)key || (int)key <= 0) throw new System.ComponentModel.InvalidEnumArgumentException("key"); } ////// This is the core private method that returns whether or not the specified key /// is down. It does it without the extra argument validation and context checks. /// private bool IsKeyDown_private(Key key) { return ( ( GetKeyStatesFromSystem(key) & KeyStates.Down ) == KeyStates.Down ); } ////// Returns whether or not the specified key is down. /// public bool IsKeyDown(Key key) { // VerifyAccess(); Validate_Key(key); return IsKeyDown_private(key); } ////// Returns whether or not the specified key is up. /// public bool IsKeyUp(Key key) { // VerifyAccess(); Validate_Key(key); return (!IsKeyDown_private(key)); } ////// Returns whether or not the specified key is toggled. /// public bool IsKeyToggled(Key key) { // VerifyAccess(); Validate_Key(key); return( ( GetKeyStatesFromSystem(key) & KeyStates.Toggled ) == KeyStates.Toggled ); } ////// Returns the state of the specified key. /// public KeyStates GetKeyStates(Key key) { // VerifyAccess(); Validate_Key(key); return GetKeyStatesFromSystem(key); } ////// Critical:This entity is not safe to give out /// internal TextServicesManager TextServicesManager { [SecurityCritical,SecurityTreatAsSafe] get { SecurityHelper.DemandUnrestrictedUIPermission(); return _TsfManager.Value; } } ////// Critical:This entity is not safe to give out /// internal TextCompositionManager TextCompositionManager { [SecurityCritical,SecurityTreatAsSafe] get { SecurityHelper.DemandUnrestrictedUIPermission(); return _textcompositionManager.Value; } } ////// Critical: This code accesses critical data (inputManager) and /// causes a change of focus. /// TreatAsSafe:This code is safe to expose /// [SecurityCritical,SecurityTreatAsSafe] private void TryChangeFocus(DependencyObject newFocus, IKeyboardInputProvider keyboardInputProvider, bool askOld, bool askNew, bool forceToNullIfFailed) { bool changeFocus = true; int timeStamp = Environment.TickCount ; DependencyObject oldFocus = _focus; // This is required, used below to see if focus has been delegated if(newFocus != _focus) { // If requested, and there is currently something with focus // Send the PreviewLostKeyboardFocus event to see if the object losing focus want to cancel it. // - no need to check "changeFocus" here as it was just previously unconditionally set to true if(askOld && _focus != null) { KeyboardFocusChangedEventArgs previewLostFocus = new KeyboardFocusChangedEventArgs(this, timeStamp, (IInputElement)_focus, (IInputElement)newFocus); previewLostFocus.RoutedEvent=Keyboard.PreviewLostKeyboardFocusEvent; previewLostFocus.Source= _focus; if(_inputManager != null) _inputManager.Value.ProcessInput(previewLostFocus); // if(previewLostFocus.Handled) { changeFocus = false; } } // If requested, and there is an object to specified to take focus // Send the PreviewGotKeyboardFocus event to see if the object gaining focus want to cancel it. // - must also check "changeFocus", no point in checking if the "previewLostFocus" event // above already cancelled it if(askNew && changeFocus && newFocus != null) { KeyboardFocusChangedEventArgs previewGotFocus = new KeyboardFocusChangedEventArgs(this, timeStamp, (IInputElement)_focus, (IInputElement)newFocus); previewGotFocus.RoutedEvent=Keyboard.PreviewGotKeyboardFocusEvent; previewGotFocus.Source= newFocus; if(_inputManager != null) _inputManager.Value.ProcessInput(previewGotFocus); // if(previewGotFocus.Handled) { changeFocus = false; } } // If we are setting the focus to an element, see if the InputProvider // can take focus for us. if(changeFocus && newFocus != null) { if (keyboardInputProvider != null && Keyboard.IsFocusable(newFocus)) { changeFocus = keyboardInputProvider.AcquireFocus(); } else { changeFocus = false; } } // If the ChangeFocus operation was cancelled or the AcquireFocus operation failed // and the "ForceToNullIfFailed" flag was set, we set focus to null if( !changeFocus && forceToNullIfFailed && oldFocus == _focus /* Focus is not delegated */ ) { // focus might be delegated (e.g. during PreviewGotKeyboardFocus) // without actually changing, if it was already on the delegated // element (see bug 1794057). We can't test for this directly, // but if focus is within the desired element we'll assume this // is what happened. IInputElement newFocusElement = newFocus as IInputElement; if (newFocusElement == null || !newFocusElement.IsKeyboardFocusWithin) { newFocus = null; changeFocus = true; } } // If both the old and new focus elements allowed it, and the // InputProvider has acquired it, go ahead and change our internal // sense of focus to the desired element. if(changeFocus) { ChangeFocus(newFocus, timeStamp); } } } ////// Critical: This code accesses critical data (inputManager,_TsfManager,_inputManager) and /// is not OK to expose /// TreatAsSafe: This changes focus within an app /// [SecurityCritical,SecurityTreatAsSafe] private void ChangeFocus(DependencyObject focus, int timestamp) { DependencyObject o = null; if(focus != _focus) { // Update the critical pieces of data. DependencyObject oldFocus = _focus; _focus = focus; _focusRootVisual = InputElement.GetRootVisual(focus); using(Dispatcher.DisableProcessing()) // Disable reentrancy due to locks taken { // Adjust the handlers we use to track everything. if(oldFocus != null) { o = oldFocus; if (InputElement.IsUIElement(o)) { ((UIElement)o).IsEnabledChanged -= _isEnabledChangedEventHandler; ((UIElement)o).IsVisibleChanged -= _isVisibleChangedEventHandler; ((UIElement)o).FocusableChanged -= _focusableChangedEventHandler; } else if (InputElement.IsContentElement(o)) { ((ContentElement)o).IsEnabledChanged -= _isEnabledChangedEventHandler; // NOTE: there is no IsVisible property for ContentElements. ((ContentElement)o).FocusableChanged -= _focusableChangedEventHandler; } else { ((UIElement3D)o).IsEnabledChanged -= _isEnabledChangedEventHandler; ((UIElement3D)o).IsVisibleChanged -= _isVisibleChangedEventHandler; ((UIElement3D)o).FocusableChanged -= _focusableChangedEventHandler; } } if(_focus != null) { o = _focus; if (InputElement.IsUIElement(o)) { ((UIElement)o).IsEnabledChanged += _isEnabledChangedEventHandler; ((UIElement)o).IsVisibleChanged += _isVisibleChangedEventHandler; ((UIElement)o).FocusableChanged += _focusableChangedEventHandler; } else if (InputElement.IsContentElement(o)) { ((ContentElement)o).IsEnabledChanged += _isEnabledChangedEventHandler; // NOTE: there is no IsVisible property for ContentElements. ((ContentElement)o).FocusableChanged += _focusableChangedEventHandler; } else { ((UIElement3D)o).IsEnabledChanged += _isEnabledChangedEventHandler; ((UIElement3D)o).IsVisibleChanged += _isVisibleChangedEventHandler; ((UIElement3D)o).FocusableChanged += _focusableChangedEventHandler; } } } // Oddly enough, update the FocusWithinProperty properties first. This is // so any callbacks will see the more-common FocusWithinProperty properties // set correctly. UIElement.FocusWithinProperty.OnOriginValueChanged(oldFocus, _focus, ref _focusTreeState); // Invalidate the IsKeyboardFocused properties. if(oldFocus != null) { o = oldFocus; o.SetValue(UIElement.IsKeyboardFocusedPropertyKey, false); // Same property for ContentElements } if(_focus != null) { // Invalidate the IsKeyboardFocused property. o = _focus; o.SetValue(UIElement.IsKeyboardFocusedPropertyKey, true); // Same property for ContentElements } // Call TestServicesManager change the focus of the InputMethod is enable/disabled accordingly // so it's ready befere the GotKeyboardFocusEvent handler is invoked. if (_TsfManager != null) _TsfManager.Value.Focus(_focus); // InputLanguageManager checks the preferred input languages. // This should before GotEvent because the preferred input language // should be set at the event handler. InputLanguageManager.Current.Focus(_focus, oldFocus); // Send the LostKeyboardFocus and GotKeyboardFocus events. if(oldFocus != null) { KeyboardFocusChangedEventArgs lostFocus = new KeyboardFocusChangedEventArgs(this, timestamp, (IInputElement) oldFocus, (IInputElement) focus); lostFocus.RoutedEvent=Keyboard.LostKeyboardFocusEvent; lostFocus.Source= oldFocus; if(_inputManager != null) _inputManager.Value.ProcessInput(lostFocus); } if(_focus != null) { KeyboardFocusChangedEventArgs gotFocus = new KeyboardFocusChangedEventArgs(this, timestamp, (IInputElement) oldFocus, (IInputElement) _focus); gotFocus.RoutedEvent=Keyboard.GotKeyboardFocusEvent; gotFocus.Source= _focus; if(_inputManager!=null) _inputManager.Value.ProcessInput(gotFocus); } // InputMethod checks the preferred ime state. // The preferred input methods should be applied after Cicero TIP gots SetFocus callback. InputMethod.Current.GotKeyboardFocus(_focus); //Could be also built-in into IsKeyboardFocused_Changed static on UIElement and ContentElement //However the Automation likes to go immediately back on us so it would be better be last one... AutomationPeer.RaiseFocusChangedEventHelper((IInputElement)_focus); } } private void OnIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) { // The element with focus just became disabled. // // We can't leave focus on a disabled element, so move it. ReevaluateFocusAsync(null, null, false); } private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { // The element with focus just became non-visible (collapsed or hidden). // // We can't leave focus on a non-visible element, so move it. ReevaluateFocusAsync(null, null, false); } private void OnFocusableChanged(object sender, DependencyPropertyChangedEventArgs e) { // The element with focus just became unfocusable. // // We can't leave focus on an unfocusable element, so move it. ReevaluateFocusAsync(null, null, false); } ////// Determines if we can remain focused on the element we think has focus /// ////// Queues an invocation of ReevaluateFocusCallback to do the actual work. /// - that way if the object that had focus has only been temporarily /// removed, disable, etc. and will eventually be valid again, we /// avoid needlessly killing focus. /// internal void ReevaluateFocusAsync(DependencyObject element, DependencyObject oldParent, bool isCoreParent) { if(element != null) { if(isCoreParent) { FocusTreeState.SetCoreParent(element, oldParent); } else { FocusTreeState.SetLogicalParent(element, oldParent); } } // It would be best to re-evaluate anything dependent on the hit-test results // immediately after layout & rendering are complete. Unfortunately this can // lead to an infinite loop. Consider the following scenario: // // If the mouse is over an element, hide it. // // This never resolves to a "correct" state. When the mouse moves over the // element, the element is hidden, so the mouse is no longer over it, so the // element is shown, but that means the mouse is over it again. Repeat. // // We push our re-evaluation to a priority lower than input processing so that // the user can change the input device to avoid the infinite loops, or close // the app if nothing else works. // if(_reevaluateFocusOperation == null) { Dispatcher.BeginInvoke(DispatcherPriority.Input, _reevaluateFocusCallback, null); } } ////// Determines if we can remain focused on the element we think has focus /// ////// Invoked asynchronously by ReevaluateFocusAsync. /// Confirms that the element we think has focus is: /// - still enabled /// - still visible /// - still in the tree /// ////// Critical: accesses critical data ( _activeSource) /// TreatAsSafe: Moving focus within an app is safe and this does not expose /// the critical data. /// [SecurityCritical,SecurityTreatAsSafe] private object ReevaluateFocusCallback(object arg) { _reevaluateFocusOperation = null; if( _focus == null ) { return null; } bool moveFocus = false; DependencyObject moveFocusTo = null; // // Search for a node in the tree that is still connected to the // active presentation source and that is valid for focus. // if(moveFocus == false && _activeSource != null) { PresentationSource presentationSource = null; DependencyObject element = _focus; while(element != null) { DependencyObject visualContainer = InputElement.GetContainingVisual(element); if(visualContainer != null) { presentationSource = PresentationSource.CriticalFromVisual(visualContainer); if(presentationSource != null) { if(Keyboard.IsFocusable(element)) { break; } } } element = DeferredElementTreeState.GetCoreParent(element, _focusTreeState); } if(presentationSource == null) { // We did not find any presentation source. We must kill focus. moveFocus = true; moveFocusTo = null; } else if(presentationSource == _activeSource.Value) { if(element == _focus) { // The focus element is still good. moveFocus = false; } else { // We found a node still plugged into the active presentation // source, but it was some ancestor of the focused element. moveFocus = true; moveFocusTo = element; } } else { // We found a presentation source, but it is not the active one. // Try to move the focus to the active presentation source root. moveFocus = true; moveFocusTo = _activeSource.Value.RootVisual; } } else { // No active presentation source, we must kill focus. moveFocus = true; moveFocusTo = null; } if(moveFocus) { // Find the nearest element that is still connected to the tree. DependencyObject oldFocus = _focus; Focus(moveFocusTo, false, true); if(oldFocus == _focus) { // The focus change was rejected. Force focus to null. Focus(null, false, true); } } else { // Refresh FocusWithinProperty so that ReverseInherited Flags are updated. // // We only need to do this is there is any information about the old // tree state. if(_focusTreeState != null && !_focusTreeState.IsEmpty) { UIElement.FocusWithinProperty.OnOriginValueChanged(_focus, _focus, ref _focusTreeState); } } return null; } ////// Critical: accesses e.StagingItem.Input /// [SecurityCritical] private void PreProcessInput(object sender, PreProcessInputEventArgs e) { RawKeyboardInputReport keyboardInput = ExtractRawKeyboardInputReport(e, InputManager.PreviewInputReportEvent); if(keyboardInput != null) { // Claim the input for the keyboard. e.StagingItem.Input.Device = this; } } ////// Critical: This code can be used for input spoofing, /// It also stores critical data InputSource /// accesses e.StagingItem.Input /// [SecurityCritical] 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(keyboardInput.InputSource); } else if(_activeSource.Value != keyboardInput.InputSource) { IKeyboardInputProvider toDeactivate = _activeSource.Value.GetInputProvider(typeof(KeyboardDevice)) as IKeyboardInputProvider; // we are now active. _activeSource = new SecurityCriticalDataClass (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; } } /// /// Critical - calls critical functions PushInput, KeyEventArgs.UnsafeInputSource /// and KeyEventArgs ctor. /// accesses e.StagingItem.Input /// [SecurityCritical] private void PostProcessInput(object sender, ProcessInputEventArgs e) { // PreviewKeyDown --> KeyDown if(e.StagingItem.Input.RoutedEvent == Keyboard.PreviewKeyDownEvent) { CheckForDisconnectedFocus(); if(!e.StagingItem.Input.Handled) { KeyEventArgs previewKeyDown = (KeyEventArgs) e.StagingItem.Input; // Dig out the real key. bool isSystemKey = false; bool isImeProcessed = false; Key key = previewKeyDown.Key; if (key == Key.System) { isSystemKey = true; key = previewKeyDown.RealKey; } if (key == Key.ImeProcessed) { isImeProcessed = true; key = previewKeyDown.RealKey; } KeyEventArgs keyDown = new KeyEventArgs(this, previewKeyDown.UnsafeInputSource, previewKeyDown.Timestamp, key); keyDown.SetRepeat( previewKeyDown.IsRepeat ); // Mark the new event as SystemKey as appropriate. if (isSystemKey) { keyDown.MarkSystem(); } // Mark the new event as ImeProcessed as appropriate. if (isImeProcessed) { keyDown.MarkImeProcessed(); } keyDown.RoutedEvent=Keyboard.KeyDownEvent; keyDown.ScanCode = previewKeyDown.ScanCode; keyDown.IsExtendedKey = previewKeyDown.IsExtendedKey; e.PushInput(keyDown, e.StagingItem); } } // PreviewKeyUp --> KeyUp if(e.StagingItem.Input.RoutedEvent == Keyboard.PreviewKeyUpEvent) { CheckForDisconnectedFocus(); if(!e.StagingItem.Input.Handled) { KeyEventArgs previewKeyUp = (KeyEventArgs) e.StagingItem.Input; // Dig out the real key. bool isSystemKey = false; bool isImeProcessed = false; Key key = previewKeyUp.Key; if (key == Key.System) { isSystemKey = true; key = previewKeyUp.RealKey; } if (key == Key.ImeProcessed) { isImeProcessed = true; key = previewKeyUp.RealKey; } KeyEventArgs keyUp = new KeyEventArgs(this, previewKeyUp.UnsafeInputSource, previewKeyUp.Timestamp, key); // Mark the new event as SystemKey as appropriate. if (isSystemKey) { keyUp.MarkSystem(); } // Mark the new event as ImeProcessed as appropriate. if (isImeProcessed) { keyUp.MarkImeProcessed(); } keyUp.RoutedEvent=Keyboard.KeyUpEvent; keyUp.ScanCode = previewKeyUp.ScanCode; keyUp.IsExtendedKey = previewKeyUp.IsExtendedKey; e.PushInput(keyUp, e.StagingItem); } } RawKeyboardInputReport keyboardInput = ExtractRawKeyboardInputReport(e, InputManager.InputReportEvent); if(keyboardInput != null) { CheckForDisconnectedFocus(); if(!e.StagingItem.Input.Handled) { // In general, this is where we promote the non-redundant // reported actions to our premier events. RawKeyboardActions actions = GetNonRedundantActions(e); // Raw --> PreviewKeyDown if((actions & RawKeyboardActions.KeyDown) == RawKeyboardActions.KeyDown) { Key key = (Key) e.StagingItem.GetData(_tagKey); if(key != Key.None) { KeyEventArgs previewKeyDown = new KeyEventArgs(this, keyboardInput.InputSource, keyboardInput.Timestamp, key); ScanCode scanCode = (ScanCode)e.StagingItem.GetData(_tagScanCode); previewKeyDown.ScanCode = scanCode.Code; previewKeyDown.IsExtendedKey = scanCode.IsExtended; if (keyboardInput.IsSystemKey) { previewKeyDown.MarkSystem(); } previewKeyDown.RoutedEvent=Keyboard.PreviewKeyDownEvent; e.PushInput(previewKeyDown, e.StagingItem); } } // Raw --> PreviewKeyUp if((actions & RawKeyboardActions.KeyUp) == RawKeyboardActions.KeyUp) { Key key = (Key) e.StagingItem.GetData(_tagKey); if(key != Key.None) { KeyEventArgs previewKeyUp = new KeyEventArgs(this, keyboardInput.InputSource, keyboardInput.Timestamp, key); ScanCode scanCode = (ScanCode)e.StagingItem.GetData(_tagScanCode); previewKeyUp.ScanCode = scanCode.Code; previewKeyUp.IsExtendedKey = scanCode.IsExtended; if (keyboardInput.IsSystemKey) { previewKeyUp.MarkSystem(); } previewKeyUp.RoutedEvent=Keyboard.PreviewKeyUpEvent; e.PushInput(previewKeyUp, e.StagingItem); } } } // Deactivate if((keyboardInput.Actions & RawKeyboardActions.Deactivate) == RawKeyboardActions.Deactivate) { if(IsActive) { _activeSource = null; // Even if handled, a keyboard deactivate results in a lost focus. ChangeFocus(null, e.StagingItem.Input.Timestamp); } } } } ////// Critical: accesses the StagingInput /// [SecurityCritical] 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; } 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; } // private bool CheckForDisconnectedFocus() { bool wasDisconnected = false; if(InputElement.GetRootVisual (_focus as DependencyObject) != _focusRootVisual) { wasDisconnected = true; Focus (null); } return wasDisconnected; } ////// Critical: accesses critical data (_inputSource) /// TreatAsSafe: doesn't expose critical data, just returns true/false. /// internal bool IsActive { [SecurityCritical, SecurityTreatAsSafe] get { return _activeSource != null && _activeSource.Value != null; } } private DeferredElementTreeState FocusTreeState { get { if (_focusTreeState == null) { _focusTreeState = new DeferredElementTreeState(); } return _focusTreeState; } } private SecurityCriticalDataClass_inputManager; private SecurityCriticalDataClass _activeSource; private DependencyObject _focus; private DeferredElementTreeState _focusTreeState; private DependencyObject _forceTarget; private DependencyObject _focusRootVisual; private Key _previousKey; private DependencyPropertyChangedEventHandler _isEnabledChangedEventHandler; private DependencyPropertyChangedEventHandler _isVisibleChangedEventHandler; private DependencyPropertyChangedEventHandler _focusableChangedEventHandler; private DispatcherOperationCallback _reevaluateFocusCallback; private DispatcherOperation _reevaluateFocusOperation; // Data tags for information we pass around the staging area. private object _tagNonRedundantActions = new object(); private object _tagKey = new object(); private object _tagScanCode = new object(); private class ScanCode { internal ScanCode(int code, bool isExtended) { _code = code; _isExtended = isExtended; } internal int Code {get {return _code;}} internal bool IsExtended {get {return _isExtended;}} private readonly int _code; private readonly bool _isExtended; } // private SecurityCriticalData _textcompositionManager; // TextServicesManager handles KeyDown -> IME composition conversion. /// /// This data is risky to give out since it is got under an elevation /// and can be used for risky operations /// private SecurityCriticalDataClass_TsfManager; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SecurityRuntime.cs
- MouseActionValueSerializer.cs
- StateDesigner.TransitionInfo.cs
- BuildManagerHost.cs
- Wizard.cs
- KeyInterop.cs
- TemplateContainer.cs
- StorageComplexTypeMapping.cs
- DivideByZeroException.cs
- ScaleTransform.cs
- HelpInfo.cs
- HtmlElementErrorEventArgs.cs
- XmlDownloadManager.cs
- InternalRelationshipCollection.cs
- manifestimages.cs
- ErrorHandler.cs
- HighlightVisual.cs
- DocumentApplicationJournalEntry.cs
- Vector3D.cs
- InlineCategoriesDocument.cs
- BitmapEffectState.cs
- FloaterParagraph.cs
- SymmetricKey.cs
- CompoundFileReference.cs
- OrderByQueryOptionExpression.cs
- MaskDescriptors.cs
- ZipIOLocalFileBlock.cs
- IntegerCollectionEditor.cs
- Win32Exception.cs
- HtmlTableRowCollection.cs
- _UriTypeConverter.cs
- RegexStringValidator.cs
- SettingsPropertyValueCollection.cs
- TransformationRules.cs
- TemplateApplicationHelper.cs
- HijriCalendar.cs
- CommandManager.cs
- NumberFormatInfo.cs
- CodeNamespaceImportCollection.cs
- InternalConfigHost.cs
- DurableRuntimeValidator.cs
- AssemblySettingAttributes.cs
- TextDecorationCollection.cs
- LoginUtil.cs
- FontResourceCache.cs
- DataGrid.cs
- SqlDeflator.cs
- DataSet.cs
- infer.cs
- QueryGeneratorBase.cs
- SystemWebSectionGroup.cs
- HttpModulesSection.cs
- GuidelineSet.cs
- KeyEventArgs.cs
- TimeIntervalCollection.cs
- Point4D.cs
- TextRenderer.cs
- MimeTypeAttribute.cs
- ZipFileInfoCollection.cs
- SqlDataRecord.cs
- WebHttpSecurity.cs
- ClientFormsAuthenticationMembershipProvider.cs
- EntityDataSourceWrapper.cs
- PackageRelationshipCollection.cs
- NetworkStream.cs
- MatrixAnimationUsingKeyFrames.cs
- OracleConnectionStringBuilder.cs
- EdmValidator.cs
- VirtualPath.cs
- DockPatternIdentifiers.cs
- DateTimeConverter2.cs
- Int32EqualityComparer.cs
- Profiler.cs
- SessionStateModule.cs
- CheckBoxRenderer.cs
- WorkflowEventArgs.cs
- Rules.cs
- WebServiceMethodData.cs
- SystemException.cs
- AccessViolationException.cs
- RuleInfoComparer.cs
- RSAProtectedConfigurationProvider.cs
- EmptyReadOnlyDictionaryInternal.cs
- TreeNodeCollection.cs
- CryptoHandle.cs
- ChainOfResponsibility.cs
- DataStreamFromComStream.cs
- Formatter.cs
- XmlCodeExporter.cs
- TextDecorationLocationValidation.cs
- TraceContextRecord.cs
- DataServiceProcessingPipeline.cs
- Code.cs
- HtmlButton.cs
- TypeListConverter.cs
- KeyPullup.cs
- QueryReaderSettings.cs
- AuthorizationRuleCollection.cs
- MachineSettingsSection.cs
- SystemIcmpV6Statistics.cs