HwndKeyboardInputProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / InterOp / HwndKeyboardInputProvider.cs / 1305600 / 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.Internal.Interop; 
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 checkOnly)
        {
            bool success = false; 

            Debug.Assert( null != _source ); 
 
            try
            { 
                // Acquiring focus into this window should clear any pending focus restoration.
                if(!checkOnly)
                {
                    _restoreFocusWindow = IntPtr.Zero; 
                    _restoreFocus = null;
                } 
 
                HandleRef thisWindow = new HandleRef(this, _source.Value.CriticalHandle);
 
                int windowStyle = UnsafeNativeMethods.GetWindowLong(thisWindow, NativeMethods.GWL_EXSTYLE);
                if ((windowStyle & NativeMethods.WS_EX_NOACTIVATE) == NativeMethods.WS_EX_NOACTIVATE || _source.Value.IsInExclusiveMenuMode)
                {
                    // If this window has the WS_EX_NOACTIVATE style, then we 
                    // do not set Win32 keyboard focus to this window because
                    // that would actually activate the window. This is 
                    // typically for the menu Popup. 
                    //
                    // If this window is in "menu mode", then we do not set 
                    // Win32 focus to this window because we don't want to
                    // move Win32 focus from where it is.  This is typically
                    // for the main window.
                    // 
                    // In either case, the window must be enabled.
                    if(SafeNativeMethods.IsWindowEnabled(thisWindow)) 
                    { 
                        if (SecurityHelper.AppDomainGrantedUnrestrictedUIPermission)
                        { 
                            // In fully-trusted AppDomains, the only hard requirement
                            // is that Win32 keyboard focus be somewhere on our thread,
                            // and that the message pump cooperate by calling
                            // ComponentDispatcher.RaiseThreadMessage. WPF will be 
                            // able to route the keyboard events to the element with
                            // WPF keyboard focus, regardless of which window has Win32 
                            // keyboard focus. Menus/ComboBoxes use this feature. 
                            int idWindowProcess;
                            IntPtr focus = UnsafeNativeMethods.GetFocus(); 
                            int idWindowThread = UnsafeNativeMethods.GetWindowThreadProcessId(new HandleRef(null, focus), out idWindowProcess);
                            success = (idWindowThread == SafeNativeMethods.GetCurrentThreadId());
                        }
                        else 
                        {
                            // In partially-trusted AppDomains, we do not want to expose input 
                            // intended for other native windows, or for WPF windows in other 
                            // AppDomains.
                            IntPtr focus = UnsafeNativeMethods.GetFocus(); 
                            success = IsOurWindow(focus);
                        }
                    }
                } 
                else
                { 
                    // This is the normal case.  We want to keep WPF keyboard 
                    // focus and Win32 keyboard focus in [....].
                    if(!checkOnly) 
                    {
                        UnsafeNativeMethods.SetFocus(thisWindow);
                    }
 
                    IntPtr focus = UnsafeNativeMethods.GetFocus();
                    success = (focus == _source.Value.CriticalHandle); 
                } 
            }
            catch(System.ComponentModel.Win32Exception) 
            {
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: AcquireFocus 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.
        ///     For HANDLED_KEYDOWN_STILL_GENERATES_CHARS we also cause the
        ///     Dispatcher to defer processing the queue until after any 
        ///     currently pending messages.
        ///  
        [SecurityCritical] 
        internal IntPtr FilterMessage(IntPtr hwnd, WindowMessage 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 WindowMessage.WM_SYSKEYDOWN: 
                case WindowMessage.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, (int)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);

                    // Force the Dispatcher to post a new message to service any 
                    // pending operations, so that the operation we just posted
                    // is guaranteed to get dispatched after any pending WM_CHAR 
                    // messages are dispatched. 
                    Dispatcher.CriticalRequestProcessing(true);
 
                    MSG msg = new MSG(hwnd, (int)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 WindowMessage.WM_SYSKEYUP:
                case WindowMessage.WM_KEYUP: 
                {
                    if(_source.Value.IsRepeatedKeyboardMessage(hwnd, (int)message, wParam, lParam)) 
                    { 
                        break;
                    } 

                    MSG msg = new MSG(hwnd, (int)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 WindowMessage.WM_CHAR:
                case WindowMessage.WM_DEADCHAR:
                case WindowMessage.WM_SYSCHAR:
                case WindowMessage.WM_SYSDEADCHAR: 
                {
                    if(_source.Value.IsRepeatedKeyboardMessage(hwnd, (int)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 WindowMessage.WM_EXITMENULOOP: 
                case WindowMessage.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 WindowMessage.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; 
 
                        if(_source.Value.RestoreFocusMode == RestoreFocusMode.Auto)
                        { 
                            // 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
                            {
                                DependencyObject restoreFocusDO = _restoreFocus as DependencyObject; 
                                _restoreFocus = null;
 
                                if(restoreFocusDO != null) 
                                {
                                    // Only restore focus to an element if that 
                                    // element still belongs to this HWND.
                                    HwndSource hwndSource = PresentationSource.CriticalFromVisual(restoreFocusDO) as HwndSource;
                                    if (hwndSource != _source.Value)
                                    { 
                                        restoreFocusDO = null;
                                    } 
                                } 

                                // Try to restore focus to the last element that had focus.  Note 
                                // that if restoreFocusDO is null, we will internally set focus
                                // to the root element.
                                Keyboard.Focus(restoreFocusDO as IInputElement);
 
                                // Lots of things can happen when setting focus to an element,
                                // including that element may set focus somewhere else, possibly 
                                // even into another HWND.  However, if Win32 focus remains on 
                                // this window, we do not allow the focused element to be in
                                // a different window. 
                                IntPtr focus = UnsafeNativeMethods.GetFocus();
                                if (focus == _source.Value.CriticalHandle)
                                {
                                    restoreFocusDO = (DependencyObject)Keyboard.FocusedElement; 
                                    if (restoreFocusDO != null)
                                    { 
                                        HwndSource hwndSource = PresentationSource.CriticalFromVisual(restoreFocusDO) as HwndSource; 
                                        if (hwndSource != _source.Value)
                                        { 
                                            Keyboard.ClearFocus();
                                        }
                                    }
                                } 
                            }
                        } 
                    } 

                    handled = true; 
                }
                break;

                // WM_KILLFOCUS is sent immediately before focus is removed. 
                // This is our clue that the keyboard is inactive.
                case WindowMessage.WM_KILLFOCUS: 
                { 
                    if(_active  &&  wParam != _source.Value.CriticalHandle )
                    { 
                        // Console.WriteLine("WM_KILLFOCUS");

                        if(_source.Value.RestoreFocusMode == RestoreFocusMode.Auto)
                        { 
                            // 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);
 
                            _restoreFocus = null;

                            // If we aren't restoring focus to a child window,
                            // then restore focus to the element that currently 
                            // has WPF keyboard focus if it is directly in this
                            // HwndSource. 
                            if (_restoreFocusWindow == IntPtr.Zero) 
                            {
                                DependencyObject focusedDO = Keyboard.FocusedElement as DependencyObject; 
                                if (focusedDO != null)
                                {
                                    HwndSource hwndSource = PresentationSource.CriticalFromVisual(focusedDO) as HwndSource;
                                    if (hwndSource == _source.Value) 
                                    {
                                        _restoreFocus = focusedDO as IInputElement; 
                                    } 
                                }
 
                            }
                        }

                        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 WindowMessage.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.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info))
            { 
                EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientInputMessage, 
                                                    EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.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 = (((WindowMessage)msg.message == WindowMessage.WM_SYSKEYDOWN) || ((WindowMessage)msg.message == WindowMessage.WM_SYSKEYUP)); 
                RawKeyboardActions action = GetKeyUpKeyDown((WindowMessage)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, WindowMessage msg, IntPtr wParam, IntPtr lParam, ref bool handled) 
        {
            char charcode = (char)wParam; 
            bool isDeadChar = ((msg == WindowMessage.WM_DEADCHAR) || (msg == WindowMessage.WM_SYSDEADCHAR)); 
            bool isSystemChar = ((msg == WindowMessage.WM_SYSCHAR) || (msg == WindowMessage.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(WindowMessage msg) 
        {
            if(  msg == WindowMessage.WM_KEYDOWN || msg == WindowMessage.WM_SYSKEYDOWN ) 
                return RawKeyboardActions.KeyDown;
            if(  msg == WindowMessage.WM_KEYUP || msg == WindowMessage.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.Internal.Interop; 
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 checkOnly)
        {
            bool success = false; 

            Debug.Assert( null != _source ); 
 
            try
            { 
                // Acquiring focus into this window should clear any pending focus restoration.
                if(!checkOnly)
                {
                    _restoreFocusWindow = IntPtr.Zero; 
                    _restoreFocus = null;
                } 
 
                HandleRef thisWindow = new HandleRef(this, _source.Value.CriticalHandle);
 
                int windowStyle = UnsafeNativeMethods.GetWindowLong(thisWindow, NativeMethods.GWL_EXSTYLE);
                if ((windowStyle & NativeMethods.WS_EX_NOACTIVATE) == NativeMethods.WS_EX_NOACTIVATE || _source.Value.IsInExclusiveMenuMode)
                {
                    // If this window has the WS_EX_NOACTIVATE style, then we 
                    // do not set Win32 keyboard focus to this window because
                    // that would actually activate the window. This is 
                    // typically for the menu Popup. 
                    //
                    // If this window is in "menu mode", then we do not set 
                    // Win32 focus to this window because we don't want to
                    // move Win32 focus from where it is.  This is typically
                    // for the main window.
                    // 
                    // In either case, the window must be enabled.
                    if(SafeNativeMethods.IsWindowEnabled(thisWindow)) 
                    { 
                        if (SecurityHelper.AppDomainGrantedUnrestrictedUIPermission)
                        { 
                            // In fully-trusted AppDomains, the only hard requirement
                            // is that Win32 keyboard focus be somewhere on our thread,
                            // and that the message pump cooperate by calling
                            // ComponentDispatcher.RaiseThreadMessage. WPF will be 
                            // able to route the keyboard events to the element with
                            // WPF keyboard focus, regardless of which window has Win32 
                            // keyboard focus. Menus/ComboBoxes use this feature. 
                            int idWindowProcess;
                            IntPtr focus = UnsafeNativeMethods.GetFocus(); 
                            int idWindowThread = UnsafeNativeMethods.GetWindowThreadProcessId(new HandleRef(null, focus), out idWindowProcess);
                            success = (idWindowThread == SafeNativeMethods.GetCurrentThreadId());
                        }
                        else 
                        {
                            // In partially-trusted AppDomains, we do not want to expose input 
                            // intended for other native windows, or for WPF windows in other 
                            // AppDomains.
                            IntPtr focus = UnsafeNativeMethods.GetFocus(); 
                            success = IsOurWindow(focus);
                        }
                    }
                } 
                else
                { 
                    // This is the normal case.  We want to keep WPF keyboard 
                    // focus and Win32 keyboard focus in [....].
                    if(!checkOnly) 
                    {
                        UnsafeNativeMethods.SetFocus(thisWindow);
                    }
 
                    IntPtr focus = UnsafeNativeMethods.GetFocus();
                    success = (focus == _source.Value.CriticalHandle); 
                } 
            }
            catch(System.ComponentModel.Win32Exception) 
            {
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: AcquireFocus 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.
        ///     For HANDLED_KEYDOWN_STILL_GENERATES_CHARS we also cause the
        ///     Dispatcher to defer processing the queue until after any 
        ///     currently pending messages.
        ///  
        [SecurityCritical] 
        internal IntPtr FilterMessage(IntPtr hwnd, WindowMessage 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 WindowMessage.WM_SYSKEYDOWN: 
                case WindowMessage.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, (int)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);

                    // Force the Dispatcher to post a new message to service any 
                    // pending operations, so that the operation we just posted
                    // is guaranteed to get dispatched after any pending WM_CHAR 
                    // messages are dispatched. 
                    Dispatcher.CriticalRequestProcessing(true);
 
                    MSG msg = new MSG(hwnd, (int)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 WindowMessage.WM_SYSKEYUP:
                case WindowMessage.WM_KEYUP: 
                {
                    if(_source.Value.IsRepeatedKeyboardMessage(hwnd, (int)message, wParam, lParam)) 
                    { 
                        break;
                    } 

                    MSG msg = new MSG(hwnd, (int)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 WindowMessage.WM_CHAR:
                case WindowMessage.WM_DEADCHAR:
                case WindowMessage.WM_SYSCHAR:
                case WindowMessage.WM_SYSDEADCHAR: 
                {
                    if(_source.Value.IsRepeatedKeyboardMessage(hwnd, (int)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 WindowMessage.WM_EXITMENULOOP: 
                case WindowMessage.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 WindowMessage.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; 
 
                        if(_source.Value.RestoreFocusMode == RestoreFocusMode.Auto)
                        { 
                            // 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
                            {
                                DependencyObject restoreFocusDO = _restoreFocus as DependencyObject; 
                                _restoreFocus = null;
 
                                if(restoreFocusDO != null) 
                                {
                                    // Only restore focus to an element if that 
                                    // element still belongs to this HWND.
                                    HwndSource hwndSource = PresentationSource.CriticalFromVisual(restoreFocusDO) as HwndSource;
                                    if (hwndSource != _source.Value)
                                    { 
                                        restoreFocusDO = null;
                                    } 
                                } 

                                // Try to restore focus to the last element that had focus.  Note 
                                // that if restoreFocusDO is null, we will internally set focus
                                // to the root element.
                                Keyboard.Focus(restoreFocusDO as IInputElement);
 
                                // Lots of things can happen when setting focus to an element,
                                // including that element may set focus somewhere else, possibly 
                                // even into another HWND.  However, if Win32 focus remains on 
                                // this window, we do not allow the focused element to be in
                                // a different window. 
                                IntPtr focus = UnsafeNativeMethods.GetFocus();
                                if (focus == _source.Value.CriticalHandle)
                                {
                                    restoreFocusDO = (DependencyObject)Keyboard.FocusedElement; 
                                    if (restoreFocusDO != null)
                                    { 
                                        HwndSource hwndSource = PresentationSource.CriticalFromVisual(restoreFocusDO) as HwndSource; 
                                        if (hwndSource != _source.Value)
                                        { 
                                            Keyboard.ClearFocus();
                                        }
                                    }
                                } 
                            }
                        } 
                    } 

                    handled = true; 
                }
                break;

                // WM_KILLFOCUS is sent immediately before focus is removed. 
                // This is our clue that the keyboard is inactive.
                case WindowMessage.WM_KILLFOCUS: 
                { 
                    if(_active  &&  wParam != _source.Value.CriticalHandle )
                    { 
                        // Console.WriteLine("WM_KILLFOCUS");

                        if(_source.Value.RestoreFocusMode == RestoreFocusMode.Auto)
                        { 
                            // 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);
 
                            _restoreFocus = null;

                            // If we aren't restoring focus to a child window,
                            // then restore focus to the element that currently 
                            // has WPF keyboard focus if it is directly in this
                            // HwndSource. 
                            if (_restoreFocusWindow == IntPtr.Zero) 
                            {
                                DependencyObject focusedDO = Keyboard.FocusedElement as DependencyObject; 
                                if (focusedDO != null)
                                {
                                    HwndSource hwndSource = PresentationSource.CriticalFromVisual(focusedDO) as HwndSource;
                                    if (hwndSource == _source.Value) 
                                    {
                                        _restoreFocus = focusedDO as IInputElement; 
                                    } 
                                }
 
                            }
                        }

                        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 WindowMessage.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.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info))
            { 
                EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientInputMessage, 
                                                    EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.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 = (((WindowMessage)msg.message == WindowMessage.WM_SYSKEYDOWN) || ((WindowMessage)msg.message == WindowMessage.WM_SYSKEYUP)); 
                RawKeyboardActions action = GetKeyUpKeyDown((WindowMessage)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, WindowMessage msg, IntPtr wParam, IntPtr lParam, ref bool handled) 
        {
            char charcode = (char)wParam; 
            bool isDeadChar = ((msg == WindowMessage.WM_DEADCHAR) || (msg == WindowMessage.WM_SYSDEADCHAR)); 
            bool isSystemChar = ((msg == WindowMessage.WM_SYSCHAR) || (msg == WindowMessage.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(WindowMessage msg) 
        {
            if(  msg == WindowMessage.WM_KEYDOWN || msg == WindowMessage.WM_SYSKEYDOWN ) 
                return RawKeyboardActions.KeyDown;
            if(  msg == WindowMessage.WM_KEYUP || msg == WindowMessage.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