HwndKeyboardInputProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / System / Windows / InterOp / HwndKeyboardInputProvider.cs / 2 / HwndKeyboardInputProvider.cs

                            using System.Windows.Input; 
using System.Windows.Media;
using System.Windows.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices; 
using System.Security;
using System.Security.Permissions; 
using MS.Utility; 
using MS.Internal;
using MS.Win32; 
using MS.Internal.PresentationCore;

using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID; 

namespace System.Windows.Interop 
{ 

    internal sealed class HwndKeyboardInputProvider : DispatcherObject, IKeyboardInputProvider, IDisposable 
    {
        /// 
        ///     Accesses and store critical data. This class is also critical (_site and _source)
        ///  
        [SecurityCritical]
        internal HwndKeyboardInputProvider(HwndSource source) 
        { 
            (new UIPermission(PermissionState.Unrestricted)).Assert();
            try //Blessed assert for InputManager.Current.RegisterInputProvider 
            {
                _site = new SecurityCriticalDataClass(InputManager.Current.RegisterInputProvider(this));
            }
            finally 
            {
                UIPermission.RevertAssert(); 
            } 
            _source = new SecurityCriticalDataClass(source);
        } 



        ///  
        ///     Critical:This class accesses critical data, _site.
        ///     TreatAsSafe: This class does not expose the critical data 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        public void Dispose() 
        {
            if(_site != null)
            {
                _site.Value.Dispose(); 
                _site = null;
            } 
            _source = null; 
        }
 
        public void OnRootChanged(Visual oldRoot, Visual newRoot)
        {
            if(_active && newRoot != null)
            { 
                Keyboard.Focus(null); // internally we will set the focus to the root.
            } 
        } 
        /// 
        ///     Critical: As this accesses critical data HwndSource 
        ///     TreatAsSafe:Information about whether a given input provider services
        ///     a visual is safe to expose. This method does not expose the critical data either.
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        bool IInputProvider.ProvidesInputForRootVisual(Visual v)
        { 
            Debug.Assert( null != _source ); 

            return _source.Value.RootVisual == v; 
        }

        void IInputProvider.NotifyDeactivate()
        { 
            _active        = false;
            _partialActive = false; 
        } 

        ///  
        ///     SecurityCritical: This code calls into GetWindowLong/GetFocus both of which are
        ///     critical.It also retrieves the handle to the current
        ///     window that has focus.Additionally it also calls into SetFocus which also
        ///     returns a critical resouce in the form of a window handle. In this case all that is 
        ///     retrieved is the extended window style and that data is not exposed.
        ///     It is simply used to detect if the window is set to WS_EX_NOACTIVATE. 
        ///     The risky operation here is the call to SetFocus. 
        /// 
        [SecurityCritical] 
        bool IKeyboardInputProvider.AcquireFocus()
        {
            bool success = false;
 
            Debug.Assert( null != _source );
 
            try 
            {
                int windowStyle = UnsafeNativeMethods.GetWindowLong(new HandleRef(this, _source.Value.CriticalHandle), NativeMethods.GWL_EXSTYLE); 
                if((windowStyle & NativeMethods.WS_EX_NOACTIVATE) == NativeMethods.WS_EX_NOACTIVATE)
                {
                    // If this window has the WS_EX_NOACTIVATE style, then we do
                    // not request keyboard focus.  Doing so will actually activate 
                    // the window.  If this window is part of a thread with other
                    // windows, keyboard input from them can actually be directed 
                    // to elements within this window.  Menus/ComboBoxes use this. 
                }
                else 
                {
                    // Attempt to set the focus to ourselves.
                    //
                    // However, there are scenarios where this won't work: if a 
                    // worker thread calls this API, Win32 will ignore it.  If
                    // we are running while a window that a different thread 
                    // created has focus, then Win32 will also ignore it. 

                    // we do not want the resulting WM_SETFOCUS message 
                    // to give focus to a child window
                    _restoreFocusWindow = IntPtr.Zero;
                    _restoreFocus = null;
 
                    UnsafeNativeMethods.SetFocus(new HandleRef(this, _source.Value.CriticalHandle));
                } 
 
                // We can only claim the attempt to acquire focus succeeded if
                // one of our windows has focus.  In that case, keyboard input 
                // will get properly forwarded to the element.
                if(!_active)
                {
                    IntPtr focus = UnsafeNativeMethods.GetFocus(); 
                    success = IsOurWindow(focus);
                } 
                else 
                {
                    success = true; 
                }
            }
            catch(System.ComponentModel.Win32Exception)
            { 
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetFocus failed!");
            } 
 
            return success;
        } 
        //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647
        /// 
        ///     Critical: This code is critical since it handles all keyboard messages and could be used to spoof input
        ///  
        [SecurityCritical]
        internal IntPtr FilterMessage(IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled) 
        { 
            IntPtr result = IntPtr.Zero ;
 
            // It is possible to be re-entered during disposal.  Just return.
            if(null == _source || null == _source.Value)
            {
                return result; 
            }
 
            _msgTime = 0; 
            try
            { 
                _msgTime = SafeNativeMethods.GetMessageTime();
            }
            catch(System.ComponentModel.Win32Exception)
            { 
                System.Diagnostics.Debug.WriteLine("HwndKeyboardInputProvider: GetMessageTime failed!");
            } 
 
            switch(message)
            { 
                // WM_KEYDOWN is sent when a nonsystem key is pressed.
                // A nonsystem key is a key that is pressed when the ALT key
                // is not pressed.
                // WM_SYSKEYDOWN is sent when a system key is pressed. 
                case NativeMethods.WM_SYSKEYDOWN:
                case NativeMethods.WM_KEYDOWN: 
                { 
                    // If we have a IKeyboardInputSite, then we should have already
                    // called ProcessKeyDown (from TranslateAccelerator) 
                    // But there are several paths (our message pump / app's message
                    // pump) where we do (or don't) call through IKeyboardInputSink.
                    // So the best way is to just check here if we already did it.
                    if(_source.Value.IsRepeatedKeyboardMessage(hwnd, message, wParam, lParam)) 
                    {
                        break; 
                    } 

                    // We will use the current time before generating KeyDown events so we can filter 
                    // the later posted WM_CHAR.
                    int currentTime = 0;
                    try
                    { 
                        currentTime = SafeNativeMethods.GetTickCount();
                    } 
                    catch(System.ComponentModel.Win32Exception) 
                    {
                        System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetTickCount failed!"); 
                    }

                    // MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS
                    // In case a nested message pump is used before we return 
                    // from processing this message, we disable processing the
                    // next WM_CHAR message because if the code pumps messages 
                    // it should really mark the message as handled. 
                    HwndSource._eatCharMessages = true;
                    DispatcherOperation restoreCharMessages = Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(HwndSource.RestoreCharMessages), null); 

                    MSG msg = new MSG(hwnd, message, wParam, lParam, _msgTime, 0, 0);
                    ProcessKeyAction(ref msg, ref handled);
 
                    if(!handled)
                    { 
                        // MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS 
                        // We did not handle the WM_KEYDOWN, so it is OK to process WM_CHAR messages.
                        // We can also abort the pending restore operation since we don't need it. 
                        HwndSource._eatCharMessages = false;
                        restoreCharMessages.Abort();
                    }
 
                    // System.Console.WriteLine("KEYDOWN(message={0}, wParam={1})={2}", message, wParam, handled);
                } 
                break; 

                // WM_KEYUP is sent when a nonsystem key is released. 
                // A nonsystem key is a key that is pressed when the ALT key
                // is not pressed.
                // WM_SYSKEYUP is sent when a system key is released.
                case NativeMethods.WM_SYSKEYUP: 
                case NativeMethods.WM_KEYUP:
                { 
                    if(_source.Value.IsRepeatedKeyboardMessage(hwnd, message, wParam, lParam)) 
                    {
                        break; 
                    }

                    MSG msg = new MSG(hwnd, message, wParam, lParam, _msgTime, 0, 0);
                    ProcessKeyAction(ref msg, ref handled); 
                    // System.Console.WriteLine("KEYUP  (message={0}, wParam={1})={2}", message, wParam, handled);
                } 
                break; 

                // 

                case NativeMethods.WM_CHAR:
                case NativeMethods.WM_DEADCHAR:
                case NativeMethods.WM_SYSCHAR: 
                case NativeMethods.WM_SYSDEADCHAR:
                { 
                    if(_source.Value.IsRepeatedKeyboardMessage(hwnd, message, wParam, lParam)) 
                    {
                        break; 
                    }

                    // MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS
                    if(HwndSource._eatCharMessages) 
                    {
                        break; 
                    } 

                    ProcessTextInputAction(hwnd, message, wParam, lParam, ref handled); 
                    // System.Console.WriteLine("CHAR(message={0}, wParam={1})={2}", message, wParam, handled);
                }
                break;
 
                case NativeMethods.WM_EXITMENULOOP:
                case NativeMethods.WM_EXITSIZEMOVE: 
                { 
                    // MITIGATION: KEYBOARD_STATE_OUT_OF_[....]
                    // 
                    // Avalon relies on keeping it's copy of the keyboard
                    // state.  This is for a number of reasons, including that
                    // we need to be able to give this state to worker threads.
                    // 
                    // There are a number of cases where Win32 eats the
                    // keyboard messages, and this can cause our keyboard 
                    // state to become stale.  Obviously this can happen when 
                    // another app is in the foreground, but we handle that
                    // by re-synching our keyboard state when we get focus. 
                    //
                    // Other times are when Win32 enters a nested loop.  While
                    // any one could enter a nested loop at any time for any
                    // reason, Win32 is nice enough to let us know when it is 
                    // finished with the two common loops: menus and sizing.
                    // We re-[....] our keyboard device in response to these. 
                    // 
                    if(_active)
                    { 
                        _partialActive = true;

                        ReportInput(hwnd,
                                    InputMode.Foreground, 
                                    _msgTime,
                                    RawKeyboardActions.Activate, 
                                    0, 
                                    false,
                                    false, 
                                    0);
                    }
                }
                break; 

                // WM_SETFOCUS is sent immediately after focus is granted. 
                // This is our clue that the keyboard is active. 
                case NativeMethods.WM_SETFOCUS:
                { 
                    if(!_active)
                    {
                        // Console.WriteLine("WM_SETFOCUS");
 
                        ReportInput(hwnd,
                                    InputMode.Foreground, 
                                    _msgTime, 
                                    RawKeyboardActions.Activate,
                                    0, 
                                    false,
                                    false,
                                    0);
 
                        // MITIGATION: KEYBOARD_STATE_OUT_OF_[....]
                        // 
                        // 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.
                        // 
                        _partialActive = true; 

                        // Restore the keyboard focus to the child window or element that had 
                        // the focus before we last lost Win32 focus.  If nothing
                        // had focus before, set it to null.
                        if (_restoreFocusWindow != IntPtr.Zero)
                        { 
                            IntPtr hwndRestoreFocus = _restoreFocusWindow;
                            _restoreFocusWindow = IntPtr.Zero; 
 
                            UnsafeNativeMethods.TrySetFocus(new HandleRef(this, hwndRestoreFocus), ref hwndRestoreFocus);
                        } 
                        else
                        {
                            IInputElement restoreFocus = _restoreFocus;
                            _restoreFocus = null; 

                            Keyboard.Focus(restoreFocus); 
                        } 
                    }
 
                    handled = true;
                }
                break;
 
                // WM_KILLFOCUS is sent immediately before focus is removed.
                // This is our clue that the keyboard is inactive. 
                case NativeMethods.WM_KILLFOCUS: 
                {
                    if(_active  &&  wParam != _source.Value.CriticalHandle ) 
                    {
                        // Console.WriteLine("WM_KILLFOCUS");

                        // when the window that's acquiring focus (wParam) is 
                        // a descendant of our window, remember the immediate
                        // child so that we can restore focus to it. 
                        _restoreFocusWindow = GetImmediateChildFor((IntPtr)wParam, _source.Value.CriticalHandle); 

                        // Remember the element that currently has keyboard 
                        // focus so that we can restore focus to it when this
                        // window gets Win32 keyboard focus again.
                        if (_restoreFocusWindow == IntPtr.Zero)
                        { 
                            _restoreFocus = Keyboard.FocusedElement;
                        } 
 
                        PossiblyDeactivate((IntPtr)wParam);
 
                    }

                    handled = true;
                } 
                break;
 
                // WM_UPDATEUISTATE is sent when the user presses ALT, expecting 
                // the app to display accelerator keys.  We don't always hear the
                // keystroke - another message loop may handle it.  So report it 
                // here.
                case NativeMethods.WM_UPDATEUISTATE:
                {
                    RawUIStateInputReport report = 
                        new RawUIStateInputReport(_source.Value,
                                                   InputMode.Foreground, 
                                                   _msgTime, 
                                                   (RawUIStateActions)NativeMethods.SignedLOWORD((int)wParam),
                                                   (RawUIStateTargets)NativeMethods.SignedHIWORD((int)wParam)); 

                    _site.Value.ReportInput(report);

                    handled = true; 
                }
                break; 
            } 

            if (handled && EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal)) 
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.HWNDMESSAGEGUID),
                                                     MS.Utility.EventType.Info,
                                                     Dispatcher.GetHashCode(), 
                                                     hwnd.ToInt64(),
                                                     message, 
                                                     (int)wParam, 
                                                     (int)lParam);
            } 

            return result;
        }
 
        /// 
        ///     Critical:This can be used to spoof input 
        ///  
        [SecurityCritical]
        internal void ProcessKeyAction(ref MSG msg, ref bool handled) 
        {
            // Remember the last message
            MSG previousMSG = ComponentDispatcher.UnsecureCurrentKeyboardMessage;
            ComponentDispatcher.UnsecureCurrentKeyboardMessage = msg; 

            try 
            { 
                int virtualKey = GetVirtualKey(msg.wParam, msg.lParam);
                int scanCode = GetScanCode(msg.wParam, msg.lParam); 
                bool isExtendedKey = IsExtendedKey(msg.lParam);
                bool isSystemKey = ((msg.message == NativeMethods.WM_SYSKEYDOWN) || (msg.message == NativeMethods.WM_SYSKEYUP));
                RawKeyboardActions action = GetKeyUpKeyDown(msg.message);
 
                // Console.WriteLine("WM_KEYDOWN: " + virtualKey + "," + scanCode);
                handled = ReportInput(msg.hwnd, 
                                      InputMode.Foreground, 
                                      _msgTime,
                                      action, 
                                      scanCode,
                                      isExtendedKey,
                                      isSystemKey,
                                      virtualKey); 
            }
            finally 
            { 
                // Restore the last message
                ComponentDispatcher.UnsecureCurrentKeyboardMessage = previousMSG; 
            }
        }

        /// 
        /// Critical - calls a critical method _source.Value.
        /// 
        [SecurityCritical ] 
        internal void ProcessTextInputAction(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        { 
            char charcode = (char)wParam;
            bool isDeadChar = ((msg == NativeMethods.WM_DEADCHAR) || (msg == NativeMethods.WM_SYSDEADCHAR));
            bool isSystemChar = ((msg == NativeMethods.WM_SYSCHAR) || (msg == NativeMethods.WM_SYSDEADCHAR));
            bool isControlChar = false; 

            // If the control is pressed but Alt is not, the char is control char. 
            try 
            {
                if (((UnsafeNativeMethods.GetKeyState(NativeMethods.VK_CONTROL) & 0x8000) != 0) && 
                    ((UnsafeNativeMethods.GetKeyState(NativeMethods.VK_MENU) & 0x8000) == 0) &&
                    Char.IsControl(charcode))
                {
                    isControlChar = true; 
                }
            } 
            catch(System.ComponentModel.Win32Exception) 
            {
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetKeyState failed!"); 
            }

            RawTextInputReport report = new RawTextInputReport(_source.Value ,
                                                               InputMode.Foreground, 
                                                               _msgTime,
                                                               isDeadChar, 
                                                               isSystemChar, 
                                                               isControlChar,
                                                               charcode); 

            handled = _site.Value.ReportInput(report);
        }
 
        internal static int GetVirtualKey(IntPtr wParam, IntPtr lParam)
        { 
            int virtualKey = NativeMethods.IntPtrToInt32( wParam); 
            int scanCode = 0;
            int keyData = NativeMethods.IntPtrToInt32(lParam); 

            // Find the left/right instance SHIFT keys.
            if(virtualKey == NativeMethods.VK_SHIFT)
            { 
                scanCode = (keyData & 0xFF0000) >> 16;
                try 
                { 
                    virtualKey = SafeNativeMethods.MapVirtualKey(scanCode, 3);
                    if(virtualKey == 0) 
                    {
                        virtualKey = NativeMethods.VK_LSHIFT;
                    }
                } 
                catch(System.ComponentModel.Win32Exception)
                { 
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: MapVirtualKey failed!"); 

                    virtualKey = NativeMethods.VK_LSHIFT; 
                }
            }

            // Find the left/right instance ALT keys. 
            if(virtualKey == NativeMethods.VK_MENU)
            { 
                bool right = ((keyData & 0x1000000) >> 24) != 0; 

                if(right) 
                {
                    virtualKey = NativeMethods.VK_RMENU;
                }
                else 
                {
                    virtualKey = NativeMethods.VK_LMENU; 
                } 
            }
 
            // Find the left/right instance CONTROL keys.
            if(virtualKey == NativeMethods.VK_CONTROL)
            {
                bool right = ((keyData & 0x1000000) >> 24) != 0; 

                if(right) 
                { 
                    virtualKey = NativeMethods.VK_RCONTROL;
                } 
                else
                {
                    virtualKey = NativeMethods.VK_LCONTROL;
                } 
            }
 
            return virtualKey; 
        }
 
        internal static int GetScanCode(IntPtr wParam, IntPtr lParam)
        {
            int keyData = NativeMethods.IntPtrToInt32(lParam);
 
            int scanCode = (keyData & 0xFF0000) >> 16;
            if(scanCode == 0) 
            { 
                try
                { 
                    int virtualKey = GetVirtualKey(wParam, lParam);
                    scanCode = SafeNativeMethods.MapVirtualKey(virtualKey, 0);
                }
                catch(System.ComponentModel.Win32Exception) 
                {
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: MapVirtualKey failed!"); 
                } 
            }
 
            return scanCode;
        }

        internal static bool IsExtendedKey(IntPtr lParam) 
        {
            int keyData = NativeMethods.IntPtrToInt32(lParam); 
            return ((keyData & 0x01000000) != 0) ? true : false; 
        }
 
        ///
        ///     Returns the set of modifier keys currently pressed as determined by calling to Win32
        ///
        /// 
        ///     Marked as FriendAccessAllowed so HwndHost in PresentationFramework can call it
        /// 
        /// 
        ///     Critical: It calls an UnsafeNativeMethod (GetKeyState).
        ///     TreatAsSafe: It's safe to return whether shift, control or alt keys are being pressed or not. 
        ///
        [FriendAccessAllowed]
        [SecurityCritical,SecurityTreatAsSafe]
        internal static ModifierKeys GetSystemModifierKeys() 
        {
            ModifierKeys modifierKeys = ModifierKeys.None; 
 
            short keyState = UnsafeNativeMethods.GetKeyState(NativeMethods.VK_SHIFT);
            if((keyState & 0x8000) == 0x8000) 
            {
                modifierKeys |= ModifierKeys.Shift;
            }
 
            keyState = UnsafeNativeMethods.GetKeyState(NativeMethods.VK_CONTROL);
            if((keyState & 0x8000) == 0x8000) 
            { 
                modifierKeys |= ModifierKeys.Control;
            } 

            keyState = UnsafeNativeMethods.GetKeyState(NativeMethods.VK_MENU);
            if((keyState & 0x8000) == 0x8000)
            { 
                modifierKeys |= ModifierKeys.Alt;
            } 
 
            return modifierKeys;
        } 

        private RawKeyboardActions GetKeyUpKeyDown(int msg)
        {
            if(  msg == NativeMethods.WM_KEYDOWN || msg == NativeMethods.WM_SYSKEYDOWN ) 
                return RawKeyboardActions.KeyDown;
            if(  msg == NativeMethods.WM_KEYUP || msg == NativeMethods.WM_SYSKEYUP ) 
                return RawKeyboardActions.KeyUp; 
            throw new ArgumentException(SR.Get(SRID.OnlyAcceptsKeyMessages));
        } 

        /// 
        ///     Critical: This code causes this window to loose focus not ok to expose
        ///               It also calls into a critical code path. 
        /// 
        [SecurityCritical] 
        private void PossiblyDeactivate(IntPtr hwndFocus) 
        {
            Debug.Assert( null != _source ); 

            // We are now longer active ourselves, but it is possible that the
            // window the keyboard is going to intereact with is in the same
            // Dispatcher as ourselves.  If so, we don't want to deactivate the 
            // keyboard input stream because the other window hasn't activated
            // it yet, and it may result in the input stream "flickering" between 
            // active/inactive/active.  This is ugly, so we try to supress the 
            // uneccesary transitions.
            // 
            bool deactivate = !IsOurWindow(hwndFocus);

            // This window itself should not be active anymore.
            _active = false; 

            // Only deactivate the keyboard input stream if needed. 
            if(deactivate) 
            {
                ReportInput(_source.Value.CriticalHandle, 
                            InputMode.Foreground,
                            _msgTime,
                            RawKeyboardActions.Deactivate,
                            0, 
                            false,
                            false, 
                            0); 
            }
        } 

        /// 
        ///     Critical: This code does not store any critical data, it accesses PresentationSource
        ///     TreatAsSafe: This information is safe to expose 
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        private bool IsOurWindow(IntPtr hwnd) 
        {
            bool isOurWindow = false; 

            Debug.Assert( null != _source );

            if(hwnd != IntPtr.Zero) 
            {
                HwndSource hwndSource = HwndSource.CriticalFromHwnd(hwnd); 
                if(hwndSource != null) 
                {
                    if(hwndSource.Dispatcher == _source.Value.Dispatcher) 
                    {
                        // The window has the same dispatcher, must be ours.
                        isOurWindow = true;
                    } 
                    else
                    { 
                        // The window has a different dispatcher, must not be ours. 
                        isOurWindow = false;
                    } 
                }
                else
                {
                    // The window is non-Avalon. 
                    // Such windows are never ours.
                    isOurWindow = false; 
                } 
            }
            else 
            {
                // This is not even a window.
                isOurWindow = false;
            } 

            return isOurWindow; 
        } 

        // return the immediate child (if any) of hwndRoot that governs the 
        // given hwnd.  If hwnd is not a descendant of hwndRoot, return 0.
        /// 
        ///     Critical:This method calls critical methods
        ///  
        [SecurityCritical]
        private IntPtr GetImmediateChildFor(IntPtr hwnd, IntPtr hwndRoot) 
        { 
            while (hwnd != IntPtr.Zero)
            { 
                // We only care to restore focus to child windows. Notice that WS_POPUP
                // windows also have parents but we do not want to track those here.

                int windowStyle = UnsafeNativeMethods.GetWindowLong(new HandleRef(this,hwnd), NativeMethods.GWL_STYLE); 
                if((windowStyle & NativeMethods.WS_CHILD) == 0)
                { 
                    break; 
                }
 
                IntPtr hwndParent = UnsafeNativeMethods.GetParent(new HandleRef(this, hwnd));

                if (hwndParent == hwndRoot)
                { 
                    return hwnd;
                } 
 
                hwnd = hwndParent;
            } 

            return IntPtr.Zero;
        }
 
        /// 
        ///     Critical:This code can cause input simulation and hence is critical. 
        ///     The current code path is only hit under RootBrowserWindow scenario for now. 
        /// 
        [SecurityCritical] 
        private bool ReportInput(
            IntPtr hwnd,
            InputMode mode,
            int timestamp, 
            RawKeyboardActions actions,
            int scanCode, 
            bool isExtendedKey, 
            bool isSystemKey,
            int virtualKey) 
        {
            Debug.Assert( null != _source );

            // The first event should also activate the keyboard device. 
            if((actions & RawKeyboardActions.Deactivate) == 0)
            { 
                if(!_active || _partialActive) 
                {
                    try 
                    {
                        // Include the activation action.
                        actions |= RawKeyboardActions.Activate;
 
                        // Remember that we are active.
                        _active = true; 
                        _partialActive = false; 
                    }
                    catch(System.ComponentModel.Win32Exception) 
                    {
                        System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetKeyboardState failed!");

                        // We'll go ahead and report the input, but we'll try to "activate" next time. 
                    }
                } 
            } 

            // Get the extra information sent along with the message. 
            IntPtr extraInformation = IntPtr.Zero;
            try
            {
                extraInformation = UnsafeNativeMethods.GetMessageExtraInfo(); 
            }
            catch(System.ComponentModel.Win32Exception) 
            { 
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetMessageExtraInfo failed!");
            } 

            RawKeyboardInputReport report = new RawKeyboardInputReport(_source.Value,
                                                                       mode,
                                                                       timestamp, 
                                                                       actions,
                                                                       scanCode, 
                                                                       isExtendedKey, 
                                                                       isSystemKey,
                                                                       virtualKey, 
                                                                       extraInformation);


            bool handled = _site.Value.ReportInput(report); 

            return handled; 
        } 

        private int  _msgTime; 
        /// 
        /// This is got under an elevation and is hence critical. This data is not ok to expose.
        /// 
        private SecurityCriticalDataClass _source; 
        /// 
        /// This is got under an elevation and is hence critical.This data is not ok to expose. 
        ///  
        private SecurityCriticalDataClass _site;
        private IInputElement _restoreFocus; 
        /// 
        /// This is got under an elevation and is hence critical.This data is not ok to expose.
        /// 
        [SecurityCritical] 
        private IntPtr _restoreFocusWindow;
        private bool _active; 
        private bool _partialActive; 
    }
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
using System.Windows.Input; 
using System.Windows.Media;
using System.Windows.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices; 
using System.Security;
using System.Security.Permissions; 
using MS.Utility; 
using MS.Internal;
using MS.Win32; 
using MS.Internal.PresentationCore;

using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID; 

namespace System.Windows.Interop 
{ 

    internal sealed class HwndKeyboardInputProvider : DispatcherObject, IKeyboardInputProvider, IDisposable 
    {
        /// 
        ///     Accesses and store critical data. This class is also critical (_site and _source)
        ///  
        [SecurityCritical]
        internal HwndKeyboardInputProvider(HwndSource source) 
        { 
            (new UIPermission(PermissionState.Unrestricted)).Assert();
            try //Blessed assert for InputManager.Current.RegisterInputProvider 
            {
                _site = new SecurityCriticalDataClass(InputManager.Current.RegisterInputProvider(this));
            }
            finally 
            {
                UIPermission.RevertAssert(); 
            } 
            _source = new SecurityCriticalDataClass(source);
        } 



        ///  
        ///     Critical:This class accesses critical data, _site.
        ///     TreatAsSafe: This class does not expose the critical data 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        public void Dispose() 
        {
            if(_site != null)
            {
                _site.Value.Dispose(); 
                _site = null;
            } 
            _source = null; 
        }
 
        public void OnRootChanged(Visual oldRoot, Visual newRoot)
        {
            if(_active && newRoot != null)
            { 
                Keyboard.Focus(null); // internally we will set the focus to the root.
            } 
        } 
        /// 
        ///     Critical: As this accesses critical data HwndSource 
        ///     TreatAsSafe:Information about whether a given input provider services
        ///     a visual is safe to expose. This method does not expose the critical data either.
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        bool IInputProvider.ProvidesInputForRootVisual(Visual v)
        { 
            Debug.Assert( null != _source ); 

            return _source.Value.RootVisual == v; 
        }

        void IInputProvider.NotifyDeactivate()
        { 
            _active        = false;
            _partialActive = false; 
        } 

        ///  
        ///     SecurityCritical: This code calls into GetWindowLong/GetFocus both of which are
        ///     critical.It also retrieves the handle to the current
        ///     window that has focus.Additionally it also calls into SetFocus which also
        ///     returns a critical resouce in the form of a window handle. In this case all that is 
        ///     retrieved is the extended window style and that data is not exposed.
        ///     It is simply used to detect if the window is set to WS_EX_NOACTIVATE. 
        ///     The risky operation here is the call to SetFocus. 
        /// 
        [SecurityCritical] 
        bool IKeyboardInputProvider.AcquireFocus()
        {
            bool success = false;
 
            Debug.Assert( null != _source );
 
            try 
            {
                int windowStyle = UnsafeNativeMethods.GetWindowLong(new HandleRef(this, _source.Value.CriticalHandle), NativeMethods.GWL_EXSTYLE); 
                if((windowStyle & NativeMethods.WS_EX_NOACTIVATE) == NativeMethods.WS_EX_NOACTIVATE)
                {
                    // If this window has the WS_EX_NOACTIVATE style, then we do
                    // not request keyboard focus.  Doing so will actually activate 
                    // the window.  If this window is part of a thread with other
                    // windows, keyboard input from them can actually be directed 
                    // to elements within this window.  Menus/ComboBoxes use this. 
                }
                else 
                {
                    // Attempt to set the focus to ourselves.
                    //
                    // However, there are scenarios where this won't work: if a 
                    // worker thread calls this API, Win32 will ignore it.  If
                    // we are running while a window that a different thread 
                    // created has focus, then Win32 will also ignore it. 

                    // we do not want the resulting WM_SETFOCUS message 
                    // to give focus to a child window
                    _restoreFocusWindow = IntPtr.Zero;
                    _restoreFocus = null;
 
                    UnsafeNativeMethods.SetFocus(new HandleRef(this, _source.Value.CriticalHandle));
                } 
 
                // We can only claim the attempt to acquire focus succeeded if
                // one of our windows has focus.  In that case, keyboard input 
                // will get properly forwarded to the element.
                if(!_active)
                {
                    IntPtr focus = UnsafeNativeMethods.GetFocus(); 
                    success = IsOurWindow(focus);
                } 
                else 
                {
                    success = true; 
                }
            }
            catch(System.ComponentModel.Win32Exception)
            { 
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetFocus failed!");
            } 
 
            return success;
        } 
        //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647
        /// 
        ///     Critical: This code is critical since it handles all keyboard messages and could be used to spoof input
        ///  
        [SecurityCritical]
        internal IntPtr FilterMessage(IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled) 
        { 
            IntPtr result = IntPtr.Zero ;
 
            // It is possible to be re-entered during disposal.  Just return.
            if(null == _source || null == _source.Value)
            {
                return result; 
            }
 
            _msgTime = 0; 
            try
            { 
                _msgTime = SafeNativeMethods.GetMessageTime();
            }
            catch(System.ComponentModel.Win32Exception)
            { 
                System.Diagnostics.Debug.WriteLine("HwndKeyboardInputProvider: GetMessageTime failed!");
            } 
 
            switch(message)
            { 
                // WM_KEYDOWN is sent when a nonsystem key is pressed.
                // A nonsystem key is a key that is pressed when the ALT key
                // is not pressed.
                // WM_SYSKEYDOWN is sent when a system key is pressed. 
                case NativeMethods.WM_SYSKEYDOWN:
                case NativeMethods.WM_KEYDOWN: 
                { 
                    // If we have a IKeyboardInputSite, then we should have already
                    // called ProcessKeyDown (from TranslateAccelerator) 
                    // But there are several paths (our message pump / app's message
                    // pump) where we do (or don't) call through IKeyboardInputSink.
                    // So the best way is to just check here if we already did it.
                    if(_source.Value.IsRepeatedKeyboardMessage(hwnd, message, wParam, lParam)) 
                    {
                        break; 
                    } 

                    // We will use the current time before generating KeyDown events so we can filter 
                    // the later posted WM_CHAR.
                    int currentTime = 0;
                    try
                    { 
                        currentTime = SafeNativeMethods.GetTickCount();
                    } 
                    catch(System.ComponentModel.Win32Exception) 
                    {
                        System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetTickCount failed!"); 
                    }

                    // MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS
                    // In case a nested message pump is used before we return 
                    // from processing this message, we disable processing the
                    // next WM_CHAR message because if the code pumps messages 
                    // it should really mark the message as handled. 
                    HwndSource._eatCharMessages = true;
                    DispatcherOperation restoreCharMessages = Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(HwndSource.RestoreCharMessages), null); 

                    MSG msg = new MSG(hwnd, message, wParam, lParam, _msgTime, 0, 0);
                    ProcessKeyAction(ref msg, ref handled);
 
                    if(!handled)
                    { 
                        // MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS 
                        // We did not handle the WM_KEYDOWN, so it is OK to process WM_CHAR messages.
                        // We can also abort the pending restore operation since we don't need it. 
                        HwndSource._eatCharMessages = false;
                        restoreCharMessages.Abort();
                    }
 
                    // System.Console.WriteLine("KEYDOWN(message={0}, wParam={1})={2}", message, wParam, handled);
                } 
                break; 

                // WM_KEYUP is sent when a nonsystem key is released. 
                // A nonsystem key is a key that is pressed when the ALT key
                // is not pressed.
                // WM_SYSKEYUP is sent when a system key is released.
                case NativeMethods.WM_SYSKEYUP: 
                case NativeMethods.WM_KEYUP:
                { 
                    if(_source.Value.IsRepeatedKeyboardMessage(hwnd, message, wParam, lParam)) 
                    {
                        break; 
                    }

                    MSG msg = new MSG(hwnd, message, wParam, lParam, _msgTime, 0, 0);
                    ProcessKeyAction(ref msg, ref handled); 
                    // System.Console.WriteLine("KEYUP  (message={0}, wParam={1})={2}", message, wParam, handled);
                } 
                break; 

                // 

                case NativeMethods.WM_CHAR:
                case NativeMethods.WM_DEADCHAR:
                case NativeMethods.WM_SYSCHAR: 
                case NativeMethods.WM_SYSDEADCHAR:
                { 
                    if(_source.Value.IsRepeatedKeyboardMessage(hwnd, message, wParam, lParam)) 
                    {
                        break; 
                    }

                    // MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS
                    if(HwndSource._eatCharMessages) 
                    {
                        break; 
                    } 

                    ProcessTextInputAction(hwnd, message, wParam, lParam, ref handled); 
                    // System.Console.WriteLine("CHAR(message={0}, wParam={1})={2}", message, wParam, handled);
                }
                break;
 
                case NativeMethods.WM_EXITMENULOOP:
                case NativeMethods.WM_EXITSIZEMOVE: 
                { 
                    // MITIGATION: KEYBOARD_STATE_OUT_OF_[....]
                    // 
                    // Avalon relies on keeping it's copy of the keyboard
                    // state.  This is for a number of reasons, including that
                    // we need to be able to give this state to worker threads.
                    // 
                    // There are a number of cases where Win32 eats the
                    // keyboard messages, and this can cause our keyboard 
                    // state to become stale.  Obviously this can happen when 
                    // another app is in the foreground, but we handle that
                    // by re-synching our keyboard state when we get focus. 
                    //
                    // Other times are when Win32 enters a nested loop.  While
                    // any one could enter a nested loop at any time for any
                    // reason, Win32 is nice enough to let us know when it is 
                    // finished with the two common loops: menus and sizing.
                    // We re-[....] our keyboard device in response to these. 
                    // 
                    if(_active)
                    { 
                        _partialActive = true;

                        ReportInput(hwnd,
                                    InputMode.Foreground, 
                                    _msgTime,
                                    RawKeyboardActions.Activate, 
                                    0, 
                                    false,
                                    false, 
                                    0);
                    }
                }
                break; 

                // WM_SETFOCUS is sent immediately after focus is granted. 
                // This is our clue that the keyboard is active. 
                case NativeMethods.WM_SETFOCUS:
                { 
                    if(!_active)
                    {
                        // Console.WriteLine("WM_SETFOCUS");
 
                        ReportInput(hwnd,
                                    InputMode.Foreground, 
                                    _msgTime, 
                                    RawKeyboardActions.Activate,
                                    0, 
                                    false,
                                    false,
                                    0);
 
                        // MITIGATION: KEYBOARD_STATE_OUT_OF_[....]
                        // 
                        // 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.
                        // 
                        _partialActive = true; 

                        // Restore the keyboard focus to the child window or element that had 
                        // the focus before we last lost Win32 focus.  If nothing
                        // had focus before, set it to null.
                        if (_restoreFocusWindow != IntPtr.Zero)
                        { 
                            IntPtr hwndRestoreFocus = _restoreFocusWindow;
                            _restoreFocusWindow = IntPtr.Zero; 
 
                            UnsafeNativeMethods.TrySetFocus(new HandleRef(this, hwndRestoreFocus), ref hwndRestoreFocus);
                        } 
                        else
                        {
                            IInputElement restoreFocus = _restoreFocus;
                            _restoreFocus = null; 

                            Keyboard.Focus(restoreFocus); 
                        } 
                    }
 
                    handled = true;
                }
                break;
 
                // WM_KILLFOCUS is sent immediately before focus is removed.
                // This is our clue that the keyboard is inactive. 
                case NativeMethods.WM_KILLFOCUS: 
                {
                    if(_active  &&  wParam != _source.Value.CriticalHandle ) 
                    {
                        // Console.WriteLine("WM_KILLFOCUS");

                        // when the window that's acquiring focus (wParam) is 
                        // a descendant of our window, remember the immediate
                        // child so that we can restore focus to it. 
                        _restoreFocusWindow = GetImmediateChildFor((IntPtr)wParam, _source.Value.CriticalHandle); 

                        // Remember the element that currently has keyboard 
                        // focus so that we can restore focus to it when this
                        // window gets Win32 keyboard focus again.
                        if (_restoreFocusWindow == IntPtr.Zero)
                        { 
                            _restoreFocus = Keyboard.FocusedElement;
                        } 
 
                        PossiblyDeactivate((IntPtr)wParam);
 
                    }

                    handled = true;
                } 
                break;
 
                // WM_UPDATEUISTATE is sent when the user presses ALT, expecting 
                // the app to display accelerator keys.  We don't always hear the
                // keystroke - another message loop may handle it.  So report it 
                // here.
                case NativeMethods.WM_UPDATEUISTATE:
                {
                    RawUIStateInputReport report = 
                        new RawUIStateInputReport(_source.Value,
                                                   InputMode.Foreground, 
                                                   _msgTime, 
                                                   (RawUIStateActions)NativeMethods.SignedLOWORD((int)wParam),
                                                   (RawUIStateTargets)NativeMethods.SignedHIWORD((int)wParam)); 

                    _site.Value.ReportInput(report);

                    handled = true; 
                }
                break; 
            } 

            if (handled && EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal)) 
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.HWNDMESSAGEGUID),
                                                     MS.Utility.EventType.Info,
                                                     Dispatcher.GetHashCode(), 
                                                     hwnd.ToInt64(),
                                                     message, 
                                                     (int)wParam, 
                                                     (int)lParam);
            } 

            return result;
        }
 
        /// 
        ///     Critical:This can be used to spoof input 
        ///  
        [SecurityCritical]
        internal void ProcessKeyAction(ref MSG msg, ref bool handled) 
        {
            // Remember the last message
            MSG previousMSG = ComponentDispatcher.UnsecureCurrentKeyboardMessage;
            ComponentDispatcher.UnsecureCurrentKeyboardMessage = msg; 

            try 
            { 
                int virtualKey = GetVirtualKey(msg.wParam, msg.lParam);
                int scanCode = GetScanCode(msg.wParam, msg.lParam); 
                bool isExtendedKey = IsExtendedKey(msg.lParam);
                bool isSystemKey = ((msg.message == NativeMethods.WM_SYSKEYDOWN) || (msg.message == NativeMethods.WM_SYSKEYUP));
                RawKeyboardActions action = GetKeyUpKeyDown(msg.message);
 
                // Console.WriteLine("WM_KEYDOWN: " + virtualKey + "," + scanCode);
                handled = ReportInput(msg.hwnd, 
                                      InputMode.Foreground, 
                                      _msgTime,
                                      action, 
                                      scanCode,
                                      isExtendedKey,
                                      isSystemKey,
                                      virtualKey); 
            }
            finally 
            { 
                // Restore the last message
                ComponentDispatcher.UnsecureCurrentKeyboardMessage = previousMSG; 
            }
        }

        /// 
        /// Critical - calls a critical method _source.Value.
        /// 
        [SecurityCritical ] 
        internal void ProcessTextInputAction(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        { 
            char charcode = (char)wParam;
            bool isDeadChar = ((msg == NativeMethods.WM_DEADCHAR) || (msg == NativeMethods.WM_SYSDEADCHAR));
            bool isSystemChar = ((msg == NativeMethods.WM_SYSCHAR) || (msg == NativeMethods.WM_SYSDEADCHAR));
            bool isControlChar = false; 

            // If the control is pressed but Alt is not, the char is control char. 
            try 
            {
                if (((UnsafeNativeMethods.GetKeyState(NativeMethods.VK_CONTROL) & 0x8000) != 0) && 
                    ((UnsafeNativeMethods.GetKeyState(NativeMethods.VK_MENU) & 0x8000) == 0) &&
                    Char.IsControl(charcode))
                {
                    isControlChar = true; 
                }
            } 
            catch(System.ComponentModel.Win32Exception) 
            {
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetKeyState failed!"); 
            }

            RawTextInputReport report = new RawTextInputReport(_source.Value ,
                                                               InputMode.Foreground, 
                                                               _msgTime,
                                                               isDeadChar, 
                                                               isSystemChar, 
                                                               isControlChar,
                                                               charcode); 

            handled = _site.Value.ReportInput(report);
        }
 
        internal static int GetVirtualKey(IntPtr wParam, IntPtr lParam)
        { 
            int virtualKey = NativeMethods.IntPtrToInt32( wParam); 
            int scanCode = 0;
            int keyData = NativeMethods.IntPtrToInt32(lParam); 

            // Find the left/right instance SHIFT keys.
            if(virtualKey == NativeMethods.VK_SHIFT)
            { 
                scanCode = (keyData & 0xFF0000) >> 16;
                try 
                { 
                    virtualKey = SafeNativeMethods.MapVirtualKey(scanCode, 3);
                    if(virtualKey == 0) 
                    {
                        virtualKey = NativeMethods.VK_LSHIFT;
                    }
                } 
                catch(System.ComponentModel.Win32Exception)
                { 
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: MapVirtualKey failed!"); 

                    virtualKey = NativeMethods.VK_LSHIFT; 
                }
            }

            // Find the left/right instance ALT keys. 
            if(virtualKey == NativeMethods.VK_MENU)
            { 
                bool right = ((keyData & 0x1000000) >> 24) != 0; 

                if(right) 
                {
                    virtualKey = NativeMethods.VK_RMENU;
                }
                else 
                {
                    virtualKey = NativeMethods.VK_LMENU; 
                } 
            }
 
            // Find the left/right instance CONTROL keys.
            if(virtualKey == NativeMethods.VK_CONTROL)
            {
                bool right = ((keyData & 0x1000000) >> 24) != 0; 

                if(right) 
                { 
                    virtualKey = NativeMethods.VK_RCONTROL;
                } 
                else
                {
                    virtualKey = NativeMethods.VK_LCONTROL;
                } 
            }
 
            return virtualKey; 
        }
 
        internal static int GetScanCode(IntPtr wParam, IntPtr lParam)
        {
            int keyData = NativeMethods.IntPtrToInt32(lParam);
 
            int scanCode = (keyData & 0xFF0000) >> 16;
            if(scanCode == 0) 
            { 
                try
                { 
                    int virtualKey = GetVirtualKey(wParam, lParam);
                    scanCode = SafeNativeMethods.MapVirtualKey(virtualKey, 0);
                }
                catch(System.ComponentModel.Win32Exception) 
                {
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: MapVirtualKey failed!"); 
                } 
            }
 
            return scanCode;
        }

        internal static bool IsExtendedKey(IntPtr lParam) 
        {
            int keyData = NativeMethods.IntPtrToInt32(lParam); 
            return ((keyData & 0x01000000) != 0) ? true : false; 
        }
 
        ///
        ///     Returns the set of modifier keys currently pressed as determined by calling to Win32
        ///
        /// 
        ///     Marked as FriendAccessAllowed so HwndHost in PresentationFramework can call it
        /// 
        /// 
        ///     Critical: It calls an UnsafeNativeMethod (GetKeyState).
        ///     TreatAsSafe: It's safe to return whether shift, control or alt keys are being pressed or not. 
        ///
        [FriendAccessAllowed]
        [SecurityCritical,SecurityTreatAsSafe]
        internal static ModifierKeys GetSystemModifierKeys() 
        {
            ModifierKeys modifierKeys = ModifierKeys.None; 
 
            short keyState = UnsafeNativeMethods.GetKeyState(NativeMethods.VK_SHIFT);
            if((keyState & 0x8000) == 0x8000) 
            {
                modifierKeys |= ModifierKeys.Shift;
            }
 
            keyState = UnsafeNativeMethods.GetKeyState(NativeMethods.VK_CONTROL);
            if((keyState & 0x8000) == 0x8000) 
            { 
                modifierKeys |= ModifierKeys.Control;
            } 

            keyState = UnsafeNativeMethods.GetKeyState(NativeMethods.VK_MENU);
            if((keyState & 0x8000) == 0x8000)
            { 
                modifierKeys |= ModifierKeys.Alt;
            } 
 
            return modifierKeys;
        } 

        private RawKeyboardActions GetKeyUpKeyDown(int msg)
        {
            if(  msg == NativeMethods.WM_KEYDOWN || msg == NativeMethods.WM_SYSKEYDOWN ) 
                return RawKeyboardActions.KeyDown;
            if(  msg == NativeMethods.WM_KEYUP || msg == NativeMethods.WM_SYSKEYUP ) 
                return RawKeyboardActions.KeyUp; 
            throw new ArgumentException(SR.Get(SRID.OnlyAcceptsKeyMessages));
        } 

        /// 
        ///     Critical: This code causes this window to loose focus not ok to expose
        ///               It also calls into a critical code path. 
        /// 
        [SecurityCritical] 
        private void PossiblyDeactivate(IntPtr hwndFocus) 
        {
            Debug.Assert( null != _source ); 

            // We are now longer active ourselves, but it is possible that the
            // window the keyboard is going to intereact with is in the same
            // Dispatcher as ourselves.  If so, we don't want to deactivate the 
            // keyboard input stream because the other window hasn't activated
            // it yet, and it may result in the input stream "flickering" between 
            // active/inactive/active.  This is ugly, so we try to supress the 
            // uneccesary transitions.
            // 
            bool deactivate = !IsOurWindow(hwndFocus);

            // This window itself should not be active anymore.
            _active = false; 

            // Only deactivate the keyboard input stream if needed. 
            if(deactivate) 
            {
                ReportInput(_source.Value.CriticalHandle, 
                            InputMode.Foreground,
                            _msgTime,
                            RawKeyboardActions.Deactivate,
                            0, 
                            false,
                            false, 
                            0); 
            }
        } 

        /// 
        ///     Critical: This code does not store any critical data, it accesses PresentationSource
        ///     TreatAsSafe: This information is safe to expose 
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        private bool IsOurWindow(IntPtr hwnd) 
        {
            bool isOurWindow = false; 

            Debug.Assert( null != _source );

            if(hwnd != IntPtr.Zero) 
            {
                HwndSource hwndSource = HwndSource.CriticalFromHwnd(hwnd); 
                if(hwndSource != null) 
                {
                    if(hwndSource.Dispatcher == _source.Value.Dispatcher) 
                    {
                        // The window has the same dispatcher, must be ours.
                        isOurWindow = true;
                    } 
                    else
                    { 
                        // The window has a different dispatcher, must not be ours. 
                        isOurWindow = false;
                    } 
                }
                else
                {
                    // The window is non-Avalon. 
                    // Such windows are never ours.
                    isOurWindow = false; 
                } 
            }
            else 
            {
                // This is not even a window.
                isOurWindow = false;
            } 

            return isOurWindow; 
        } 

        // return the immediate child (if any) of hwndRoot that governs the 
        // given hwnd.  If hwnd is not a descendant of hwndRoot, return 0.
        /// 
        ///     Critical:This method calls critical methods
        ///  
        [SecurityCritical]
        private IntPtr GetImmediateChildFor(IntPtr hwnd, IntPtr hwndRoot) 
        { 
            while (hwnd != IntPtr.Zero)
            { 
                // We only care to restore focus to child windows. Notice that WS_POPUP
                // windows also have parents but we do not want to track those here.

                int windowStyle = UnsafeNativeMethods.GetWindowLong(new HandleRef(this,hwnd), NativeMethods.GWL_STYLE); 
                if((windowStyle & NativeMethods.WS_CHILD) == 0)
                { 
                    break; 
                }
 
                IntPtr hwndParent = UnsafeNativeMethods.GetParent(new HandleRef(this, hwnd));

                if (hwndParent == hwndRoot)
                { 
                    return hwnd;
                } 
 
                hwnd = hwndParent;
            } 

            return IntPtr.Zero;
        }
 
        /// 
        ///     Critical:This code can cause input simulation and hence is critical. 
        ///     The current code path is only hit under RootBrowserWindow scenario for now. 
        /// 
        [SecurityCritical] 
        private bool ReportInput(
            IntPtr hwnd,
            InputMode mode,
            int timestamp, 
            RawKeyboardActions actions,
            int scanCode, 
            bool isExtendedKey, 
            bool isSystemKey,
            int virtualKey) 
        {
            Debug.Assert( null != _source );

            // The first event should also activate the keyboard device. 
            if((actions & RawKeyboardActions.Deactivate) == 0)
            { 
                if(!_active || _partialActive) 
                {
                    try 
                    {
                        // Include the activation action.
                        actions |= RawKeyboardActions.Activate;
 
                        // Remember that we are active.
                        _active = true; 
                        _partialActive = false; 
                    }
                    catch(System.ComponentModel.Win32Exception) 
                    {
                        System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetKeyboardState failed!");

                        // We'll go ahead and report the input, but we'll try to "activate" next time. 
                    }
                } 
            } 

            // Get the extra information sent along with the message. 
            IntPtr extraInformation = IntPtr.Zero;
            try
            {
                extraInformation = UnsafeNativeMethods.GetMessageExtraInfo(); 
            }
            catch(System.ComponentModel.Win32Exception) 
            { 
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetMessageExtraInfo failed!");
            } 

            RawKeyboardInputReport report = new RawKeyboardInputReport(_source.Value,
                                                                       mode,
                                                                       timestamp, 
                                                                       actions,
                                                                       scanCode, 
                                                                       isExtendedKey, 
                                                                       isSystemKey,
                                                                       virtualKey, 
                                                                       extraInformation);


            bool handled = _site.Value.ReportInput(report); 

            return handled; 
        } 

        private int  _msgTime; 
        /// 
        /// This is got under an elevation and is hence critical. This data is not ok to expose.
        /// 
        private SecurityCriticalDataClass _source; 
        /// 
        /// This is got under an elevation and is hence critical.This data is not ok to expose. 
        ///  
        private SecurityCriticalDataClass _site;
        private IInputElement _restoreFocus; 
        /// 
        /// This is got under an elevation and is hence critical.This data is not ok to expose.
        /// 
        [SecurityCritical] 
        private IntPtr _restoreFocusWindow;
        private bool _active; 
        private bool _partialActive; 
    }
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK