Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / System / Windows / Input / TextCompositionManager.cs / 1 / TextCompositionManager.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: the CompositionManager class // // History: // 11/18/2003 : yutakas created // //--------------------------------------------------------------------------- using System; using System.Diagnostics; using System.Globalization; using System.Security; using System.Security.Permissions; using System.Text; using System.Windows.Threading; using System.Windows; using System.Runtime.InteropServices; using MS.Win32; using Microsoft.Win32; // for RegistryKey class using MS.Internal ; using MS.Internal.PresentationCore; // SecurityHelper using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; namespace System.Windows.Input { // // Modes of AltNumpad. // internal enum AltNumpadConversionMode { DefaultCodePage, // ACP code page encoding. Alt+Numpad0+NumpadX OEMCodePage, // OEM code page encoding. Alt+NumpadX HexDefaultCodePage, // HEX value in ACP. Alt+NumpadDOT+NumpadX HexUnicode, // HEX value in Unicode. Alt+NumpadPlus+NumpadX } ////// the CompositionManager class provides input-text/composition event promotion /// public sealed class TextCompositionManager : DispatcherObject { //----------------------------------------------------- // // static RoutedEvent // //----------------------------------------------------- ////// Preview Composition Start /// public static readonly RoutedEvent PreviewTextInputStartEvent = EventManager.RegisterRoutedEvent("PreviewTextInputStart", RoutingStrategy.Tunnel, typeof(TextCompositionEventHandler), typeof(TextCompositionManager)); ////// Adds a handler for the PreviewTextInputStart attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewTextInputStartHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.AddHandler(element, PreviewTextInputStartEvent, handler); } ////// Removes a handler for the PreviewTextInputStart attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewTextInputStartHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.RemoveHandler(element, PreviewTextInputStartEvent, handler); } ////// Composition Start /// public static readonly RoutedEvent TextInputStartEvent = EventManager.RegisterRoutedEvent("TextInputStart", RoutingStrategy.Bubble, typeof(TextCompositionEventHandler), typeof(TextCompositionManager)); ////// Adds a handler for the TextInputStart attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddTextInputStartHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.AddHandler(element, TextInputStartEvent, handler); } ////// Removes a handler for the TextInputStart attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveTextInputStartHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.RemoveHandler(element, TextInputStartEvent, handler); } ////// Preview Composition Updated /// public static readonly RoutedEvent PreviewTextInputUpdateEvent = EventManager.RegisterRoutedEvent("PreviewTextInputUpdate", RoutingStrategy.Tunnel, typeof(TextCompositionEventHandler), typeof(TextCompositionManager)); ////// Adds a handler for the PreviewTextInputUpdate attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewTextInputUpdateHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.AddHandler(element, PreviewTextInputUpdateEvent, handler); } ////// Removes a handler for the PreviewTextInputUpdate attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewTextInputUpdateHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.RemoveHandler(element, PreviewTextInputUpdateEvent, handler); } ////// Composition Updated /// public static readonly RoutedEvent TextInputUpdateEvent = EventManager.RegisterRoutedEvent("TextInputUpdate", RoutingStrategy.Bubble, typeof(TextCompositionEventHandler), typeof(TextCompositionManager)); ////// Adds a handler for the TextInputUpdate attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddTextInputUpdateHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.AddHandler(element, TextInputUpdateEvent, handler); } ////// Removes a handler for the TextInputUpdate attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveTextInputUpdateHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.RemoveHandler(element, TextInputUpdateEvent, handler); } ////// Preview Composition End /// public static readonly RoutedEvent PreviewTextInputEvent = EventManager.RegisterRoutedEvent("PreviewTextInput", RoutingStrategy.Tunnel, typeof(TextCompositionEventHandler), typeof(TextCompositionManager)); ////// Adds a handler for the PreviewTextInput attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewTextInputHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.AddHandler(element, PreviewTextInputEvent, handler); } ////// Removes a handler for the PreviewTextInput attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewTextInputHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.RemoveHandler(element, PreviewTextInputEvent, handler); } ////// Composition End /// public static readonly RoutedEvent TextInputEvent = EventManager.RegisterRoutedEvent("TextInput", RoutingStrategy.Bubble, typeof(TextCompositionEventHandler), typeof(TextCompositionManager)); ////// Adds a handler for the TextInput attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddTextInputHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.AddHandler(element, TextInputEvent, handler); } ////// Removes a handler for the TextInput attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveTextInputHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.RemoveHandler(element, TextInputEvent, handler); } //------------------------------------------------------ // // Constructors // //----------------------------------------------------- #region Constructors ////// Critical - Calls a critical method - PreProcessInput /// TreatAsSafe - Ok for us to register an event handler. Handler itself is critical. /// [SecurityCritical, SecurityTreatAsSafe ] internal TextCompositionManager(InputManager inputManager) { _inputManager = inputManager; _inputManager.PreProcessInput += new PreProcessInputEventHandler(PreProcessInput); _inputManager.PostProcessInput += new ProcessInputEventHandler(PostProcessInput); } #endregion Constructors //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ ////// Start the composition. /// ////// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// ////// Critical calls UnsafeStartComposition. /// PublicOk: Linkdemand blocks external callers /// [SecurityCritical] [UIPermissionAttribute(SecurityAction.LinkDemand,Unrestricted=true)] public static bool StartComposition(TextComposition composition) { return UnsafeStartComposition(composition); } ////// Update the composition. /// ////// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// ////// Critical calls UnsafeUpdataComposition. /// PublicOk: Linkdemand blocks external callers /// [SecurityCritical] [UIPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)] public static bool UpdateComposition(TextComposition composition) { return UnsafeUpdateComposition(composition); } ////// Complete the composition. /// ////// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// ////// Critical calls UnsafeCompleteComposition. /// PublicOk: Linkdemand blocks external callers /// [SecurityCritical] [UIPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)] public static bool CompleteComposition(TextComposition composition) { return UnsafeCompleteComposition(composition); } //----------------------------------------------------- // // Public Properties // //------------------------------------------------------ //----------------------------------------------------- // // Public Events // //----------------------------------------------------- //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ //------------------------------------------------------ // // Internal Properties // //----------------------------------------------------- //------------------------------------------------------ // // Internal Events // //----------------------------------------------------- //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- ////// Critical - as this refers to _InputManager and calls Critical function /// InputManager.ProcessInput. This can be used to spoof text input. /// [SecurityCritical] private static bool UnsafeStartComposition(TextComposition composition) { if (composition == null) { throw new ArgumentNullException("composition"); } if (composition._InputManager == null) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_NoInputManager, "composition")); } if (composition.Stage != TextCompositionStage.None) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_TextCompositionHasStarted, "composition")); } composition.Stage = TextCompositionStage.Started; TextCompositionEventArgs textargs = new TextCompositionEventArgs(composition._InputDevice, composition); textargs.RoutedEvent=TextCompositionManager.PreviewTextInputStartEvent; textargs.Source= composition.Source; return composition._InputManager.ProcessInput(textargs); } ////// Critical - as this refers to _InputManager and calls Critical function /// InputManager.ProcessInput. This can be used to spoof text input. /// [SecurityCritical] private static bool UnsafeUpdateComposition(TextComposition composition) { if (composition == null) { throw new ArgumentNullException("composition"); } if (composition._InputManager == null) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_NoInputManager, "composition")); } if (composition.Stage == TextCompositionStage.None) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_TextCompositionNotStarted, "composition")); } if (composition.Stage == TextCompositionStage.Done) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_TextCompositionHasDone, "composition")); } TextCompositionEventArgs textargs = new TextCompositionEventArgs(composition._InputDevice, composition); textargs.RoutedEvent=TextCompositionManager.PreviewTextInputUpdateEvent; textargs.Source= composition.Source; return composition._InputManager.ProcessInput(textargs); } ////// Critical - as this accesses InputManager and calls Critical method ProcessInput. /// [SecurityCritical] private static bool UnsafeCompleteComposition(TextComposition composition) { if (composition == null) { throw new ArgumentNullException("composition"); } if (composition._InputManager == null) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_NoInputManager, "composition")); } if (composition.Stage == TextCompositionStage.None) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_TextCompositionNotStarted, "composition")); } if (composition.Stage == TextCompositionStage.Done) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_TextCompositionHasDone, "composition")); } composition.Stage = TextCompositionStage.Done; TextCompositionEventArgs textargs = new TextCompositionEventArgs(composition._InputDevice, composition); textargs.RoutedEvent=TextCompositionManager.PreviewTextInputEvent; textargs.Source= composition.Source; return composition._InputManager.ProcessInput(textargs); } ////// Critical - calls unmanaged code. /// TreatAsSafe - This calls GetOWMCP() but it does not expose the return value (current oem cp). /// [SecurityCritical, SecurityTreatAsSafe] private static string GetCurrentOEMCPEncoding(int code) { SecurityPermission sp = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode); sp.Assert();//Blessed Assert try { int cp = UnsafeNativeMethods.GetOEMCP(); return CharacterEncoding(cp, code); } finally { SecurityPermission.RevertAssert(); } } // Convert code to the string based on the code page. ////// Critical - calls unmanaged code UnsafeNativeMethods.MultiByteToWideChar which might be exploitable if there /// were BO based exploits /// TreatAsSafe - The code calls into functions that convert an int to a byte array and also the encoding length /// is a contant. /// [SecurityCritical, SecurityTreatAsSafe] private static string CharacterEncoding(int cp, int code) { Byte[] bytes = ConvertCodeToByteArray(code); StringBuilder sbuilder = new StringBuilder(EncodingBufferLen); // Win32K uses MB_PRECOMPOSED | MB_USEGLYPHCHARS. int nret = UnsafeNativeMethods.MultiByteToWideChar(cp, UnsafeNativeMethods.MB_PRECOMPOSED | UnsafeNativeMethods.MB_USEGLYPHCHARS, bytes, bytes.Length, sbuilder, EncodingBufferLen); if (nret == 0) { int win32Err = Marshal.GetLastWin32Error(); throw new System.ComponentModel.Win32Exception(win32Err); } // set the length as MultiByteToWideChar returns. sbuilder.Length = nret; return sbuilder.ToString(); } // PreProcessInput event handler ////// Critical - calls a critical method - to create a TextComposition and calls /// Critical methods UnsafeStartComposition, UnsafeUpdateComposition /// and UnsafeCompleteComposition. /// [SecurityCritical] private void PreProcessInput(object sender, PreProcessInputEventArgs e) { // KeyDown --> Alt Numpad // // We eat Alt-NumPat keys and handle them by ourselves. Avalon has its own acceralator handler // and it may have a corrision with Win32k's AltNumPad handling. As a result, the AltNumPad cache // in Win32k's ToUnicodeEx() could be broken. // if (e.StagingItem.Input.RoutedEvent == Keyboard.KeyDownEvent) { KeyEventArgs keyArgs = (KeyEventArgs) e.StagingItem.Input; if (!keyArgs.Handled) { if (!_altNumpadEntryMode) { EnterAltNumpadEntryMode(keyArgs.RealKey); } else { if (HandleAltNumpadEntry(keyArgs.RealKey, keyArgs.ScanCode, keyArgs.IsExtendedKey)) { if (_altNumpadcomposition == null) { _altNumpadcomposition = new TextComposition(_inputManager, (IInputElement)keyArgs.Source, "", TextCompositionAutoComplete.Off, keyArgs.Device); keyArgs.Handled = UnsafeStartComposition(_altNumpadcomposition); } else { _altNumpadcomposition.ClearTexts(); keyArgs.Handled = UnsafeUpdateComposition(_altNumpadcomposition); } // We ate this key for AltNumPad entry. None will be able to handle this. e.Cancel(); } else { // alt numpad entry was reset so composition needs to be finalized. if (_altNumpadcomposition != null) { _altNumpadcomposition.ClearTexts(); _altNumpadcomposition.Complete(); ClearAltnumpadComposition(); } } } } } } // PostProcessInput event handler //////Critical- calls critical functions pushInput, UnsafeStartComposition and /// UnsafeUpdateComposition. /// [SecurityCritical] private void PostProcessInput(object sender, ProcessInputEventArgs e) { // KeyUp if(e.StagingItem.Input.RoutedEvent == Keyboard.KeyUpEvent) { KeyEventArgs keyArgs = (KeyEventArgs) e.StagingItem.Input; if(!keyArgs.Handled) { if(keyArgs.RealKey == Key.LeftAlt || keyArgs.RealKey == Key.RightAlt) { // Make sure both Alt keys are up. ModifierKeys modifiers = keyArgs.KeyboardDevice.Modifiers; if((modifiers & ModifierKeys.Alt) == 0) { if(_altNumpadEntryMode) { _altNumpadEntryMode = false; // Generate the Unicode equivalent if we // actually entered a number via the numpad. if(_altNumpadEntry != 0) { _altNumpadcomposition.ClearTexts(); if (_altNumpadConversionMode == AltNumpadConversionMode.OEMCodePage) { _altNumpadcomposition.SetText(GetCurrentOEMCPEncoding(_altNumpadEntry)); } else if ((_altNumpadConversionMode == AltNumpadConversionMode.DefaultCodePage) || (_altNumpadConversionMode == AltNumpadConversionMode.HexDefaultCodePage)) { _altNumpadcomposition.SetText(CharacterEncoding(InputLanguageManager.Current.CurrentInputLanguage.TextInfo.ANSICodePage, _altNumpadEntry)); } else if (_altNumpadConversionMode == AltNumpadConversionMode.HexUnicode) { Char[] chars = new Char[1]; chars[0] = (Char) _altNumpadEntry; _altNumpadcomposition.SetText(new string(chars)); } } } } } } else { // Someone handled Alt key up event, we cancel Alt-Numpad handling. _altNumpadEntryMode = false; _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.OEMCodePage; } } // PreviewTextInputBegin --> TextInputStart else if(e.StagingItem.Input.RoutedEvent == TextCompositionManager.PreviewTextInputStartEvent) { TextCompositionEventArgs textArgs = (TextCompositionEventArgs) e.StagingItem.Input; if(!textArgs.Handled) { TextCompositionEventArgs text = new TextCompositionEventArgs(textArgs.Device, textArgs.TextComposition); text.RoutedEvent=TextCompositionManager.TextInputStartEvent; text.Source= textArgs.TextComposition.Source; e.PushInput(text, e.StagingItem); } } // PreviewTextInputUpdate --> TextInputUpdate else if(e.StagingItem.Input.RoutedEvent == TextCompositionManager.PreviewTextInputUpdateEvent) { TextCompositionEventArgs textArgs = (TextCompositionEventArgs) e.StagingItem.Input; if(!textArgs.Handled) { TextCompositionEventArgs text = new TextCompositionEventArgs(textArgs.Device, textArgs.TextComposition); text.RoutedEvent=TextCompositionManager.TextInputUpdateEvent; text.Source= textArgs.TextComposition.Source; e.PushInput(text, e.StagingItem); } } // PreviewTextInput --> TextInput else if(e.StagingItem.Input.RoutedEvent == TextCompositionManager.PreviewTextInputEvent) { TextCompositionEventArgs textArgs = (TextCompositionEventArgs) e.StagingItem.Input; if(!textArgs.Handled) { TextCompositionEventArgs text = new TextCompositionEventArgs(textArgs.Device, textArgs.TextComposition); text.RoutedEvent=TextCompositionManager.TextInputEvent; text.Source= textArgs.TextComposition.Source; e.PushInput(text, e.StagingItem); } } // TextCompositioniBegin --> TextInput if this is AutomaticComplete. else if(e.StagingItem.Input.RoutedEvent == TextCompositionManager.TextInputStartEvent) { TextCompositionEventArgs textArgs = (TextCompositionEventArgs) e.StagingItem.Input; if(!textArgs.Handled) { if (textArgs.TextComposition.AutoComplete == TextCompositionAutoComplete.On) { textArgs.Handled = UnsafeCompleteComposition(textArgs.TextComposition); } } } // TextCompositionUpdate --> TextInput if this is AutomaticComplete. else if(e.StagingItem.Input.RoutedEvent == TextCompositionManager.TextInputUpdateEvent) { TextCompositionEventArgs textArgs = (TextCompositionEventArgs) e.StagingItem.Input; if(!textArgs.Handled) { if ((textArgs.TextComposition == _deadCharTextComposition) && (_deadCharTextComposition.Composed)) { textArgs.Handled = UnsafeCompleteComposition(_deadCharTextComposition); _deadCharTextComposition = null; } } } // Raw to StartComposition. InputReportEventArgs input = e.StagingItem.Input as InputReportEventArgs; if(input != null) { if(input.Report.Type == InputType.Text && input.RoutedEvent == InputManager.InputReportEvent) { RawTextInputReport textInput; textInput = (RawTextInputReport)input.Report; // // string inputText = new string(textInput.CharacterCode, 1); bool fDoneAltNumpadComposition = false; if (_altNumpadcomposition != null) { // Generate TextInput event from WM_CHAR handler. if (inputText.Equals(_altNumpadcomposition.Text)) { fDoneAltNumpadComposition = true; } else { // The generated text from InputReport does not matched with _altNumpadcomposition. // Cancel this composition and process the char from InputReport. _altNumpadcomposition.ClearTexts(); } _altNumpadcomposition.Complete(); ClearAltnumpadComposition(); } if (!fDoneAltNumpadComposition) { if (textInput.IsDeadCharacter) { _deadCharTextComposition = new DeadCharTextComposition(_inputManager, (IInputElement)null, inputText , TextCompositionAutoComplete.Off, InputManager.Current.PrimaryKeyboardDevice); if (textInput.IsSystemCharacter) { _deadCharTextComposition.MakeSystem(); } else if (textInput.IsControlCharacter) { _deadCharTextComposition.MakeControl(); } input.Handled = UnsafeStartComposition(_deadCharTextComposition); } else { if(inputText != null) { if (_deadCharTextComposition != null) { _deadCharTextComposition.ClearTexts(); _deadCharTextComposition.SetText(inputText); _deadCharTextComposition.Composed = true; if (textInput.IsSystemCharacter) { _deadCharTextComposition.MakeSystem(); } else if (textInput.IsControlCharacter) { _deadCharTextComposition.MakeControl(); } input.Handled = UnsafeUpdateComposition(_deadCharTextComposition); } else { TextComposition composition = new TextComposition(_inputManager, (IInputElement)e.StagingItem.Input.Source, inputText, TextCompositionAutoComplete.On, InputManager.Current.PrimaryKeyboardDevice); if (textInput.IsSystemCharacter) { composition.MakeSystem(); } else if (textInput.IsControlCharacter) { composition.MakeControl(); } input.Handled = UnsafeStartComposition(composition); } } } } } } } // AltNumpad key handler private bool EnterAltNumpadEntryMode(Key key) { bool handled = false; if(key == Key.LeftAlt || key == Key.RightAlt) { if(!_altNumpadEntryMode) { _altNumpadEntryMode = true; _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.OEMCodePage; handled = true; } } return handled; } // AltNumpad key handler private bool HandleAltNumpadEntry(Key key, int scanCode, bool isExtendedKey) { bool handled = false; Debug.Assert(_altNumpadEntryMode); // All Numpad keys (either numlock or not) are not an extended key. // We're interested in only NumPad key so we can filter them first. if (isExtendedKey) { return handled; } // If Alt key is up, we will quit AltNumpadEntryMode. if (!Keyboard.IsKeyDown(Key.LeftAlt) && !Keyboard.IsKeyDown(Key.RightAlt)) { return false; } // // Windows has historically offered a back-door for entering // characters that are not available on the keyboard. The // user can hold down one of the Alt keys, type in the numerical // value of the desried character using the num-pad keys, and // the release the Alt key. The numeric value will be converted // into Unicode, and a text event will // be raised. // if (scanCode == NumpadScanCode.NumpadDot) { if (IsHexNumpadEnabled) { _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.HexDefaultCodePage; handled = true; } else { // reset alt numpad entry and mode. _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.OEMCodePage; handled = false; } } else if (scanCode == NumpadScanCode.NumpadPlus) { if (IsHexNumpadEnabled) { _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.HexUnicode; handled = true; } else { // reset alt numpad entry and mode. _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.OEMCodePage; handled = false; } } else { int newEntry = GetNewEntry(key, scanCode); if (newEntry == -1) { _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.OEMCodePage; // we don't handle this case to cancel TextComposition. handled = false; } else { // If the first key is NumPad0, it is the default codepage. if ((_altNumpadEntry == 0) && (newEntry == 0)) _altNumpadConversionMode = AltNumpadConversionMode.DefaultCodePage; if (HexConversionMode) _altNumpadEntry = (_altNumpadEntry * 0x10) + newEntry; else _altNumpadEntry = (_altNumpadEntry * 10) + newEntry; handled = true; } } return handled; } // Convert Key and ScanCode to new entry number. private int GetNewEntry(Key key, int scanCode) { if (HexConversionMode) { switch (key) { // We accept digit keys and A-F in HexConversionMode. case Key.D0: return 0x00; case Key.D1: return 0x01; case Key.D2: return 0x02; case Key.D3: return 0x03; case Key.D4: return 0x04; case Key.D5: return 0x05; case Key.D6: return 0x06; case Key.D7: return 0x07; case Key.D8: return 0x08; case Key.D9: return 0x09; case Key.A: return 0x0A; case Key.B: return 0x0B; case Key.C: return 0x0C; case Key.D: return 0x0D; case Key.E: return 0x0E; case Key.F: return 0x0F; } } return NumpadScanCode.DigitFromScanCode(scanCode); } // Convert the code to byte array for DBCS/SBCS. ////// Critical - returns a byte array that is passed into a call under an elevation /// TreatAsSafe - The code calls is safe in terms of what it does the reason it is critical is because /// if there was logic error here in the future it could be used to exploit the elevated call. /// [SecurityCritical, SecurityTreatAsSafe] private static Byte[] ConvertCodeToByteArray(int codeEntry) { Byte[] bytes; if (codeEntry > 0xff) { bytes = new Byte[2]; bytes[0] = (Byte)(codeEntry >> 8); bytes[1] = (Byte)codeEntry; } else { bytes = new Byte[1]; bytes[0] = (Byte)codeEntry; } return bytes; } // clear the altnumpad composition object and reset entry. // the existence of the altnumpad composition object needs to be consistent with altnumpad entry. private void ClearAltnumpadComposition() { _altNumpadcomposition = null; _altNumpadConversionMode = AltNumpadConversionMode.OEMCodePage; _altNumpadEntry = 0; } //------------------------------------------------------ // // Private Properties // //----------------------------------------------------- // Return true if we're in hex conversion mode. private bool HexConversionMode { get { if ((_altNumpadConversionMode == AltNumpadConversionMode.HexDefaultCodePage) || (_altNumpadConversionMode == AltNumpadConversionMode.HexUnicode)) return true; return false; } } ////// Return true if HexNumPad is enabled. /// ////// Critical - asserts registry permissions to read from HKEY_CURRENT_USER. /// Treat as safe - we only read a value from HKEY_CURENT_USER. And we don't expose the value. /// private static bool IsHexNumpadEnabled { [SecurityCritical, SecurityTreatAsSafe ] get { if (!_isHexNumpadRegistryChecked) { // Acquire permissions to read the one key we care about from the registry RegistryPermission permission = new RegistryPermission( RegistryPermissionAccess.Read, "HKEY_CURRENT_USER\\Control Panel\\Input Method"); permission.Assert(); try { object obj; RegistryKey key; key = Registry.CurrentUser.OpenSubKey("Control Panel\\Input Method"); if (key != null) { obj = key.GetValue("EnableHexNumpad"); if ((obj is string) && ((string)obj != "0")) { _isHexNumpadEnabled = true; } } } finally { RegistryPermission.RevertAssert(); } _isHexNumpadRegistryChecked = true; } return _isHexNumpadEnabled; } } //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ // InputManager for this TextCompositionManager ////// Critical - InputManager is critical. /// [SecurityCritical] private readonly InputManager _inputManager; // The current dead char composition. private DeadCharTextComposition _deadCharTextComposition; // The state of AltNumpad mode. private bool _altNumpadEntryMode; // The current value entered from NumPad. private int _altNumpadEntry; // The current AltNumpad conversion mode. private AltNumpadConversionMode _altNumpadConversionMode; // TextComposition for AltNumpad. private TextComposition _altNumpadcomposition; // True if EnableHexNumpad registry has been checked. private static bool _isHexNumpadRegistryChecked = false; // True if EnableHexNumpad registry is set. private static bool _isHexNumpadEnabled = false; // Character encoding length. ////// Critical - Is used to detereming length in a call to unmanaged code which happens under an elevation /// [SecurityCritical] private const int EncodingBufferLen = 4; // ScanCode of Numpad keys. internal static class NumpadScanCode { internal static int DigitFromScanCode(int scanCode) { switch (scanCode) { case Numpad0: return 0; case Numpad1: return 1; case Numpad2: return 2; case Numpad3: return 3; case Numpad4: return 4; case Numpad5: return 5; case Numpad6: return 6; case Numpad7: return 7; case Numpad8: return 8; case Numpad9: return 9; } return -1; } internal const int NumpadDot = 0x53; internal const int NumpadPlus = 0x4e; internal const int Numpad0 = 0x52; internal const int Numpad1 = 0x4f; internal const int Numpad2 = 0x50; internal const int Numpad3 = 0x51; internal const int Numpad4 = 0x4b; internal const int Numpad5 = 0x4c; internal const int Numpad6 = 0x4d; internal const int Numpad7 = 0x47; internal const int Numpad8 = 0x48; internal const int Numpad9 = 0x49; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: the CompositionManager class // // History: // 11/18/2003 : yutakas created // //--------------------------------------------------------------------------- using System; using System.Diagnostics; using System.Globalization; using System.Security; using System.Security.Permissions; using System.Text; using System.Windows.Threading; using System.Windows; using System.Runtime.InteropServices; using MS.Win32; using Microsoft.Win32; // for RegistryKey class using MS.Internal ; using MS.Internal.PresentationCore; // SecurityHelper using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; namespace System.Windows.Input { // // Modes of AltNumpad. // internal enum AltNumpadConversionMode { DefaultCodePage, // ACP code page encoding. Alt+Numpad0+NumpadX OEMCodePage, // OEM code page encoding. Alt+NumpadX HexDefaultCodePage, // HEX value in ACP. Alt+NumpadDOT+NumpadX HexUnicode, // HEX value in Unicode. Alt+NumpadPlus+NumpadX } ////// the CompositionManager class provides input-text/composition event promotion /// public sealed class TextCompositionManager : DispatcherObject { //----------------------------------------------------- // // static RoutedEvent // //----------------------------------------------------- ////// Preview Composition Start /// public static readonly RoutedEvent PreviewTextInputStartEvent = EventManager.RegisterRoutedEvent("PreviewTextInputStart", RoutingStrategy.Tunnel, typeof(TextCompositionEventHandler), typeof(TextCompositionManager)); ////// Adds a handler for the PreviewTextInputStart attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewTextInputStartHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.AddHandler(element, PreviewTextInputStartEvent, handler); } ////// Removes a handler for the PreviewTextInputStart attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewTextInputStartHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.RemoveHandler(element, PreviewTextInputStartEvent, handler); } ////// Composition Start /// public static readonly RoutedEvent TextInputStartEvent = EventManager.RegisterRoutedEvent("TextInputStart", RoutingStrategy.Bubble, typeof(TextCompositionEventHandler), typeof(TextCompositionManager)); ////// Adds a handler for the TextInputStart attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddTextInputStartHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.AddHandler(element, TextInputStartEvent, handler); } ////// Removes a handler for the TextInputStart attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveTextInputStartHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.RemoveHandler(element, TextInputStartEvent, handler); } ////// Preview Composition Updated /// public static readonly RoutedEvent PreviewTextInputUpdateEvent = EventManager.RegisterRoutedEvent("PreviewTextInputUpdate", RoutingStrategy.Tunnel, typeof(TextCompositionEventHandler), typeof(TextCompositionManager)); ////// Adds a handler for the PreviewTextInputUpdate attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewTextInputUpdateHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.AddHandler(element, PreviewTextInputUpdateEvent, handler); } ////// Removes a handler for the PreviewTextInputUpdate attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewTextInputUpdateHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.RemoveHandler(element, PreviewTextInputUpdateEvent, handler); } ////// Composition Updated /// public static readonly RoutedEvent TextInputUpdateEvent = EventManager.RegisterRoutedEvent("TextInputUpdate", RoutingStrategy.Bubble, typeof(TextCompositionEventHandler), typeof(TextCompositionManager)); ////// Adds a handler for the TextInputUpdate attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddTextInputUpdateHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.AddHandler(element, TextInputUpdateEvent, handler); } ////// Removes a handler for the TextInputUpdate attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveTextInputUpdateHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.RemoveHandler(element, TextInputUpdateEvent, handler); } ////// Preview Composition End /// public static readonly RoutedEvent PreviewTextInputEvent = EventManager.RegisterRoutedEvent("PreviewTextInput", RoutingStrategy.Tunnel, typeof(TextCompositionEventHandler), typeof(TextCompositionManager)); ////// Adds a handler for the PreviewTextInput attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewTextInputHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.AddHandler(element, PreviewTextInputEvent, handler); } ////// Removes a handler for the PreviewTextInput attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewTextInputHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.RemoveHandler(element, PreviewTextInputEvent, handler); } ////// Composition End /// public static readonly RoutedEvent TextInputEvent = EventManager.RegisterRoutedEvent("TextInput", RoutingStrategy.Bubble, typeof(TextCompositionEventHandler), typeof(TextCompositionManager)); ////// Adds a handler for the TextInput attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddTextInputHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.AddHandler(element, TextInputEvent, handler); } ////// Removes a handler for the TextInput attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveTextInputHandler(DependencyObject element, TextCompositionEventHandler handler) { if (element == null) { throw new ArgumentNullException("element"); } UIElement.RemoveHandler(element, TextInputEvent, handler); } //------------------------------------------------------ // // Constructors // //----------------------------------------------------- #region Constructors ////// Critical - Calls a critical method - PreProcessInput /// TreatAsSafe - Ok for us to register an event handler. Handler itself is critical. /// [SecurityCritical, SecurityTreatAsSafe ] internal TextCompositionManager(InputManager inputManager) { _inputManager = inputManager; _inputManager.PreProcessInput += new PreProcessInputEventHandler(PreProcessInput); _inputManager.PostProcessInput += new ProcessInputEventHandler(PostProcessInput); } #endregion Constructors //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ ////// Start the composition. /// ////// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// ////// Critical calls UnsafeStartComposition. /// PublicOk: Linkdemand blocks external callers /// [SecurityCritical] [UIPermissionAttribute(SecurityAction.LinkDemand,Unrestricted=true)] public static bool StartComposition(TextComposition composition) { return UnsafeStartComposition(composition); } ////// Update the composition. /// ////// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// ////// Critical calls UnsafeUpdataComposition. /// PublicOk: Linkdemand blocks external callers /// [SecurityCritical] [UIPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)] public static bool UpdateComposition(TextComposition composition) { return UnsafeUpdateComposition(composition); } ////// Complete the composition. /// ////// Callers must have UIPermission(PermissionState.Unrestricted) to call this API. /// ////// Critical calls UnsafeCompleteComposition. /// PublicOk: Linkdemand blocks external callers /// [SecurityCritical] [UIPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)] public static bool CompleteComposition(TextComposition composition) { return UnsafeCompleteComposition(composition); } //----------------------------------------------------- // // Public Properties // //------------------------------------------------------ //----------------------------------------------------- // // Public Events // //----------------------------------------------------- //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ //------------------------------------------------------ // // Internal Properties // //----------------------------------------------------- //------------------------------------------------------ // // Internal Events // //----------------------------------------------------- //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- ////// Critical - as this refers to _InputManager and calls Critical function /// InputManager.ProcessInput. This can be used to spoof text input. /// [SecurityCritical] private static bool UnsafeStartComposition(TextComposition composition) { if (composition == null) { throw new ArgumentNullException("composition"); } if (composition._InputManager == null) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_NoInputManager, "composition")); } if (composition.Stage != TextCompositionStage.None) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_TextCompositionHasStarted, "composition")); } composition.Stage = TextCompositionStage.Started; TextCompositionEventArgs textargs = new TextCompositionEventArgs(composition._InputDevice, composition); textargs.RoutedEvent=TextCompositionManager.PreviewTextInputStartEvent; textargs.Source= composition.Source; return composition._InputManager.ProcessInput(textargs); } ////// Critical - as this refers to _InputManager and calls Critical function /// InputManager.ProcessInput. This can be used to spoof text input. /// [SecurityCritical] private static bool UnsafeUpdateComposition(TextComposition composition) { if (composition == null) { throw new ArgumentNullException("composition"); } if (composition._InputManager == null) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_NoInputManager, "composition")); } if (composition.Stage == TextCompositionStage.None) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_TextCompositionNotStarted, "composition")); } if (composition.Stage == TextCompositionStage.Done) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_TextCompositionHasDone, "composition")); } TextCompositionEventArgs textargs = new TextCompositionEventArgs(composition._InputDevice, composition); textargs.RoutedEvent=TextCompositionManager.PreviewTextInputUpdateEvent; textargs.Source= composition.Source; return composition._InputManager.ProcessInput(textargs); } ////// Critical - as this accesses InputManager and calls Critical method ProcessInput. /// [SecurityCritical] private static bool UnsafeCompleteComposition(TextComposition composition) { if (composition == null) { throw new ArgumentNullException("composition"); } if (composition._InputManager == null) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_NoInputManager, "composition")); } if (composition.Stage == TextCompositionStage.None) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_TextCompositionNotStarted, "composition")); } if (composition.Stage == TextCompositionStage.Done) { throw new ArgumentException(SR.Get(SRID.TextCompositionManager_TextCompositionHasDone, "composition")); } composition.Stage = TextCompositionStage.Done; TextCompositionEventArgs textargs = new TextCompositionEventArgs(composition._InputDevice, composition); textargs.RoutedEvent=TextCompositionManager.PreviewTextInputEvent; textargs.Source= composition.Source; return composition._InputManager.ProcessInput(textargs); } ////// Critical - calls unmanaged code. /// TreatAsSafe - This calls GetOWMCP() but it does not expose the return value (current oem cp). /// [SecurityCritical, SecurityTreatAsSafe] private static string GetCurrentOEMCPEncoding(int code) { SecurityPermission sp = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode); sp.Assert();//Blessed Assert try { int cp = UnsafeNativeMethods.GetOEMCP(); return CharacterEncoding(cp, code); } finally { SecurityPermission.RevertAssert(); } } // Convert code to the string based on the code page. ////// Critical - calls unmanaged code UnsafeNativeMethods.MultiByteToWideChar which might be exploitable if there /// were BO based exploits /// TreatAsSafe - The code calls into functions that convert an int to a byte array and also the encoding length /// is a contant. /// [SecurityCritical, SecurityTreatAsSafe] private static string CharacterEncoding(int cp, int code) { Byte[] bytes = ConvertCodeToByteArray(code); StringBuilder sbuilder = new StringBuilder(EncodingBufferLen); // Win32K uses MB_PRECOMPOSED | MB_USEGLYPHCHARS. int nret = UnsafeNativeMethods.MultiByteToWideChar(cp, UnsafeNativeMethods.MB_PRECOMPOSED | UnsafeNativeMethods.MB_USEGLYPHCHARS, bytes, bytes.Length, sbuilder, EncodingBufferLen); if (nret == 0) { int win32Err = Marshal.GetLastWin32Error(); throw new System.ComponentModel.Win32Exception(win32Err); } // set the length as MultiByteToWideChar returns. sbuilder.Length = nret; return sbuilder.ToString(); } // PreProcessInput event handler ////// Critical - calls a critical method - to create a TextComposition and calls /// Critical methods UnsafeStartComposition, UnsafeUpdateComposition /// and UnsafeCompleteComposition. /// [SecurityCritical] private void PreProcessInput(object sender, PreProcessInputEventArgs e) { // KeyDown --> Alt Numpad // // We eat Alt-NumPat keys and handle them by ourselves. Avalon has its own acceralator handler // and it may have a corrision with Win32k's AltNumPad handling. As a result, the AltNumPad cache // in Win32k's ToUnicodeEx() could be broken. // if (e.StagingItem.Input.RoutedEvent == Keyboard.KeyDownEvent) { KeyEventArgs keyArgs = (KeyEventArgs) e.StagingItem.Input; if (!keyArgs.Handled) { if (!_altNumpadEntryMode) { EnterAltNumpadEntryMode(keyArgs.RealKey); } else { if (HandleAltNumpadEntry(keyArgs.RealKey, keyArgs.ScanCode, keyArgs.IsExtendedKey)) { if (_altNumpadcomposition == null) { _altNumpadcomposition = new TextComposition(_inputManager, (IInputElement)keyArgs.Source, "", TextCompositionAutoComplete.Off, keyArgs.Device); keyArgs.Handled = UnsafeStartComposition(_altNumpadcomposition); } else { _altNumpadcomposition.ClearTexts(); keyArgs.Handled = UnsafeUpdateComposition(_altNumpadcomposition); } // We ate this key for AltNumPad entry. None will be able to handle this. e.Cancel(); } else { // alt numpad entry was reset so composition needs to be finalized. if (_altNumpadcomposition != null) { _altNumpadcomposition.ClearTexts(); _altNumpadcomposition.Complete(); ClearAltnumpadComposition(); } } } } } } // PostProcessInput event handler //////Critical- calls critical functions pushInput, UnsafeStartComposition and /// UnsafeUpdateComposition. /// [SecurityCritical] private void PostProcessInput(object sender, ProcessInputEventArgs e) { // KeyUp if(e.StagingItem.Input.RoutedEvent == Keyboard.KeyUpEvent) { KeyEventArgs keyArgs = (KeyEventArgs) e.StagingItem.Input; if(!keyArgs.Handled) { if(keyArgs.RealKey == Key.LeftAlt || keyArgs.RealKey == Key.RightAlt) { // Make sure both Alt keys are up. ModifierKeys modifiers = keyArgs.KeyboardDevice.Modifiers; if((modifiers & ModifierKeys.Alt) == 0) { if(_altNumpadEntryMode) { _altNumpadEntryMode = false; // Generate the Unicode equivalent if we // actually entered a number via the numpad. if(_altNumpadEntry != 0) { _altNumpadcomposition.ClearTexts(); if (_altNumpadConversionMode == AltNumpadConversionMode.OEMCodePage) { _altNumpadcomposition.SetText(GetCurrentOEMCPEncoding(_altNumpadEntry)); } else if ((_altNumpadConversionMode == AltNumpadConversionMode.DefaultCodePage) || (_altNumpadConversionMode == AltNumpadConversionMode.HexDefaultCodePage)) { _altNumpadcomposition.SetText(CharacterEncoding(InputLanguageManager.Current.CurrentInputLanguage.TextInfo.ANSICodePage, _altNumpadEntry)); } else if (_altNumpadConversionMode == AltNumpadConversionMode.HexUnicode) { Char[] chars = new Char[1]; chars[0] = (Char) _altNumpadEntry; _altNumpadcomposition.SetText(new string(chars)); } } } } } } else { // Someone handled Alt key up event, we cancel Alt-Numpad handling. _altNumpadEntryMode = false; _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.OEMCodePage; } } // PreviewTextInputBegin --> TextInputStart else if(e.StagingItem.Input.RoutedEvent == TextCompositionManager.PreviewTextInputStartEvent) { TextCompositionEventArgs textArgs = (TextCompositionEventArgs) e.StagingItem.Input; if(!textArgs.Handled) { TextCompositionEventArgs text = new TextCompositionEventArgs(textArgs.Device, textArgs.TextComposition); text.RoutedEvent=TextCompositionManager.TextInputStartEvent; text.Source= textArgs.TextComposition.Source; e.PushInput(text, e.StagingItem); } } // PreviewTextInputUpdate --> TextInputUpdate else if(e.StagingItem.Input.RoutedEvent == TextCompositionManager.PreviewTextInputUpdateEvent) { TextCompositionEventArgs textArgs = (TextCompositionEventArgs) e.StagingItem.Input; if(!textArgs.Handled) { TextCompositionEventArgs text = new TextCompositionEventArgs(textArgs.Device, textArgs.TextComposition); text.RoutedEvent=TextCompositionManager.TextInputUpdateEvent; text.Source= textArgs.TextComposition.Source; e.PushInput(text, e.StagingItem); } } // PreviewTextInput --> TextInput else if(e.StagingItem.Input.RoutedEvent == TextCompositionManager.PreviewTextInputEvent) { TextCompositionEventArgs textArgs = (TextCompositionEventArgs) e.StagingItem.Input; if(!textArgs.Handled) { TextCompositionEventArgs text = new TextCompositionEventArgs(textArgs.Device, textArgs.TextComposition); text.RoutedEvent=TextCompositionManager.TextInputEvent; text.Source= textArgs.TextComposition.Source; e.PushInput(text, e.StagingItem); } } // TextCompositioniBegin --> TextInput if this is AutomaticComplete. else if(e.StagingItem.Input.RoutedEvent == TextCompositionManager.TextInputStartEvent) { TextCompositionEventArgs textArgs = (TextCompositionEventArgs) e.StagingItem.Input; if(!textArgs.Handled) { if (textArgs.TextComposition.AutoComplete == TextCompositionAutoComplete.On) { textArgs.Handled = UnsafeCompleteComposition(textArgs.TextComposition); } } } // TextCompositionUpdate --> TextInput if this is AutomaticComplete. else if(e.StagingItem.Input.RoutedEvent == TextCompositionManager.TextInputUpdateEvent) { TextCompositionEventArgs textArgs = (TextCompositionEventArgs) e.StagingItem.Input; if(!textArgs.Handled) { if ((textArgs.TextComposition == _deadCharTextComposition) && (_deadCharTextComposition.Composed)) { textArgs.Handled = UnsafeCompleteComposition(_deadCharTextComposition); _deadCharTextComposition = null; } } } // Raw to StartComposition. InputReportEventArgs input = e.StagingItem.Input as InputReportEventArgs; if(input != null) { if(input.Report.Type == InputType.Text && input.RoutedEvent == InputManager.InputReportEvent) { RawTextInputReport textInput; textInput = (RawTextInputReport)input.Report; // // string inputText = new string(textInput.CharacterCode, 1); bool fDoneAltNumpadComposition = false; if (_altNumpadcomposition != null) { // Generate TextInput event from WM_CHAR handler. if (inputText.Equals(_altNumpadcomposition.Text)) { fDoneAltNumpadComposition = true; } else { // The generated text from InputReport does not matched with _altNumpadcomposition. // Cancel this composition and process the char from InputReport. _altNumpadcomposition.ClearTexts(); } _altNumpadcomposition.Complete(); ClearAltnumpadComposition(); } if (!fDoneAltNumpadComposition) { if (textInput.IsDeadCharacter) { _deadCharTextComposition = new DeadCharTextComposition(_inputManager, (IInputElement)null, inputText , TextCompositionAutoComplete.Off, InputManager.Current.PrimaryKeyboardDevice); if (textInput.IsSystemCharacter) { _deadCharTextComposition.MakeSystem(); } else if (textInput.IsControlCharacter) { _deadCharTextComposition.MakeControl(); } input.Handled = UnsafeStartComposition(_deadCharTextComposition); } else { if(inputText != null) { if (_deadCharTextComposition != null) { _deadCharTextComposition.ClearTexts(); _deadCharTextComposition.SetText(inputText); _deadCharTextComposition.Composed = true; if (textInput.IsSystemCharacter) { _deadCharTextComposition.MakeSystem(); } else if (textInput.IsControlCharacter) { _deadCharTextComposition.MakeControl(); } input.Handled = UnsafeUpdateComposition(_deadCharTextComposition); } else { TextComposition composition = new TextComposition(_inputManager, (IInputElement)e.StagingItem.Input.Source, inputText, TextCompositionAutoComplete.On, InputManager.Current.PrimaryKeyboardDevice); if (textInput.IsSystemCharacter) { composition.MakeSystem(); } else if (textInput.IsControlCharacter) { composition.MakeControl(); } input.Handled = UnsafeStartComposition(composition); } } } } } } } // AltNumpad key handler private bool EnterAltNumpadEntryMode(Key key) { bool handled = false; if(key == Key.LeftAlt || key == Key.RightAlt) { if(!_altNumpadEntryMode) { _altNumpadEntryMode = true; _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.OEMCodePage; handled = true; } } return handled; } // AltNumpad key handler private bool HandleAltNumpadEntry(Key key, int scanCode, bool isExtendedKey) { bool handled = false; Debug.Assert(_altNumpadEntryMode); // All Numpad keys (either numlock or not) are not an extended key. // We're interested in only NumPad key so we can filter them first. if (isExtendedKey) { return handled; } // If Alt key is up, we will quit AltNumpadEntryMode. if (!Keyboard.IsKeyDown(Key.LeftAlt) && !Keyboard.IsKeyDown(Key.RightAlt)) { return false; } // // Windows has historically offered a back-door for entering // characters that are not available on the keyboard. The // user can hold down one of the Alt keys, type in the numerical // value of the desried character using the num-pad keys, and // the release the Alt key. The numeric value will be converted // into Unicode, and a text event will // be raised. // if (scanCode == NumpadScanCode.NumpadDot) { if (IsHexNumpadEnabled) { _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.HexDefaultCodePage; handled = true; } else { // reset alt numpad entry and mode. _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.OEMCodePage; handled = false; } } else if (scanCode == NumpadScanCode.NumpadPlus) { if (IsHexNumpadEnabled) { _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.HexUnicode; handled = true; } else { // reset alt numpad entry and mode. _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.OEMCodePage; handled = false; } } else { int newEntry = GetNewEntry(key, scanCode); if (newEntry == -1) { _altNumpadEntry = 0; _altNumpadConversionMode = AltNumpadConversionMode.OEMCodePage; // we don't handle this case to cancel TextComposition. handled = false; } else { // If the first key is NumPad0, it is the default codepage. if ((_altNumpadEntry == 0) && (newEntry == 0)) _altNumpadConversionMode = AltNumpadConversionMode.DefaultCodePage; if (HexConversionMode) _altNumpadEntry = (_altNumpadEntry * 0x10) + newEntry; else _altNumpadEntry = (_altNumpadEntry * 10) + newEntry; handled = true; } } return handled; } // Convert Key and ScanCode to new entry number. private int GetNewEntry(Key key, int scanCode) { if (HexConversionMode) { switch (key) { // We accept digit keys and A-F in HexConversionMode. case Key.D0: return 0x00; case Key.D1: return 0x01; case Key.D2: return 0x02; case Key.D3: return 0x03; case Key.D4: return 0x04; case Key.D5: return 0x05; case Key.D6: return 0x06; case Key.D7: return 0x07; case Key.D8: return 0x08; case Key.D9: return 0x09; case Key.A: return 0x0A; case Key.B: return 0x0B; case Key.C: return 0x0C; case Key.D: return 0x0D; case Key.E: return 0x0E; case Key.F: return 0x0F; } } return NumpadScanCode.DigitFromScanCode(scanCode); } // Convert the code to byte array for DBCS/SBCS. ////// Critical - returns a byte array that is passed into a call under an elevation /// TreatAsSafe - The code calls is safe in terms of what it does the reason it is critical is because /// if there was logic error here in the future it could be used to exploit the elevated call. /// [SecurityCritical, SecurityTreatAsSafe] private static Byte[] ConvertCodeToByteArray(int codeEntry) { Byte[] bytes; if (codeEntry > 0xff) { bytes = new Byte[2]; bytes[0] = (Byte)(codeEntry >> 8); bytes[1] = (Byte)codeEntry; } else { bytes = new Byte[1]; bytes[0] = (Byte)codeEntry; } return bytes; } // clear the altnumpad composition object and reset entry. // the existence of the altnumpad composition object needs to be consistent with altnumpad entry. private void ClearAltnumpadComposition() { _altNumpadcomposition = null; _altNumpadConversionMode = AltNumpadConversionMode.OEMCodePage; _altNumpadEntry = 0; } //------------------------------------------------------ // // Private Properties // //----------------------------------------------------- // Return true if we're in hex conversion mode. private bool HexConversionMode { get { if ((_altNumpadConversionMode == AltNumpadConversionMode.HexDefaultCodePage) || (_altNumpadConversionMode == AltNumpadConversionMode.HexUnicode)) return true; return false; } } ////// Return true if HexNumPad is enabled. /// ////// Critical - asserts registry permissions to read from HKEY_CURRENT_USER. /// Treat as safe - we only read a value from HKEY_CURENT_USER. And we don't expose the value. /// private static bool IsHexNumpadEnabled { [SecurityCritical, SecurityTreatAsSafe ] get { if (!_isHexNumpadRegistryChecked) { // Acquire permissions to read the one key we care about from the registry RegistryPermission permission = new RegistryPermission( RegistryPermissionAccess.Read, "HKEY_CURRENT_USER\\Control Panel\\Input Method"); permission.Assert(); try { object obj; RegistryKey key; key = Registry.CurrentUser.OpenSubKey("Control Panel\\Input Method"); if (key != null) { obj = key.GetValue("EnableHexNumpad"); if ((obj is string) && ((string)obj != "0")) { _isHexNumpadEnabled = true; } } } finally { RegistryPermission.RevertAssert(); } _isHexNumpadRegistryChecked = true; } return _isHexNumpadEnabled; } } //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ // InputManager for this TextCompositionManager ////// Critical - InputManager is critical. /// [SecurityCritical] private readonly InputManager _inputManager; // The current dead char composition. private DeadCharTextComposition _deadCharTextComposition; // The state of AltNumpad mode. private bool _altNumpadEntryMode; // The current value entered from NumPad. private int _altNumpadEntry; // The current AltNumpad conversion mode. private AltNumpadConversionMode _altNumpadConversionMode; // TextComposition for AltNumpad. private TextComposition _altNumpadcomposition; // True if EnableHexNumpad registry has been checked. private static bool _isHexNumpadRegistryChecked = false; // True if EnableHexNumpad registry is set. private static bool _isHexNumpadEnabled = false; // Character encoding length. ////// Critical - Is used to detereming length in a call to unmanaged code which happens under an elevation /// [SecurityCritical] private const int EncodingBufferLen = 4; // ScanCode of Numpad keys. internal static class NumpadScanCode { internal static int DigitFromScanCode(int scanCode) { switch (scanCode) { case Numpad0: return 0; case Numpad1: return 1; case Numpad2: return 2; case Numpad3: return 3; case Numpad4: return 4; case Numpad5: return 5; case Numpad6: return 6; case Numpad7: return 7; case Numpad8: return 8; case Numpad9: return 9; } return -1; } internal const int NumpadDot = 0x53; internal const int NumpadPlus = 0x4e; internal const int Numpad0 = 0x52; internal const int Numpad1 = 0x4f; internal const int Numpad2 = 0x50; internal const int Numpad3 = 0x51; internal const int Numpad4 = 0x4b; internal const int Numpad5 = 0x4c; internal const int Numpad6 = 0x4d; internal const int Numpad7 = 0x47; internal const int Numpad8 = 0x48; internal const int Numpad9 = 0x49; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- InvalidateEvent.cs
- PropertyStore.cs
- SiteMap.cs
- Debug.cs
- InputReferenceExpression.cs
- MetadataPropertyAttribute.cs
- TypeSemantics.cs
- ZipIOExtraFieldPaddingElement.cs
- Merger.cs
- ConfigurationSettings.cs
- SessionStateContainer.cs
- TableLayoutPanelCellPosition.cs
- CultureInfo.cs
- SqlProcedureAttribute.cs
- GatewayDefinition.cs
- TriggerBase.cs
- PointConverter.cs
- EpmHelper.cs
- XmlNodeWriter.cs
- FixedDSBuilder.cs
- TableDetailsCollection.cs
- FullTextBreakpoint.cs
- followingsibling.cs
- ExpandedProjectionNode.cs
- ISAPIApplicationHost.cs
- securestring.cs
- MultiByteCodec.cs
- DbQueryCommandTree.cs
- PropertyDescriptorGridEntry.cs
- BevelBitmapEffect.cs
- GacUtil.cs
- PathTooLongException.cs
- DocumentPageView.cs
- EventSourceCreationData.cs
- OleDbReferenceCollection.cs
- MdiWindowListStrip.cs
- DataGridViewElement.cs
- XmlSerializationWriter.cs
- NotSupportedException.cs
- NamespaceInfo.cs
- DataObjectSettingDataEventArgs.cs
- ExceptionHelpers.cs
- RelatedPropertyManager.cs
- ScriptingJsonSerializationSection.cs
- DrawingAttributeSerializer.cs
- MessageLoggingFilterTraceRecord.cs
- TimeSpan.cs
- ResourcePropertyMemberCodeDomSerializer.cs
- WebServiceClientProxyGenerator.cs
- ControlBuilderAttribute.cs
- GlobalDataBindingHandler.cs
- EnumDataContract.cs
- QueryAccessibilityHelpEvent.cs
- MobileErrorInfo.cs
- ETagAttribute.cs
- InputScope.cs
- Byte.cs
- EntityDataSourceDataSelection.cs
- VectorValueSerializer.cs
- SByteConverter.cs
- MSHTMLHost.cs
- ListViewDesigner.cs
- BindingEditor.xaml.cs
- RectangleHotSpot.cs
- StorageAssociationSetMapping.cs
- RemotingAttributes.cs
- ReadOnlyCollectionBase.cs
- EntityCommandDefinition.cs
- WMICapabilities.cs
- SqlDataReaderSmi.cs
- ConstraintConverter.cs
- GridItemCollection.cs
- GorillaCodec.cs
- WaitHandle.cs
- Visual3D.cs
- RightsManagementInformation.cs
- IPCCacheManager.cs
- SettingsAttributeDictionary.cs
- NominalTypeEliminator.cs
- SystemIPGlobalProperties.cs
- NativeMethods.cs
- StateBag.cs
- SiteMapSection.cs
- SvcMapFileLoader.cs
- PolicyStatement.cs
- TextBox.cs
- LabelDesigner.cs
- DefaultObjectMappingItemCollection.cs
- mediaeventshelper.cs
- InputReferenceExpression.cs
- WorkflowNamespace.cs
- DataTableTypeConverter.cs
- MailAddress.cs
- ListSurrogate.cs
- BoolExpr.cs
- DesignerImageAdapter.cs
- SiteMapDesignerDataSourceView.cs
- StyleTypedPropertyAttribute.cs
- DataSourceControl.cs
- ResolveNameEventArgs.cs