| File: System\Windows\Input\InputProcessorProfiles.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. // // Description: Creates ITfInputProcessorProfiles instances. // using System.Runtime.InteropServices; using System.Globalization; using System.Threading; using MS.Win32; namespace System.Windows.Input { /// <summary> /// The <see cref="InputProcessorProfiles"/> class is always associated with hwndInputLanguage class. /// </summary> internal sealed class InputProcessorProfiles { /// <summary> /// InputProcessorProfiles Constructor; /// </summary> internal InputProcessorProfiles() { // _ipp is a ValueType, hence no need for new. _ipp = null; _cookie = UnsafeNativeMethods.TF_INVALID_COOKIE; } /// <summary> /// Initialize an interface and notify sink. /// </summary> internal bool Initialize(object o) { Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.STA, "Initialize called on MTA thread!"); Debug.Assert(_ipp == null, "Initialize called twice"); _ipp = InputProcessorProfilesLoader.Load(); if (_ipp == null) { return false; } AdviseNotifySink(o); return true; } /// <summary> /// Initialize an interface and notify sink. /// </summary> internal void Uninitialize() { Debug.Assert(_ipp != null, "Uninitialize called without initializing"); UnadviseNotifySink(); Marshal.ReleaseComObject(_ipp); _ipp = null; } /// <summary> /// Get the current input language of the current thread. /// </summary> internal short CurrentInputLanguage { set { if (_ipp != null) { if (_ipp.ChangeCurrentLanguage(value) != 0) { // // Under WinXP or W2K3, ITfInputProcessorProfiles::ChangeCurrentLanguage() fails // if there is no thread manager in the current thread. This is fixed on // Windows Vista+ IntPtr[] hklList = null; int count = (int)SafeNativeMethods.GetKeyboardLayoutList(0, null); if (count > 1) { hklList = new IntPtr[count]; count = SafeNativeMethods.GetKeyboardLayoutList(count, hklList); int i; for (i = 0; (i < hklList.Length) && (i < count); i++) { if (value == (short)hklList[i]) { SafeNativeMethods.ActivateKeyboardLayout(new HandleRef(this, hklList[i]), 0); break; } } } } } } } /// <summary> /// Get the list of the input languages that are available in the current thread. /// </summary> internal unsafe CultureInfo[] InputLanguageList { get { // ITfInputProcessorProfiles::GetLanguageList returns the pointer that was allocated by CoTaskMemAlloc(). _ipp.GetLanguageList(out nint ptrLanguageIDs, out int nCount); ReadOnlySpan<short> languageIDs = new((void*)ptrLanguageIDs, nCount); CultureInfo[] langArray = new CultureInfo[nCount]; // Create CultureInfo from each ID and store it for (int i = 0; i < langArray.Length; i++) langArray[i] = new CultureInfo(languageIDs[i]); // Call CoTaskMemFree(). Marshal.FreeCoTaskMem(ptrLanguageIDs); return langArray; } } /// <summary> /// This advices the input language notify sink to /// ITfInputProcessorProfile. /// </summary> private void AdviseNotifySink(object o) { Debug.Assert(_cookie == UnsafeNativeMethods.TF_INVALID_COOKIE, "Cookie is already set."); UnsafeNativeMethods.ITfSource source = _ipp as UnsafeNativeMethods.ITfSource; // workaround because I can't pass a ref to a readonly constant Guid guid = UnsafeNativeMethods.IID_ITfLanguageProfileNotifySink; source.AdviseSink(ref guid, o, out _cookie); } /// <summary> /// This unadvises the sink. /// </summary> private void UnadviseNotifySink() { Debug.Assert(_cookie != UnsafeNativeMethods.TF_INVALID_COOKIE, "Cookie is not set."); UnsafeNativeMethods.ITfSource source = _ipp as UnsafeNativeMethods.ITfSource; source.UnadviseSink(_cookie); _cookie = UnsafeNativeMethods.TF_INVALID_COOKIE; } /// <summary> /// The reference to <see cref="UnsafeNativeMethods.ITfInputProcessorProfiles"/>. /// </summary> private UnsafeNativeMethods.ITfInputProcessorProfiles _ipp; /// <summary> /// The cookie for the advised sink. /// </summary> private int _cookie; } }