From 67bfdb970ba01d9bc2c69e52c62ffd58221f8d44 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 10 Mar 2021 10:34:55 +1100 Subject: [PATCH] fix(windows): Handle disabled profiles and invalid language ids Fixes #4490. Fixes #4435. There are three parts to this: 1. Ensure that transient language profiles associated with a disabled keyboard are enumerated correctly 2. Stop trusting `LocaleNameToLCID` when it returns a transient language id, as it sometimes reports out-of-date values. We don't need to trust it in these cases anyway, because we have already collected the relevant transient language data from Win8Languages. 3. Finally, setting the profile GUID to `GUID_NULL` is simply tidyup, which does not have impact on the running code currently but makes state consistent. I believe that part 2 fixes #4435 because the symptoms are identical. But as I am unable to repro that particular issue on my machine thus far, that is an assumption. Hopefully we can get a good test result from @MakaraSok. --- .../keymankeyboardlanguageinstalled.pas | 5 +-- .../keymankeyboardlanguagesinstalled.pas | 35 +++++++++++++++++++ ...stem.Process.KPInstallKeyboardLanguage.pas | 11 ++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/windows/src/engine/kmcomapi/com/keyboardlanguages/keymankeyboardlanguageinstalled.pas b/windows/src/engine/kmcomapi/com/keyboardlanguages/keymankeyboardlanguageinstalled.pas index a195176f73..990386f0eb 100644 --- a/windows/src/engine/kmcomapi/com/keyboardlanguages/keymankeyboardlanguageinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboardlanguages/keymankeyboardlanguageinstalled.pas @@ -134,9 +134,10 @@ begin try UninstallTip(FOwner.ID, Get_LangID, Get_ProfileGUID, False); if IsTransientLanguageID(Get_LangID) then - // TODO: this breaks re-enabling the keyboard because the reg entry is - // still referring to the old langid. + begin SetLangID(0); + FProfileGUID := GUID_NULL; + end; finally Free; end; diff --git a/windows/src/engine/kmcomapi/com/keyboardlanguages/keymankeyboardlanguagesinstalled.pas b/windows/src/engine/kmcomapi/com/keyboardlanguages/keymankeyboardlanguagesinstalled.pas index c9b6b75b9f..6f17470667 100644 --- a/windows/src/engine/kmcomapi/com/keyboardlanguages/keymankeyboardlanguagesinstalled.pas +++ b/windows/src/engine/kmcomapi/com/keyboardlanguages/keymankeyboardlanguagesinstalled.pas @@ -252,12 +252,47 @@ procedure TKeymanKeyboardLanguagesInstalled.DoRefresh; end; end; + // Adds custom transient profiles for a disabled + // keyboard which will not be found by enumerating + // LM values. + procedure RefreshDisabledProfiles; + var + reg: TRegistryErrorControlled; + RootPath: string; + ids: TStringList; + id: string; + begin + if FOwner.Loaded then + Exit; + + ids := TStringList.Create; + reg := TRegistryErrorControlled.Create(KEY_READ); + try + RootPath := GetRegistryKeyboardActiveKey_CU(FOwner.ID) + '\' + SRegSubKey_KeyboardLanguages; + if reg.OpenKeyReadOnly(RootPath) then + begin + reg.GetValueNames(ids); + for id in ids do + begin + if not HasLanguage(id) then + begin + FLanguages.Add(TKeymanKeyboardLanguageInstalled.Create(Context, FOwner, id, 0, GUID_NULL, '')); + end; + end; + end; + finally + reg.Free; + ids.Free; + end; + end; + begin KL.MethodEnter(Self, 'DoRefresh', []); try RefreshProfiles; RefreshTransientProfiles; RefreshSuggestedLanguages; + RefreshDisabledProfiles; finally KL.MethodExit(Self, 'DoRefresh'); end; diff --git a/windows/src/engine/kmcomapi/processes/keyboard/Keyman.System.Process.KPInstallKeyboardLanguage.pas b/windows/src/engine/kmcomapi/processes/keyboard/Keyman.System.Process.KPInstallKeyboardLanguage.pas index ef4c1c2e64..d4c8208c2f 100644 --- a/windows/src/engine/kmcomapi/processes/keyboard/Keyman.System.Process.KPInstallKeyboardLanguage.pas +++ b/windows/src/engine/kmcomapi/processes/keyboard/Keyman.System.Process.KPInstallKeyboardLanguage.pas @@ -326,6 +326,17 @@ begin Exit(False); end; + if PRIMARYLANGID(LangID) = 0 then + begin + // LocaleNameToLCID can return a recently uninstalled transient LangID, but + // attempts to use that LangID result in an 'unknown locale' being + // installed, or a default locale being associated with the keyboard. Given + // an installed transient language will always be found in the + // Win8LanguageList, we should then assume that LocaleNameToLCID is lying to + // us and look for a new transient language id to be applied instead. + Exit(False); + end; + case LangID of LOCALE_CUSTOM_DEFAULT,