| File: System\Windows\Input\InputLanguageManager.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationCore\PresentationCore.csproj (PresentationCore) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Windows.Threading; using System.Globalization; using MS.Win32; using System.ComponentModel; namespace System.Windows.Input { /// <summary> /// The InputLanguageManager class is responsible for mmanaging /// the input language in Avalon. /// </summary> public sealed class InputLanguageManager : DispatcherObject { /// <summary> /// This is the property of the preferred input language of the /// element. /// When the element get focus, this input language is selected /// automatically. /// </summary> public static readonly DependencyProperty InputLanguageProperty = DependencyProperty.RegisterAttached( "InputLanguage", typeof(CultureInfo), typeof(InputLanguageManager), new PropertyMetadata(CultureInfo.InvariantCulture) ); /// <summary> /// Setter for InputLanguage DependencyProperty /// </summary> public static void SetInputLanguage(DependencyObject target, CultureInfo inputLanguage) { ArgumentNullException.ThrowIfNull(target); target.SetValue(InputLanguageProperty, inputLanguage); } /// <summary> /// Getter for InputLanguage DependencyProperty /// </summary> [AttachedPropertyBrowsableForType(typeof(DependencyObject))] [TypeConverter(typeof(System.Windows.CultureInfoIetfLanguageTagConverter))] public static CultureInfo GetInputLanguage(DependencyObject target) { ArgumentNullException.ThrowIfNull(target); return (CultureInfo)(target.GetValue(InputLanguageProperty)); } /// <summary> /// If this is true, the previous inputlanguage is restored /// when the element with InputLanguage dynamicproperty lose the focus. /// This property is ignored if InputLanguage dynamic property is /// not available in the element. /// </summary> public static readonly DependencyProperty RestoreInputLanguageProperty = DependencyProperty.RegisterAttached( "RestoreInputLanguage", typeof(bool), typeof(InputLanguageManager), new PropertyMetadata(false) ); /// <summary> /// Setter for RestoreInputLanguage DependencyProperty /// </summary> public static void SetRestoreInputLanguage(DependencyObject target, bool restore) { ArgumentNullException.ThrowIfNull(target); target.SetValue(RestoreInputLanguageProperty, restore); } /// <summary> /// Getter for RestoreInputLanguage DependencyProperty /// </summary> [AttachedPropertyBrowsableForType(typeof(DependencyObject))] public static bool GetRestoreInputLanguage(DependencyObject target) { ArgumentNullException.ThrowIfNull(target); return (bool)(target.GetValue(RestoreInputLanguageProperty)); } //------------------------------------------------------ // // Constructors // //------------------------------------------------------ private InputLanguageManager() { // register our default input language source. RegisterInputLanguageSource(new InputLanguageSource(this)); } //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Registers an input language soruces with the input /// input language manager. /// </summary> /// <param name="inputLanguageSource"> /// The input language source to register. /// </param> public void RegisterInputLanguageSource(IInputLanguageSource inputLanguageSource) { ArgumentNullException.ThrowIfNull(inputLanguageSource); _source = inputLanguageSource; if (((_InputLanguageChanged != null) || (_InputLanguageChanging != null)) && IsMultipleKeyboardLayout) _source.Initialize(); return; } /// <summary> /// Report the input language is changed from the source. /// </summary> /// <param name="newLanguageId"> /// The new language id. /// </param> /// <param name="previousLanguageId"> /// The previous language id. /// </param> public void ReportInputLanguageChanged( CultureInfo newLanguageId, CultureInfo previousLanguageId) { ArgumentNullException.ThrowIfNull(newLanguageId); ArgumentNullException.ThrowIfNull(previousLanguageId); // // if this language change was not done by SetFocus() and // InputLanguage Property of the element, we clear _previousLanguageId. // if (!previousLanguageId.Equals(_previousLanguageId)) { _previousLanguageId = null; } if (_InputLanguageChanged != null) { InputLanguageChangedEventArgs args = new InputLanguageChangedEventArgs(newLanguageId, previousLanguageId); // Stability Review: Task#32416 // - No state to be restored even exception happens while this callback. _InputLanguageChanged(this, args); } } /// <summary> /// Report the input language is being changed from the source. /// </summary> /// <param name="newLanguageId"> /// The new language id. /// </param> /// <param name="previousLanguageId"> /// The previous language id. /// </param> public bool ReportInputLanguageChanging( CultureInfo newLanguageId, CultureInfo previousLanguageId) { ArgumentNullException.ThrowIfNull(newLanguageId); ArgumentNullException.ThrowIfNull(previousLanguageId); bool accepted = true; if (_InputLanguageChanging != null) { InputLanguageChangingEventArgs args = new InputLanguageChangingEventArgs(newLanguageId, previousLanguageId); // Stability Review: Task#32416 // - No state to be restored even exception happens while this callback. _InputLanguageChanging(this, args); accepted = args.Rejected ? false : true; } return accepted; } #endregion Public Methods //------------------------------------------------------ // // Public Operators // //------------------------------------------------------ //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ /// <summary> /// Return the input language manager associated /// with the current context. /// </summary> public static InputLanguageManager Current { get { // InputLanguageManager for the current Dispatcher is stored in InputMethod of // the current Dispatcher. if(InputMethod.Current.InputLanguageManager == null) { InputMethod.Current.InputLanguageManager = new InputLanguageManager(); } return InputMethod.Current.InputLanguageManager; } } /// <summary> /// This accesses the input language associated /// with the current context. /// </summary> [TypeConverter(typeof(System.Windows.CultureInfoIetfLanguageTagConverter))] public CultureInfo CurrentInputLanguage { get { // If the source is available, we should use it. if (_source != null) { return _source.CurrentInputLanguage; } IntPtr hkl = SafeNativeMethods.GetKeyboardLayout(0); if (hkl == IntPtr.Zero) { return CultureInfo.InvariantCulture; } // This needs to work before source is attached. return new CultureInfo((short)NativeMethods.IntPtrToInt32(hkl)); } set { ArgumentNullException.ThrowIfNull(value); SetSourceCurrentLanguageId(value); } } /// <summary> /// Return enumerator for available input languages. /// </summary> public IEnumerable AvailableInputLanguages { get { if (_source == null) { return null; } return _source.InputLanguageList; } } //------------------------------------------------------ // // Public Events // //------------------------------------------------------ /// <summary> /// This is an event when the input language is changed. /// </summary> public event InputLanguageEventHandler InputLanguageChanged { add { ArgumentNullException.ThrowIfNull(value); if ((_InputLanguageChanged == null) && (_InputLanguageChanging == null) && IsMultipleKeyboardLayout && (_source != null)) _source.Initialize(); _InputLanguageChanged += value; } remove { ArgumentNullException.ThrowIfNull(value); _InputLanguageChanged -= value; if ((_InputLanguageChanged == null) && (_InputLanguageChanging == null) && IsMultipleKeyboardLayout && (_source != null)) _source.Uninitialize(); } } /// <summary> /// This is an event when the input language is being changed. /// </summary> public event InputLanguageEventHandler InputLanguageChanging { add { ArgumentNullException.ThrowIfNull(value); if ((_InputLanguageChanged == null) && (_InputLanguageChanging == null) && IsMultipleKeyboardLayout && (_source != null)) _source.Initialize(); _InputLanguageChanging += value; } remove { ArgumentNullException.ThrowIfNull(value); _InputLanguageChanging -= value; if ((_InputLanguageChanged == null) && (_InputLanguageChanging == null) && IsMultipleKeyboardLayout && (_source != null)) _source.Uninitialize(); } } //------------------------------------------------------ // // Protected Methods // //------------------------------------------------------ //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods /// <summary> /// When keyboard device gets focus, this is called. /// We will check the preferred input language of focus element. /// </summary> internal void Focus(DependencyObject focus, DependencyObject focused) { CultureInfo culture = null; if (focus != null) { // // Check the InputLanguageProperty of the focus element. // culture = (CultureInfo)focus.GetValue(InputLanguageProperty); } if ((culture == null) || (culture.Equals(CultureInfo.InvariantCulture))) { // // If the focus element does not have InputLanguage property, // we may need to restore the previous input language. // if (focused != null) { if ((_previousLanguageId != null) && (bool)focused.GetValue(RestoreInputLanguageProperty)) { // // set the current language id of source. // SetSourceCurrentLanguageId(_previousLanguageId); } _previousLanguageId = null; } } else { // Cache the previous language id. // _previousLanguageId can be clear during SetSourceCurrentLanguageId() because the call back // ReportInputLanguageChanged() is called. We need to remember the current input language // to update _previousLanguageId. CultureInfo previousLanguageId = _source.CurrentInputLanguage; // // set the current language id of source. // SetSourceCurrentLanguageId(culture); _previousLanguageId = previousLanguageId; } } #endregion Internal methods //------------------------------------------------------ // // Internal Properties // //------------------------------------------------------ #region Internal Properties internal IInputLanguageSource Source { get { return _source; } } /// <summary> /// This checks if there is two or more keyboard layouts. /// </summary> internal static bool IsMultipleKeyboardLayout { get { int count = SafeNativeMethods.GetKeyboardLayoutList(0, null); return (count > 1); } } #endregion Internal Properties //------------------------------------------------------ // // Private Methods // //------------------------------------------------------ private void SetSourceCurrentLanguageId(CultureInfo languageId) { if (_source == null) { throw new InvalidOperationException(SR.InputLanguageManager_NotReadyToChangeCurrentLanguage); } _source.CurrentInputLanguage = languageId; } //------------------------------------------------------ // // Private Events // //------------------------------------------------------ /// <summary> /// This is an event when the input language is changed. /// </summary> private event InputLanguageEventHandler _InputLanguageChanged; /// <summary> /// This is an event when the input language is being changed. /// </summary> private event InputLanguageEventHandler _InputLanguageChanging; //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ #region Private Fields // the previous input language id this is used for restring input language at // losing focus. private CultureInfo _previousLanguageId; // The reference to the source of input language. private IInputLanguageSource _source; #endregion Private Fields } /// <summary> /// This is a delegate for InputLanguageChanged and /// InputLanguageChanging events. /// </summary> public delegate void InputLanguageEventHandler(Object sender, InputLanguageEventArgs e); }