public void UpdateAvailableKeyboards() { var curKeyboards = KeyboardController.Instance.Keyboards.OfType <WinKeyboardDescription>().ToDictionary(kd => kd.Id); foreach (InputLanguage inputLanguage in InputLanguage.InstalledInputLanguages) { string keyboardId; LayoutName keyboardLayoutName; CultureInfo culture; string cultureName; try { culture = new CultureInfo(inputLanguage.Culture.Name); cultureName = culture.DisplayName; keyboardId = $"{culture.Name}_{inputLanguage.LayoutName}"; keyboardLayoutName = GetBestAvailableKeyboardName(inputLanguage); } catch (CultureNotFoundException) { // This can happen for old versions of Keyman that created a custom culture that is invalid to .Net. // Also see http://stackoverflow.com/a/24820530/4953232 culture = new CultureInfo("en-US"); cultureName = "[Unknown Language]"; keyboardId = $"{cultureName}_{inputLanguage.LayoutName}"; keyboardLayoutName = new LayoutName(inputLanguage.LayoutName, inputLanguage.LayoutName); } WinKeyboardDescription existingKeyboard; if (curKeyboards.TryGetValue(keyboardId, out existingKeyboard)) { if (!existingKeyboard.IsAvailable) { existingKeyboard.SetIsAvailable(true); existingKeyboard.SetLocalizedName(keyboardLayoutName.LocalizedName); } curKeyboards.Remove(keyboardId); } else { // Prevent a keyboard with this id from being registered again. // Potentially, id's are duplicated. e.g. A Keyman keyboard linked to a windows one. // For now we simply ignore this second registration. // A future enhancement would be to include knowledge of the driver in the Keyboard definition so // we could choose the best one to register. KeyboardDescription keyboard; if (!KeyboardController.Instance.Keyboards.TryGet(keyboardId, out keyboard)) { KeyboardController.Instance.Keyboards.Add( new WinKeyboardDescription(keyboardId, GetDisplayName(keyboardLayoutName.LocalizedName, cultureName), keyboardLayoutName.Name, culture.Name, true, new InputLanguageWrapper(inputLanguage), this)); } } } // Set each unhanandled keyboard to unavailable foreach (var existingKeyboard in curKeyboards.Values) { existingKeyboard.SetIsAvailable(false); } }
private IEnumerable <LayoutName> GetAvailableKeyboardNames(InputLanguage inputLanguage) { IEnumTfInputProcessorProfiles profilesEnumerator; try { profilesEnumerator = ProfileManager.EnumProfiles((short)inputLanguage.Culture.KeyboardLayoutId); } catch (Exception e) { Debug.WriteLine($"Error looking up keyboards for language {inputLanguage.Culture.Name} - {(short)inputLanguage.Culture.KeyboardLayoutId}"); yield break; } TfInputProcessorProfile[] profiles = new TfInputProcessorProfile[1]; bool returnedLanguage = false; while (profilesEnumerator.Next(1, profiles) == 1) { // We only deal with keyboards; skip other input methods if (profiles[0].CatId != Guids.Consts.TfcatTipKeyboard) { continue; } if ((profiles[0].Flags & TfIppFlags.Enabled) == 0) { continue; } if (profiles[0].ProfileType == TfProfileType.Illegal) { continue; } LayoutName layoutName; if (profiles[0].Hkl == IntPtr.Zero) { returnedLanguage = true; layoutName = new LayoutName(inputLanguage.LayoutName, ProcessorProfiles.GetLanguageProfileDescription(ref profiles[0].ClsId, profiles[0].LangId, ref profiles[0].GuidProfile), profiles[0]); yield return(layoutName); } else { layoutName = WinKeyboardUtils.GetLayoutNameEx(profiles[0].Hkl); if (layoutName.Name != string.Empty) { layoutName.Profile = profiles[0]; returnedLanguage = true; yield return(layoutName); } } } if (!returnedLanguage) { yield return(new LayoutName(inputLanguage.LayoutName, inputLanguage.Culture.DisplayName)); } }
private IEnumerable <LayoutName> GetAvailableKeyboardNames(InputLanguage inputLanguage) { IEnumTfInputProcessorProfiles profilesEnumerator; string cultureName; var culture = GetCultureInfoFromInputLanguage(inputLanguage, out cultureName); if (cultureName == UnknownLanguage) { Debug.WriteLine($"Error looking up keyboards with layout {inputLanguage.LayoutName} - invalid culture"); yield break; } try { profilesEnumerator = ProfileManager.EnumProfiles((short)culture.KeyboardLayoutId); } catch { Debug.WriteLine($"Error looking up keyboards for language {culture.Name} - {(short)culture.KeyboardLayoutId}"); yield break; } TfInputProcessorProfile[] profiles = new TfInputProcessorProfile[1]; bool returnedLanguage = false; while (profilesEnumerator.Next(1, profiles) == 1) { // We only deal with keyboards; skip other input methods if (profiles[0].CatId != Guids.Consts.TfcatTipKeyboard) { continue; } if ((profiles[0].Flags & TfIppFlags.Enabled) == 0) { continue; } if (profiles[0].ProfileType == TfProfileType.Illegal) { continue; } LayoutName layoutName; if (profiles[0].Hkl == IntPtr.Zero) { try { layoutName = new LayoutName(inputLanguage.LayoutName, ProcessorProfiles.GetLanguageProfileDescription(ref profiles[0].ClsId, profiles[0].LangId, ref profiles[0].GuidProfile), profiles[0]); } catch { // this exception has happened in testing, doesn't seem to be anything we can do // except just ignore this keyboard continue; } returnedLanguage = true; yield return(layoutName); } else { layoutName = WinKeyboardUtils.GetLayoutNameEx(profiles[0].Hkl); if (layoutName.Name != string.Empty) { layoutName.Profile = profiles[0]; returnedLanguage = true; yield return(layoutName); } } } if (!returnedLanguage) { yield return(new LayoutName(inputLanguage.LayoutName, culture.DisplayName)); } }
private void GetInputMethods() { IEnumerable <Tuple <TfInputProcessorProfile, ushort, IntPtr> > imes; if (ProfileMgr != null) { // Windows >= Vista imes = GetInputMethodsThroughTsf(); } else { // Windows XP imes = GetInputMethodsThroughWinApi(); } var allKeyboards = KeyboardController.Instance.Keyboards; Dictionary <string, WinKeyboardDescription> curKeyboards = allKeyboards.OfType <WinKeyboardDescription>().ToDictionary(kd => kd.Id); foreach (Tuple <TfInputProcessorProfile, ushort, IntPtr> ime in imes) { TfInputProcessorProfile profile = ime.Item1; ushort langId = ime.Item2; IntPtr hkl = ime.Item3; CultureInfo culture; string locale; string cultureName; try { culture = new CultureInfo(langId); cultureName = culture.DisplayName; locale = culture.Name; } catch (CultureNotFoundException) { // This can happen for old versions of Keyman that created a custom culture that is invalid to .Net. // Also see http://stackoverflow.com/a/24820530/4953232 culture = new CultureInfo("en-US"); cultureName = "[Unknown Language]"; locale = "en-US"; } try { LayoutName layoutName; if (profile.Hkl == IntPtr.Zero && profile.ProfileType != TfProfileType.Illegal) { layoutName = new LayoutName(ProcessorProfiles.GetLanguageProfileDescription( ref profile.ClsId, profile.LangId, ref profile.GuidProfile)); } else { layoutName = GetLayoutNameEx(hkl); } string id = GetId(layoutName.Name, locale); WinKeyboardDescription existingKeyboard; if (curKeyboards.TryGetValue(id, out existingKeyboard)) { if (!existingKeyboard.IsAvailable) { existingKeyboard.SetIsAvailable(true); existingKeyboard.InputProcessorProfile = profile; existingKeyboard.SetLocalizedName(GetDisplayName(layoutName.LocalizedName, cultureName)); } curKeyboards.Remove(id); } else { // Prevent a keyboard with this id from being registered again. // Potentially, id's are duplicated. e.g. A Keyman keyboard linked to a windows one. // For now we simply ignore this second registration. // A future enhancement would be to include knowledge of the driver in the Keyboard definition so // we could choose the best one to register. KeyboardDescription keyboard; if (!allKeyboards.TryGet(id, out keyboard)) { KeyboardController.Instance.Keyboards.Add( new WinKeyboardDescription(id, GetDisplayName(layoutName.Name, cultureName), layoutName.Name, locale, true, new InputLanguageWrapper(culture, hkl, layoutName.Name), this, GetDisplayName(layoutName.LocalizedName, cultureName), profile)); } } } catch (COMException) { // this can happen when the user changes the language associated with a // Keyman keyboard (LT-16172) } } foreach (WinKeyboardDescription existingKeyboard in curKeyboards.Values) { existingKeyboard.SetIsAvailable(false); } }