diff --git a/windows/src/engine/kmcomapi/com/keyboardlanguages/keymankeyboardlanguagesinstalled.pas b/windows/src/engine/kmcomapi/com/keyboardlanguages/keymankeyboardlanguagesinstalled.pas
index 69cee87f6b..ad49eec580 100644
--- a/windows/src/engine/kmcomapi/com/keyboardlanguages/keymankeyboardlanguagesinstalled.pas
+++ b/windows/src/engine/kmcomapi/com/keyboardlanguages/keymankeyboardlanguagesinstalled.pas
@@ -86,19 +86,17 @@ begin
end;
procedure TKeymanKeyboardLanguagesInstalled.DoRefresh;
-var
- FProfiles: TStringList;
- i: Integer;
- FKeyboardLanguage: TKeymanKeyboardLanguageInstalled;
- RootPath: string;
- FLangID: Integer;
- FName, FLocale: string;
- FGUID: TGUID;
-begin
- KL.MethodEnter(Self, 'DoRefresh', []);
- try
- { Iterate through something somewhere and get the languages associated with this profile? }
+ procedure RefreshProfiles;
+ var
+ FProfiles: TStringList;
+ i: Integer;
+ FKeyboardLanguage: TKeymanKeyboardLanguageInstalled;
+ RootPath: string;
+ FLangID: Integer;
+ FName, FLocale: string;
+ FGUID: TGUID;
+ begin
FProfiles := TStringList.Create;
with TRegistryErrorControlled.Create do
try
@@ -129,6 +127,55 @@ begin
Free;
FProfiles.Free;
end;
+ end;
+
+ function HasLanguage(BCP47: string): Boolean;
+ var
+ i: Integer;
+ begin
+ for i := 0 to FLanguages.Count - 1 do
+ if SameText((FLanguages[i] as IKeymanKeyboardLanguage).BCP47Code, BCP47) then
+ Exit(True);
+ Result := False;
+ end;
+
+ procedure RefreshSuggestedLanguages;
+ var
+ RootPath: string;
+ FIDs: TStringList;
+ i: Integer;
+ FName: string;
+ FKeyboardLanguage: TKeymanKeyboardLanguageInstalled;
+ begin
+ FIDs := TStringList.Create;
+ with TRegistryErrorControlled.Create do
+ try
+ RootKey := HKEY_LOCAL_MACHINE;
+ RootPath := GetRegistryKeyboardInstallKey_LM(FOwner.ID) + '\' + SRegSubKey_SuggestedLanguages;
+ if OpenKeyReadOnly(RootPath) then
+ begin
+ GetValueNames(FIDs);
+ for i := 0 to FIDs.Count - 1 do
+ begin
+ if not HasLanguage(FIDs[i]) then
+ begin
+ FName := ReadString(FIDs[i]);
+ FKeyboardLanguage := TKeymanKeyboardLanguageInstalled.Create(Context, FOwner, FIDs[i], 0, GUID_NULL, FName);
+ FLanguages.Add(FKeyboardLanguage);
+ end;
+ end;
+ end;
+ finally
+ Free;
+ FIDs.Free;
+ end;
+ end;
+
+begin
+ KL.MethodEnter(Self, 'DoRefresh', []);
+ try
+ RefreshProfiles;
+ RefreshSuggestedLanguages;
finally
KL.MethodExit(Self, 'DoRefresh');
end;
diff --git a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas
index f0cd44683f..480b7461b5 100644
--- a/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas
+++ b/windows/src/engine/kmcomapi/com/keyboards/keymankeyboardfile.pas
@@ -64,7 +64,7 @@ type
function Get_DefaultWindowsLanguages: WideString; override; safecall;
function Get_DefaultPrimaryLanguage: Integer; override; safecall;
function Get_Version: WideString; override; safecall;
- function Get_Languages: IKeymanKeyboardLanguages; safecall;
+ function Get_Languages: IKeymanKeyboardLanguagesFile; safecall;
public
constructor Create(AContext: TKeymanContext; const Filename: Widestring; pk: TPackageKeyboard);
destructor Destroy; override;
@@ -173,7 +173,7 @@ begin
Result := FKeyboardInfo.KeyboardVersion;
end;
-function TKeymanKeyboardFile.Get_Languages: IKeymanKeyboardLanguages;
+function TKeymanKeyboardFile.Get_Languages: IKeymanKeyboardLanguagesFile;
begin
Result := FLanguages;
end;
diff --git a/windows/src/engine/kmcomapi/keymanapi_TLB.pas b/windows/src/engine/kmcomapi/keymanapi_TLB.pas
index c9b30598b6..99b5c8ff97 100644
--- a/windows/src/engine/kmcomapi/keymanapi_TLB.pas
+++ b/windows/src/engine/kmcomapi/keymanapi_TLB.pas
@@ -12,7 +12,7 @@ unit keymanapi_TLB;
// ************************************************************************ //
// $Rev: 52393 $
-// File generated on 21/02/2018 1:52:03 PM from Type Library described below.
+// File generated on 21/02/2018 8:54:26 PM from Type Library described below.
// ************************************************************************ //
// Type Lib: C:\Projects\keyman\open\windows\src\engine\kmcomapi\kmcomapi (1)
@@ -889,8 +889,8 @@ type
IKeymanKeyboardFile = interface(IKeymanKeyboard)
['{80959B80-C7A9-4EB1-AB46-3762F8E5315B}']
procedure Install(Force: WordBool); safecall;
- function Get_Languages: IKeymanKeyboardLanguages; safecall;
- property Languages: IKeymanKeyboardLanguages read Get_Languages;
+ function Get_Languages: IKeymanKeyboardLanguagesFile; safecall;
+ property Languages: IKeymanKeyboardLanguagesFile read Get_Languages;
end;
// *********************************************************************//
@@ -901,7 +901,7 @@ type
IKeymanKeyboardFileDisp = dispinterface
['{80959B80-C7A9-4EB1-AB46-3762F8E5315B}']
procedure Install(Force: WordBool); dispid 256;
- property Languages: IKeymanKeyboardLanguages readonly dispid 402;
+ property Languages: IKeymanKeyboardLanguagesFile readonly dispid 402;
property Bitmap: IPicture readonly dispid 1;
property Copyright: WideString readonly dispid 2;
property DefaultBCP47Languages: WideString readonly dispid 3;
diff --git a/windows/src/engine/kmcomapi/kmcomapi.ridl b/windows/src/engine/kmcomapi/kmcomapi.ridl
index 988db3d49d..bd79c2b8af 100644
--- a/windows/src/engine/kmcomapi/kmcomapi.ridl
+++ b/windows/src/engine/kmcomapi/kmcomapi.ridl
@@ -6,7 +6,7 @@
// However, when applying changes via the Editor this file will be regenerated
// and comments or formatting changes will be lost.
// ************************************************************************ //
-// File generated on 21/02/2018 1:52:06 PM (- $Rev: 12980 $, 701365859).
+// File generated on 21/02/2018 8:54:28 PM (- $Rev: 12980 $, 726708000).
[
uuid(F16E2A9A-DA46-4EA3-BFF3-BA46B480C961),
@@ -581,7 +581,7 @@ library keymanapi
[id(0x00000100)]
HRESULT _stdcall Install([in] VARIANT_BOOL Force);
[propget, id(0x00000192)]
- HRESULT _stdcall Languages([out, retval] IKeymanKeyboardLanguages** Value);
+ HRESULT _stdcall Languages([out, retval] IKeymanKeyboardLanguagesFile** Value);
};
[
diff --git a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas
index ea7c8d9661..6c0b810edc 100644
--- a/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas
+++ b/windows/src/engine/kmcomapi/processes/keyboard/kpinstallkeyboard.pas
@@ -47,7 +47,7 @@ unit kpinstallkeyboard; // I3306
interface
uses
- Windows,
+ Winapi.Windows,
PackageInfo,
kpbase;
@@ -66,19 +66,38 @@ type
implementation
uses
- SysUtils, Classes, Graphics,
- ErrorControlledRegistry, kmxfile, keymanerror, utilkeyman, utilsystem,
- isadmin, RegistryKeys, GetOsVersion, glossary,
+ System.SysUtils,
+ System.Classes,
+ System.Variants,
+ Vcl.Graphics,
+
+ Keyman.System.LanguageCodeUtils,
+
+ ErrorControlledRegistry,
+ kmxfile,
+ keymanerror,
+ utilkeyman,
+ utilsystem,
+ isadmin,
+ RegistryKeys,
+ GetOsVersion,
+ glossary,
utilexecute,
- keymanerrorcodes, keymancontext, kpinstallkeyboardlanguageprofiles,
- OnlineConstants, KLog, custinterfaces, utilolepicture,
- kprecompilemnemonickeyboard, KPInstallVisualKeyboard,
+ keymanerrorcodes,
+ keymancontext,
+ kpinstallkeyboardlanguageprofiles,
+ OnlineConstants,
+ KLog,
+ custinterfaces,
+ utilolepicture,
+ kprecompilemnemonickeyboard,
+ KPInstallVisualKeyboard,
utildir,
KeymanPaths,
kmxfileconsts,
utilicon,
utilstr,
- keymanapi_TLB, Variants;
+ keymanapi_TLB;
procedure TKPInstallKeyboard.Execute(const FileName, PackageName: string; FInstallOptions: TKPInstallKeyboardOptions; Languages: TPackageKeyboardLanguageList; Force: Boolean);
var
@@ -98,6 +117,37 @@ var
FKVKName: WideString;
FCreatedIcon: Boolean;
FLanguageID: Integer;
+
+type
+ TWSLCallback = reference to procedure(r: TRegistryErrorControlled);
+ procedure WriteSuggestedLanguages(c: TWSLCallback);
+ var
+ r: TRegistryErrorControlled;
+ begin
+ r := TRegistryErrorControlled.Create;
+ try
+ r.RootKey := HKEY_LOCAL_MACHINE;
+ if not r.OpenKey('\'+GetRegistryKeyboardInstallKey_LM(FileName)+'\'+SRegSubKey_SuggestedLanguages, True) then
+ r.RaiseLastRegistryError;
+ c(r);
+ finally
+ r.Free;
+ end;
+ end;
+
+ procedure AddLanguage(FLanguageID: Integer);
+ var
+ i: Integer;
+ begin
+ for i := 0 to High(FLanguages) do
+ if FLanguages[i] = FLanguageID then
+ Exit;
+
+ SetLength(FLanguages, Length(FLanguages)+1);
+ FLanguages[High(FLanguages)] := FLanguageID;
+ end;
+
+
begin
KL.MethodEnter(Self, 'Execute', [FileName,PackageName,ikPartOfPackage in FInstallOptions ,Force]);
try
@@ -195,7 +245,15 @@ begin
RegisterLanguageProfile(Languages[0].ID, kbdname, ki.KeyboardName, FIconFileName, Languages[0].Name);
// Save the list of preferred languages for the keyboard, to the registry, for future installation.
- ////// TODO:BCP47: AddPreferredLanguagesToRegistry(
+ WriteSuggestedLanguages(
+ procedure(r: TRegistryErrorControlled)
+ var
+ i: Integer;
+ begin
+ for i := 0 to Languages.Count - 1 do
+ r.WriteString(Languages[i].ID, Languages[i].Name);
+ end
+ );
end
else
begin
@@ -204,8 +262,7 @@ begin
//
if ki.KeyboardID <> 0 then
begin
- SetLength(FLanguages, 1);
- FLanguages[0] := ki.KeyboardID;
+ AddLanguage(ki.KeyboardID);
end;
//
@@ -220,23 +277,30 @@ begin
Delete(FLanguage, 1, 1); // 'x'
if TryStrToInt('$'+FLanguage, FLanguageID) then
begin
- SetLength(FLanguages, Length(FLanguages)+1);
- FLanguages[High(FLanguages)] := FLanguageID;
+ AddLanguage(FLanguageID);
end;
end;
//
// Final fallback is to install against default language for system // I4607
//
- SetLength(FLanguages, Length(FLanguages)+1);
- FLanguages[High(FLanguages)] := HKLToLanguageID(FDefaultHKL);
+ if Length(FLanguages) = 0 then
+ AddLanguage(HKLToLanguageID(FDefaultHKL));
// Registers only the first language
RegisterLanguageProfile(FLanguages, kbdname, ki.KeyboardName, FIconFileName); // I3581 // I3707
// Save the list of preferred languages for the keyboard, translated to BCP47 tags
// to the registry, for future installation.
- ////// TODO:BCP47: AddPreferredLanguagesToRegistry(
+ WriteSuggestedLanguages(
+ procedure(r: TRegistryErrorControlled)
+ var
+ i: Integer;
+ begin
+ for i := 0 to High(FLanguages) do
+ r.WriteString(TLanguageCodeUtils.TranslateWindowsLanguagesToBCP47(FLanguages[i]), '');
+ end
+ );
end;
CloseKey;
diff --git a/windows/src/global/delphi/general/RegistryKeys.pas b/windows/src/global/delphi/general/RegistryKeys.pas
index f897cfc362..ee65c26191 100644
--- a/windows/src/global/delphi/general/RegistryKeys.pas
+++ b/windows/src/global/delphi/general/RegistryKeys.pas
@@ -215,6 +215,8 @@ const
SRegValue_KeymanProfileGUID = 'profile guid'; // LM CU // I3581
+ SRegSubKey_SuggestedLanguages = 'Suggested Languages'; // LM
+
{ Language Profiles }
{$MESSAGE HINT 'Refactor this to use SRegKeyNode naming (no prefix \); fixup references'}
diff --git a/windows/src/test/integration-tests/keymanapi/Keyman.Test.Console.KeymanAPIHost.pas b/windows/src/test/integration-tests/keymanapi/Keyman.Test.Console.KeymanAPIHost.pas
index df08fa442a..cc40a73126 100644
--- a/windows/src/test/integration-tests/keymanapi/Keyman.Test.Console.KeymanAPIHost.pas
+++ b/windows/src/test/integration-tests/keymanapi/Keyman.Test.Console.KeymanAPIHost.pas
@@ -8,20 +8,10 @@ uses
Winapi.ActiveX,
System.Win.ComObj,
System.SysUtils,
- keymanapi_tlb;
+ keymanapi_tlb,
+ Keyman.Test.Console.KeymanAPITest_Base;
type
- TKeymanAPITest_Base = class
- private
- FTestPath: string;
- k: IKeyman;
- procedure CheckKeyboardProperties(kbd: IKeymanKeyboard);
- procedure CheckPackageProperties(pkg: IKeymanPackage);
- public
- constructor Create;
- destructor Destroy; override;
- end;
-
[TestFixture]
[Category('Default')]
TKeymanAPITest = class(TKeymanAPITest_Base)
@@ -154,77 +144,6 @@ uses
KeymanOptionNames,
System.Variants;
-constructor TKeymanAPITest_Base.Create;
-begin
- inherited Create;
- FTestPath := ExtractFilePath(ExtractFileDir(ExtractFileDir(ParamStr(0)))) + 'test\';
- CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
-end;
-
-destructor TKeymanAPITest_Base.Destroy;
-begin
- CoUninitialize;
- inherited Destroy;
-end;
-
-procedure TKeymanAPITest_Base.CheckKeyboardProperties(kbd: IKeymanKeyboard);
-begin
- Assert.AreEqual('กขฃ', kbd.GetCharsUsed);
- Assert.AreEqual('(C) 2017 SIL International', kbd.Copyright);
- Assert.AreEqual('eng', kbd.DefaultBCP47Languages);
- Assert.AreEqual($040C, kbd.DefaultPrimaryLanguage);
- Assert.AreEqual('x040C x040C', kbd.DefaultWindowsLanguages);
-// Assert.IsNotNull(f.DefaultHotkey); TODO: Resolve DefaultHotkey implementation -- remove from reg, read from kmx in --installed, read from kmx in --file as well
-// Assert.AreEqual(False, f.DefaultHotkey.IsEmpty);
-// Assert.AreEqual(HK_ALT or HK_CTRL, f.DefaultHotkey.Modifiers);
-// Assert.AreEqual(Ord('T'), f.DefaultHotkey.VirtualKey);
-// Assert.AreEqual(0, f.DefaultHotkey.RawValue);
-// Assert.AreEqual(0, f.DefaultHotkey.Target);
- Assert.AreEqual(keUnicode, kbd.Encodings);
- Assert.AreEqual('test.kmx', ExtractFileName(kbd.Filename));
- Assert.AreEqual('test', kbd.ID);
- Assert.AreEqual(kltPositional, kbd.LayoutType);
- Assert.AreEqual('Test Message', kbd.Message);
- Assert.AreEqual('Test Keyboard', kbd.Name);
- Assert.AreEqual('1.2.3', kbd.Version);
- Assert.IsNotNull(kbd.Bitmap);
- // Assert.AreEqual(f.SerializeXML(...), False);
-end;
-
-procedure TKeymanAPITest_Base.CheckPackageProperties(pkg: IKeymanPackage);
-begin
- Assert.AreEqual('Keyman', pkg.Author);
- Assert.AreEqual('mailto:support@keyman.com', pkg.AuthorEmail);
- Assert.AreEqual('(C) 2017 SIL International', pkg.Copyright);
-
- Assert.IsNotNull(pkg.Files);
- // TODO: Check each file
-
- Assert.IsNotNull(pkg.Fonts);
- // TODO: Check each font
-
- Assert.IsNull(pkg.Graphic);
- Assert.IsNull(pkg.GraphicFile);
- Assert.AreEqual('test', pkg.ID);
- Assert.IsNull(pkg.KeyboardOptionsFile);
-
- Assert.IsNotNull(pkg.Keyboards);
- Assert.AreEqual(1, pkg.Keyboards.Count);
-
- Assert.AreEqual('Test Keyboard', pkg.Name);
-
- Assert.IsNotNull(pkg.ReadmeFile);
- Assert.AreEqual('readme.txt', ExtractFileName(pkg.ReadmeFile.Filename));
-
- Assert.IsNull(pkg.UsageFile);
- Assert.AreEqual('1.2.3', pkg.Version);
-
- Assert.IsNotNull(pkg.WelcomeFile);
- Assert.AreEqual('welcome.htm', ExtractFileName(pkg.WelcomeFile.Filename));
-
- Assert.AreEqual('https://keyman.com/', pkg.Website);
-end;
-
//
// IKeyman
//
@@ -414,7 +333,7 @@ procedure TKeymanAPITest.Test_IKeymanKeyboardFile;
var
kbd: IKeymanKeyboardFile;
begin
- kbd := k.Keyboards.GetKeyboardFromFile(FTestPath + 'test.kmx');
+ kbd := k.Keyboards.GetKeyboardFromFile(TestPath + 'test.kmx');
CheckKeyboardProperties(kbd);
// kbd.Install()... Todo: test installation (forced installation is tested in IKeymanKeyboardInstalled)
end;
@@ -574,7 +493,7 @@ procedure TKeymanAPITest.Test_IKeymanPackageFile;
var
pkg: IKeymanPackageFile;
begin
- pkg := k.Packages.GetPackageFromFile(FTestPath + 'test.kmp');
+ pkg := k.Packages.GetPackageFromFile(TestPath + 'test.kmp');
Assert.IsNotNull(pkg);
Assert.AreEqual('test.kmp', ExtractFileName(pkg.Filename));
CheckPackageProperties(pkg);
@@ -640,7 +559,7 @@ procedure TKeymanAPITest_Elevated.Test_IKeymanKeyboardInstalled;
var
kbd: IKeymanKeyboardInstalled;
begin
- k.Keyboards.Install(FTestPath + 'test.kmx', True);
+ k.Keyboards.Install(TestPath + 'test.kmx', True);
k.Keyboards.Refresh;
kbd := k.Keyboards['test'];
Assert.IsNotNull(kbd);
@@ -668,7 +587,7 @@ var
pkg: IKeymanPackageInstalled;
kbd: IKeymanKeyboardInstalled;
begin
- k.Packages.Install(FTestPath + 'test.kmp', True);
+ k.Packages.Install(TestPath + 'test.kmp', True);
k.Packages.Refresh;
k.Keyboards.Refresh;
pkg := k.Packages['test'];
diff --git a/windows/src/test/integration-tests/keymanapi/Keyman.Test.Console.KeymanAPITest_BCP47.pas b/windows/src/test/integration-tests/keymanapi/Keyman.Test.Console.KeymanAPITest_BCP47.pas
new file mode 100644
index 0000000000..390445cece
--- /dev/null
+++ b/windows/src/test/integration-tests/keymanapi/Keyman.Test.Console.KeymanAPITest_BCP47.pas
@@ -0,0 +1,143 @@
+unit Keyman.Test.Console.KeymanAPITest_BCP47;
+
+interface
+uses
+ DUnitX.TestFramework,
+ Keyman.Test.Console.KeymanAPITest_Base,
+ keymanapi_tlb;
+
+type
+
+ [TestFixture]
+ TKeymanAPITest_BCP47 = class(TKeymanAPITest_Base)
+ private
+ k: IKeyman;
+ public
+ constructor Create;
+
+ [Setup]
+ procedure Setup;
+ [TearDown]
+ procedure TearDown;
+
+ [Test]
+ procedure TestFile;
+
+ [Test]
+ procedure TestInstall;
+ end;
+
+implementation
+
+uses
+ Winapi.Windows,
+ System.SysUtils,
+ System.Win.Registry,
+ RegistryKeys;
+
+constructor TKeymanAPITest_BCP47.Create;
+begin
+ // This shouldn't be needed but it seems the parent constructor doesn't run when
+ // instantiated by DUnitX unless constructor is present in child class?
+ inherited Create;
+end;
+
+procedure TKeymanAPITest_BCP47.Setup;
+begin
+ k := CoKeyman.Create;
+ if not k.SystemInfo.IsAdministrator then
+ begin
+ Assert.Fail('Must be running as administrator in order to run elevated tests, to exclude use parameter --exclude:Elevated');
+ end;
+end;
+
+procedure TKeymanAPITest_BCP47.TearDown;
+begin
+ k := nil;
+end;
+
+// Extracted from utilkeyman.pas.
+function GetShortKeyboardName(const FileName: string): string;
+begin
+ if (LowerCase(ExtractFileExt(FileName)) = '.kmx') or
+ (LowerCase(ExtractFileExt(FileName)) = '.kxx') or
+ (LowerCase(ExtractFileExt(FileName)) = '.kmp')
+ then Result := ChangeFileExt(ExtractFileName(FileName), '')
+ else Result := FileName;
+end;
+
+// Extracted from utilkeyman.pas.
+function GetRegistryKeyboardInstallKey_LM(const FileName: string): string;
+begin
+ Result := SRegKey_InstalledKeyboards_LM+'\'+GetShortKeyboardName(FileName);
+end;
+
+procedure TKeymanAPITest_BCP47.TestFile;
+var
+ kbd_file: IKeymanKeyboardFile;
+ pkg_file: IKeymanPackageFile;
+begin
+ pkg_file := k.Packages.GetPackageFromFile(TestPath + 'bcp47.kmp');
+ Assert.AreEqual(1, pkg_file.Keyboards.Count);
+ kbd_file := pkg_file.Keyboards[0] as IKeymanKeyboardFile;
+ Assert.AreEqual(2, kbd_file.Languages.Count);
+ Assert.AreEqual('tpi', kbd_file.Languages[0].BCP47Code);
+ Assert.AreEqual('Tok Pisin', kbd_file.Languages[0].Name);
+ pkg_file := nil;
+ kbd_file := nil;
+end;
+
+procedure TKeymanAPITest_BCP47.TestInstall;
+var
+ kbd_installed: IKeymanKeyboardInstalled;
+ pkg_installed: IKeymanPackageInstalled;
+begin
+ k.Packages.Install(TestPath + 'bcp47.kmp', True);
+ k.Packages.Refresh;
+ k.Keyboards.Refresh;
+
+ pkg_installed := k.Packages['bcp47'];
+ Assert.IsNotNull(pkg_installed);
+
+ kbd_installed := k.Keyboards['bcp47'];
+ Assert.IsNotNull(kbd_installed);
+
+ Assert.AreEqual(2, kbd_installed.Languages.Count, 'kbd.Languages.Count');
+ Assert.AreEqual('tpi', kbd_installed.Languages[0].BCP47Code);
+ Assert.AreEqual('Tok Pisin', kbd_installed.Languages[0].Name);
+ Assert.AreNotEqual(0, kbd_installed.Languages[0].LangID);
+
+ Assert.AreEqual('abg', kbd_installed.Languages[1].BCP47Code);
+ Assert.AreEqual('Abaga', kbd_installed.Languages[1].Name);
+ Assert.AreEqual(0, kbd_installed.Languages[1].LangID);
+
+ Assert.IsTrue(kbd_installed.Languages[0].IsInstalled);
+ Assert.IsFalse(kbd_installed.Languages[1].IsInstalled);
+
+ kbd_installed := nil;
+
+ // Test registry values
+ with TRegistry.Create do
+ try
+ RootKey := HKEY_LOCAL_MACHINE;
+ if OpenKeyReadOnly('\'+GetRegistryKeyboardInstallKey_LM('bcp47')+'\'+SRegSubKey_SuggestedLanguages) then
+ begin
+ Assert.IsTrue(ValueExists('tpi'));
+ Assert.AreEqual(ReadString('tpi'), 'Tok Pisin');
+
+ Assert.IsTrue(ValueExists('abg'));
+ Assert.AreEqual(ReadString('abg'), 'Abaga');
+ end;
+ finally
+ Free;
+ end;
+
+
+ pkg_installed.Uninstall(True);
+ k.Keyboards.Refresh;
+ k.Keyboards.Apply;
+end;
+
+initialization
+ TDUnitX.RegisterTestFixture(TKeymanAPITest_BCP47);
+end.
diff --git a/windows/src/test/integration-tests/keymanapi/Keyman.Test.Console.KeymanAPITest_Base.pas b/windows/src/test/integration-tests/keymanapi/Keyman.Test.Console.KeymanAPITest_Base.pas
new file mode 100644
index 0000000000..f7c9c40a06
--- /dev/null
+++ b/windows/src/test/integration-tests/keymanapi/Keyman.Test.Console.KeymanAPITest_Base.pas
@@ -0,0 +1,103 @@
+unit Keyman.Test.Console.KeymanAPITest_Base;
+
+interface
+
+uses
+ DUnitX.TestFramework,
+ keymanapi_tlb;
+
+type
+ TKeymanAPITest_Base = class
+ strict private
+ FTestPath: string;
+ FK: IKeyman;
+ protected
+ procedure CheckKeyboardProperties(kbd: IKeymanKeyboard);
+ procedure CheckPackageProperties(pkg: IKeymanPackage);
+ property TestPath: string read FTestPath;
+ property k: IKeyman read FK write FK;
+ public
+ constructor Create;
+ destructor Destroy; override;
+ end;
+
+implementation
+
+uses
+ Winapi.Windows,
+ Winapi.ActiveX,
+ System.Win.ComObj,
+ System.SysUtils;
+
+constructor TKeymanAPITest_Base.Create;
+begin
+ inherited Create;
+ FTestPath := ExtractFilePath(ExtractFileDir(ExtractFileDir(ParamStr(0)))) + 'test\';
+ CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
+end;
+
+destructor TKeymanAPITest_Base.Destroy;
+begin
+ CoUninitialize;
+ inherited Destroy;
+end;
+
+procedure TKeymanAPITest_Base.CheckKeyboardProperties(kbd: IKeymanKeyboard);
+begin
+ Assert.AreEqual('กขฃ', kbd.GetCharsUsed);
+ Assert.AreEqual('(C) 2017 SIL International', kbd.Copyright);
+ Assert.AreEqual('en', kbd.DefaultBCP47Languages);
+ Assert.AreEqual($040C, kbd.DefaultPrimaryLanguage);
+ Assert.AreEqual('x040C x040C', kbd.DefaultWindowsLanguages);
+// Assert.IsNotNull(f.DefaultHotkey); TODO: Resolve DefaultHotkey implementation -- remove from reg, read from kmx in --installed, read from kmx in --file as well
+// Assert.AreEqual(False, f.DefaultHotkey.IsEmpty);
+// Assert.AreEqual(HK_ALT or HK_CTRL, f.DefaultHotkey.Modifiers);
+// Assert.AreEqual(Ord('T'), f.DefaultHotkey.VirtualKey);
+// Assert.AreEqual(0, f.DefaultHotkey.RawValue);
+// Assert.AreEqual(0, f.DefaultHotkey.Target);
+ Assert.AreEqual(keUnicode, kbd.Encodings);
+ Assert.AreEqual('test.kmx', ExtractFileName(kbd.Filename));
+ Assert.AreEqual('test', kbd.ID);
+ Assert.AreEqual(kltPositional, kbd.LayoutType);
+ Assert.AreEqual('Test Message', kbd.Message);
+ Assert.AreEqual('Test Keyboard', kbd.Name);
+ Assert.AreEqual('1.2.3', kbd.Version);
+ Assert.IsNotNull(kbd.Bitmap);
+ // Assert.AreEqual(f.SerializeXML(...), False);
+end;
+
+procedure TKeymanAPITest_Base.CheckPackageProperties(pkg: IKeymanPackage);
+begin
+ Assert.AreEqual('Keyman', pkg.Author);
+ Assert.AreEqual('mailto:support@keyman.com', pkg.AuthorEmail);
+ Assert.AreEqual('(C) 2017 SIL International', pkg.Copyright);
+
+ Assert.IsNotNull(pkg.Files);
+ // TODO: Check each file
+
+ Assert.IsNotNull(pkg.Fonts);
+ // TODO: Check each font
+
+ Assert.IsNull(pkg.Graphic);
+ Assert.IsNull(pkg.GraphicFile);
+ Assert.AreEqual('test', pkg.ID);
+ Assert.IsNull(pkg.KeyboardOptionsFile);
+
+ Assert.IsNotNull(pkg.Keyboards);
+ Assert.AreEqual(1, pkg.Keyboards.Count);
+
+ Assert.AreEqual('Test Keyboard', pkg.Name);
+
+ Assert.IsNotNull(pkg.ReadmeFile);
+ Assert.AreEqual('readme.txt', ExtractFileName(pkg.ReadmeFile.Filename));
+
+ Assert.IsNull(pkg.UsageFile);
+ Assert.AreEqual('1.2.3', pkg.Version);
+
+ Assert.IsNotNull(pkg.WelcomeFile);
+ Assert.AreEqual('welcome.htm', ExtractFileName(pkg.WelcomeFile.Filename));
+
+ Assert.AreEqual('https://keyman.com/', pkg.Website);
+end;
+
+end.
diff --git a/windows/src/test/integration-tests/keymanapi/keymanapi_test.dpr b/windows/src/test/integration-tests/keymanapi/keymanapi_test.dpr
index 302dda6a28..71afe17b7b 100644
--- a/windows/src/test/integration-tests/keymanapi/keymanapi_test.dpr
+++ b/windows/src/test/integration-tests/keymanapi/keymanapi_test.dpr
@@ -17,7 +17,11 @@ uses
Winapi.ActiveX,
Keyman.Test.Console.KeymanAPIHost in 'Keyman.Test.Console.KeymanAPIHost.pas',
keymanapi_TLB in '..\..\..\engine\kmcomapi\keymanapi_TLB.pas',
- KeymanOptionNames in '..\..\..\global\delphi\general\KeymanOptionNames.pas';
+ KeymanOptionNames in '..\..\..\global\delphi\general\KeymanOptionNames.pas',
+ Keyman.Test.Console.KeymanAPITest_BCP47 in 'Keyman.Test.Console.KeymanAPITest_BCP47.pas',
+ Keyman.Test.Console.KeymanAPITest_Base in 'Keyman.Test.Console.KeymanAPITest_Base.pas',
+ RegistryKeys in '..\..\..\global\delphi\general\RegistryKeys.pas',
+ KeymanVersion in '..\..\..\global\delphi\general\KeymanVersion.pas';
var
runner : ITestRunner;
diff --git a/windows/src/test/integration-tests/keymanapi/keymanapi_test.dproj b/windows/src/test/integration-tests/keymanapi/keymanapi_test.dproj
index c562dc5a24..24ec419aed 100644
--- a/windows/src/test/integration-tests/keymanapi/keymanapi_test.dproj
+++ b/windows/src/test/integration-tests/keymanapi/keymanapi_test.dproj
@@ -111,8 +111,12 @@
MainSource
-
-
+
+
+
+
+
+
Cfg_2
Base
@@ -135,35 +139,35 @@
+
+
+ keymanapi_test.exe
+ true
+
+
true
-
-
- true
-
-
-
-
- true
-
-
-
-
- true
-
-
keymanapi_test.exe
true
-
-
- keymanapi_test.rsm
+
+
+ true
+
+
+
+
+ true
+
+
+
+
true
diff --git a/windows/src/test/integration-tests/keymanapi/test/bcp47.kmn b/windows/src/test/integration-tests/keymanapi/test/bcp47.kmn
new file mode 100644
index 0000000000..b60670fdcb
--- /dev/null
+++ b/windows/src/test/integration-tests/keymanapi/test/bcp47.kmn
@@ -0,0 +1,6 @@
+store(&NAME) 'BCP47 Test'
+begin Unicode > use(main)
+
+group(main) using keys
+
++ 'a' > 'bcp47 keyboard'
diff --git a/windows/src/test/integration-tests/keymanapi/test/bcp47.kmp b/windows/src/test/integration-tests/keymanapi/test/bcp47.kmp
new file mode 100644
index 0000000000..3661d2585b
Binary files /dev/null and b/windows/src/test/integration-tests/keymanapi/test/bcp47.kmp differ
diff --git a/windows/src/test/integration-tests/keymanapi/test/bcp47.kmx b/windows/src/test/integration-tests/keymanapi/test/bcp47.kmx
new file mode 100644
index 0000000000..72a01b68f6
Binary files /dev/null and b/windows/src/test/integration-tests/keymanapi/test/bcp47.kmx differ
diff --git a/windows/src/test/integration-tests/keymanapi/test/bcp47.kps b/windows/src/test/integration-tests/keymanapi/test/bcp47.kps
new file mode 100644
index 0000000000..3ce1d5ff09
--- /dev/null
+++ b/windows/src/test/integration-tests/keymanapi/test/bcp47.kps
@@ -0,0 +1,41 @@
+
+
+
+ 10.0.1021.0
+ 7.0
+
+
+
+
+
+
+
+
+
+
+
+ 1.0
+ BCP47 Test
+
+
+
+ bcp47.kmx
+ Keyboard BCP47 Test
+ 0
+ .kmx
+
+
+
+
+ BCP47 Test
+ bcp47
+ 1.0
+ True
+
+ Tok Pisin
+ Abaga
+
+
+
+
+
diff --git a/windows/src/test/integration-tests/keymanapi/test/test.kpj b/windows/src/test/integration-tests/keymanapi/test/test.kpj
new file mode 100644
index 0000000000..5101b4073e
--- /dev/null
+++ b/windows/src/test/integration-tests/keymanapi/test/test.kpj
@@ -0,0 +1,103 @@
+
+
+
+
+ False
+ True
+
+
+
+ id_40ba94fbf72e9d4b1e17ea3cbc6e4287
+ test.kmn
+ test.kmn
+ 1.2.3
+ .kmn
+
+ Test Keyboard
+ (C) 2017 SIL International
+ Test Message
+
+
+
+ id_43c2962a46c842a207e8feeac7444b9e
+ test.kps
+ test.kps
+ 1.2.3
+ .kps
+
+ Test Keyboard
+ (C) 2017 SIL International
+ 1.2.3
+
+
+
+ id_93662347dadf4f8457343f345e633233
+ bcp47.kps
+ bcp47.kps
+ 1.0
+ .kps
+
+ BCP47 Test
+ 1.0
+
+
+
+ id_99c63a38148734593a9a8e3982e4aca5
+ bcp47.kmn
+ bcp47.kmn
+ 1.0
+ .kmn
+
+ BCP47 Test
+
+
+
+ id_5df400e6f9f0f1b01651c61d86ff8f23
+ test.kvk
+ test.kvk
+
+ .kvk
+ id_43c2962a46c842a207e8feeac7444b9e
+
+
+ id_230d4faf67c42acd737cc6c82600abc2
+ test.kmx
+ test.kmx
+
+ .kmx
+ id_43c2962a46c842a207e8feeac7444b9e
+
+
+ id_baf6639217cac055ff5e648f2b14832e
+ keymanweb-osk.ttf
+ keymanweb-osk.ttf
+
+ .ttf
+ id_43c2962a46c842a207e8feeac7444b9e
+
+
+ id_eb6b6c90251ab33cee784713c451e6d8
+ readme.txt
+ readme.txt
+
+ .txt
+ id_43c2962a46c842a207e8feeac7444b9e
+
+
+ id_9a2fbfc6076553fc8f8cae9f6ac5d05d
+ welcome.htm
+ welcome.htm
+
+ .htm
+ id_43c2962a46c842a207e8feeac7444b9e
+
+
+ id_585856c9c8411cde30e57ab4ab0714ab
+ bcp47.kmx
+ bcp47.kmx
+
+ .kmx
+ id_93662347dadf4f8457343f345e633233
+
+
+