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.
This commit is contained in:
Marc Durdin 2021-03-10 10:34:55 +11:00
parent c83f595622
commit 67bfdb970b
3 changed files with 49 additions and 2 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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,