spiegel-keyman/windows/src/engine/kmcomapi/processes/keyboard/Keyman.System.MitigateWin10_1803LanguageInstall.pas
Marc Durdin 227e023cdd fix(windows): disable mitigation for Windows 10 build 19597 and later
Fixes #1285.

If running Windows 10 19597 or later, the underlying issue has
been addressed, so disable the mitigation for new installs of
the keyboard. Does not attempt to change the language code if
the keyboard is already installed.
2020-12-21 08:56:34 +11:00

124 lines
4 KiB
ObjectPascal

// See discussion online at https://github.com/keymanapp/keyman/issues/1285
// Introduced in Keyman 11. Back ported to Keyman 10. If Microsoft introduces
// a fix in a later release, we will need to update this to turn the mitigation
// off for that version. In that situation, users will need to reinstall their
// language profile in order to get the corrected language.
unit Keyman.System.MitigateWin10_1803LanguageInstall;
interface
uses
Winapi.Windows;
type
TMitigateWin10_1803 = class
type
TLanguageReference = record
Code: LANGID;
BCP47: string;
Name: string;
end;
TMitigatedLanguage = record
OriginalLanguage: TLanguageReference;
NewLanguage: TLanguageReference;
end;
class function IsMitigationRequired(Code: LANGID; var lang: TMitigateWin10_1803.TMitigatedLanguage): Boolean; overload;
class function IsMitigationRequired(BCP47Tag: string; var lang: TMitigateWin10_1803.TMitigatedLanguage): Boolean; overload;
end;
implementation
uses
System.SysUtils;
const
MitigatedLanguages: array[0..2] of TMitigateWin10_1803.TMitigatedLanguage = (
(OriginalLanguage: (Code: $005E; BCP47: 'am'; Name: 'Amharic'); NewLanguage: (BCP47: 'gez-Ethi-ET'; Name: 'Geez')),
(OriginalLanguage: (Code: $0073; BCP47: 'ti'; Name: 'Tigrinya'); NewLanguage: (BCP47: 'gez-Ethi-ET'; Name: 'Geez')),
(OriginalLanguage: (Code: $005B; BCP47: 'si'; Name: 'Sinhala'); NewLanguage: (Code: $0409; Name: 'English (US)'))
);
{ TMitigateWin10_1803 }
const
WINDOWS_10_MAJORVERSION = 10;
WINDOWS_10_MINORVERSION = 0;
WINDOWS_10_BUILDNUMBER_WithFailure = 17134;
WINDOWS_10_BUILDNUMBER_Fixed = 19597;
function IsWindows10_OrGreater_Build(Build: DWORD): BOOL; inline;
var
osvi: OSVERSIONINFOEXW;
dwlConditionMask: DWORDLONG;
begin
// Code pattern comes from Keyman.Winapi.VersionHelpers, but testing also
// build number so cannot use functions already there. This also makes back-porting
// to Keyman 10 simpler.
FillChar(osvi, SizeOf(osvi), 0);
osvi.dwOSVersionInfoSize := SizeOf(osvi);
dwlConditionMask := VerSetConditionMask(
VerSetConditionMask(
VerSetConditionMask(
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
VER_MINORVERSION, VER_GREATER_EQUAL),
VER_BUILDNUMBER, VER_GREATER_EQUAL);
osvi.dwMajorVersion := WINDOWS_10_MAJORVERSION;
osvi.dwMinorVersion := WINDOWS_10_MINORVERSION;
osvi.dwBuildNumber := Build;
Result := VerifyVersionInfoW(osvi, VER_MAJORVERSION or VER_MINORVERSION or VER_BUILDNUMBER, dwlConditionMask) <> False;
end;
class function TMitigateWin10_1803.IsMitigationRequired(Code: LANGID; var lang: TMitigateWin10_1803.TMitigatedLanguage): Boolean;
var
I: Integer;
begin
if not IsWindows10_OrGreater_Build(WINDOWS_10_BUILDNUMBER_WithFailure) then
Exit(False);
if IsWindows10_OrGreater_Build(WINDOWS_10_BUILDNUMBER_Fixed) then
Exit(False);
Code := PRIMARYLANGID(Code);
for I := Low(MitigatedLanguages) to High(MitigatedLanguages) do
if MitigatedLanguages[I].OriginalLanguage.Code = Code then
begin
lang := MitigatedLanguages[I];
Exit(True);
end;
// lang value undefined.
Result := False;
end;
class function TMitigateWin10_1803.IsMitigationRequired(BCP47Tag: string;
var lang: TMitigateWin10_1803.TMitigatedLanguage): Boolean;
var
I: Integer;
begin
if not IsWindows10_OrGreater_Build(WINDOWS_10_BUILDNUMBER_WithFailure) then
Exit(False);
if IsWindows10_OrGreater_Build(WINDOWS_10_BUILDNUMBER_Fixed) then
Exit(False);
// We only want to look at the primary language tag for comparison
// And we assume that the tag has been canonicalized from ISO639-3 first
BCP47Tag := LowerCase(BCP47Tag);
I := Pos('-', BCP47Tag);
if I > 0 then
BCP47Tag := Copy(BCP47Tag, 1, I-1);
for I := Low(MitigatedLanguages) to High(MitigatedLanguages) do
if MitigatedLanguages[I].OriginalLanguage.BCP47 = BCP47Tag then
begin
lang := MitigatedLanguages[I];
Exit(True);
end;
// lang value undefined.
Result := False;
end;
end.