mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-08 16:47:46 +00:00
Merge branch 'master' into change/web/context-tracker-backspaces-and-alignment
This commit is contained in:
commit
b314cee54b
76 changed files with 3931 additions and 469 deletions
19
HISTORY.md
19
HISTORY.md
|
|
@ -1,5 +1,22 @@
|
|||
# Keyman Version History
|
||||
|
||||
## 18.0.169 alpha 2025-01-17
|
||||
|
||||
* chore(windows): remove `postinstall` state from mermaid diagram (#12923)
|
||||
|
||||
## 18.0.168 alpha 2025-01-16
|
||||
|
||||
* chore: update macOS environment-variable shell script (#12878)
|
||||
* fix(android): use main looper to dispatch key events when OSK is hidden (#12871)
|
||||
* chore(web): integrates predictive-text builds to top level script, reconnects headless tests (#12866)
|
||||
* chore(ios): Update crowdin strings for Khmer (#12910)
|
||||
* chore(windows): merge master epic windows updates (#12904)
|
||||
* fix(developer): detect invalid key ids in touch layout files (#12895)
|
||||
* chore: use GitHub PR titles when writing HISTORY.md (#12907)
|
||||
* fix(developer): filter incorrect fonts out of .keyboard_info (#12909)
|
||||
* change(web): make 'keep' transform pattern match standard suggestion pattern by including the prefix string (#12906)
|
||||
* chore: Add docker images for building the different platforms (#11397)
|
||||
|
||||
## 18.0.167 alpha 2025-01-15
|
||||
|
||||
* chore: changes to use https and removes anchor in docs (#12838)
|
||||
|
|
@ -213,7 +230,7 @@
|
|||
|
||||
## 18.0.134 alpha 2024-11-04
|
||||
|
||||
* (#12606)
|
||||
* fix(developer): ldml don't allow a uset as right-hand-side variable (#12606)
|
||||
|
||||
## 18.0.133 alpha 2024-11-01
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
18.0.168
|
||||
18.0.170
|
||||
|
|
@ -31,6 +31,7 @@ import android.content.pm.ApplicationInfo;
|
|||
import android.content.res.Configuration;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
|
|
@ -70,6 +71,10 @@ final class KMKeyboard extends WebView {
|
|||
protected KeyboardType keyboardType = KeyboardType.KEYBOARD_TYPE_UNDEFINED;
|
||||
protected ArrayList<String> javascriptAfterLoad = new ArrayList<>();
|
||||
|
||||
// .getMainLooper() returns the looper associated with the main UI thread.
|
||||
// https://stackoverflow.com/questions/13974661/runonuithread-vs-looper-getmainlooper-post-in-android
|
||||
private Handler jsQueuer = new Handler(Looper.getMainLooper());
|
||||
|
||||
private static String currentKeyboard = null;
|
||||
|
||||
/**
|
||||
|
|
@ -368,7 +373,7 @@ final class KMKeyboard extends WebView {
|
|||
if(this.javascriptAfterLoad.size() > 0) {
|
||||
// Don't call this WebView method on just ANY thread - run it on the main UI thread.
|
||||
// https://stackoverflow.com/a/22611010
|
||||
this.postDelayed(new Runnable() {
|
||||
jsQueuer.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
StringBuilder allCalls = new StringBuilder();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
Keyman is copyright (C) SIL Global. MIT License.
|
||||
|
||||
This module provides functionality to track the execution state of the Keyman
|
||||
engine. It uses a global atom to record whether Keyman has started during the
|
||||
current session and checks if it has previously run.
|
||||
}
|
||||
unit Keyman.System.ExecutionHistory;
|
||||
|
||||
|
||||
interface
|
||||
|
||||
const
|
||||
AtomName = 'KeymanSessionFlag';
|
||||
|
||||
function RecordKeymanStarted : Boolean;
|
||||
function HasKeymanRun : Boolean;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
Winapi.Windows,
|
||||
KLog;
|
||||
|
||||
function RecordKeymanStarted : Boolean;
|
||||
var
|
||||
atom: WORD;
|
||||
begin
|
||||
atom := GlobalAddAtom(AtomName);
|
||||
if atom = 0 then
|
||||
begin
|
||||
// TODO-WINDOWS-UPDATES: #10210 log to sentry
|
||||
Result := False;
|
||||
end
|
||||
else
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function HasKeymanRun : Boolean;
|
||||
begin
|
||||
Result := GlobalFindAtom(AtomName) <> 0;
|
||||
if not Result then
|
||||
begin
|
||||
if GetLastError <> ERROR_FILE_NOT_FOUND then
|
||||
begin
|
||||
// TODO-WINDOWS-UPDATES: log to Sentry
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
@ -35,6 +35,7 @@ type
|
|||
|
||||
TUpdateCheckResponse = record
|
||||
private
|
||||
FOriginalData: string;
|
||||
FInstallSize: Int64;
|
||||
FInstallURL: string;
|
||||
FNewVersion: string;
|
||||
|
|
@ -46,9 +47,13 @@ type
|
|||
FFileName: string;
|
||||
function ParseKeyboards(nodes: TJSONObject): Boolean;
|
||||
function ParseLanguages(i: Integer; v: TJSONValue): Boolean;
|
||||
function DoParse(const message, app, currentVersion: string): Boolean;
|
||||
public
|
||||
function Parse(const message: AnsiString; const app, currentVersion: string): Boolean;
|
||||
|
||||
procedure SaveToFile(const Filename: string);
|
||||
function LoadFromFile(const Filename, app, currentVersion: string): Boolean;
|
||||
|
||||
property CurrentVersion: string read FCurrentVersion;
|
||||
property NewVersion: string read FNewVersion;
|
||||
property NewVersionWithTag: string read FNewVersionWithTag;
|
||||
|
|
@ -58,25 +63,32 @@ type
|
|||
property ErrorMessage: string read FErrorMessage;
|
||||
property Status: TUpdateCheckResponseStatus read FStatus;
|
||||
property Packages: TUpdateCheckResponsePackages read FPackages;
|
||||
property OriginalData: string read FOriginalData;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.Classes,
|
||||
System.Generics.Collections,
|
||||
versioninfo;
|
||||
|
||||
{ TUpdateCheckResponse }
|
||||
|
||||
function TUpdateCheckResponse.Parse(const message: AnsiString; const app, currentVersion: string): Boolean;
|
||||
begin
|
||||
Result := DoParse(string(UTF8String(message)), app, currentVersion);
|
||||
end;
|
||||
|
||||
function TUpdateCheckResponse.DoParse(const message, app, currentVersion: string): Boolean;
|
||||
var
|
||||
node, doc: TJSONObject;
|
||||
begin
|
||||
FOriginalData := message;
|
||||
FCurrentVersion := currentVersion;
|
||||
FStatus := ucrsNoUpdate;
|
||||
|
||||
// TODO: test with UTF8 characters in response
|
||||
doc := TJSONObject.ParseJSONValue(UTF8String(message)) as TJSONObject;
|
||||
doc := TJSONObject.ParseJSONValue(UTF8String(FOriginalData)) as TJSONObject;
|
||||
if doc = nil then
|
||||
begin
|
||||
FErrorMessage := Format('Invalid response:'#13#10'%s', [string(message)]);
|
||||
|
|
@ -168,4 +180,29 @@ begin
|
|||
Result := True;
|
||||
end;
|
||||
|
||||
function TUpdateCheckResponse.LoadFromFile(const Filename, app, currentVersion: string): Boolean;
|
||||
var
|
||||
ss: TStringStream;
|
||||
begin
|
||||
ss := TStringStream.Create('', TEncoding.UTF8);
|
||||
try
|
||||
ss.LoadFromFile(Filename);
|
||||
Result := DoParse(ss.DataString, app, currentVersion);
|
||||
finally
|
||||
ss.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TUpdateCheckResponse.SaveToFile(const Filename: string);
|
||||
var
|
||||
ss: TStringStream;
|
||||
begin
|
||||
ss := TStringStream.Create(FOriginalData, TEncoding.UTF8);
|
||||
try
|
||||
ss.SaveToFile(Filename);
|
||||
finally
|
||||
ss.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ type
|
|||
const S_CEF_SubProcess = 'kmbrowserhost.exe';
|
||||
const S_CEF_SubProcess_Developer = 'kmdbrowserhost.exe';
|
||||
const S_CustomisationFilename = 'desktop_pro.pxx';
|
||||
|
||||
const S_KeymanAppData_UpdateCache = 'Keyman\UpdateCache\';
|
||||
public
|
||||
const S_KMShell = 'kmshell.exe';
|
||||
const S_TSysInfoExe = 'tsysinfo.exe';
|
||||
|
|
@ -27,8 +29,10 @@ type
|
|||
const S_FallbackKeyboardPath = 'Keyboards\';
|
||||
const S__Package = '_Package\';
|
||||
const S_MCompileExe = 'mcompile.exe';
|
||||
const S_UpdateCache_Metadata = 'cache.json';
|
||||
class function ErrorLogPath(const app: string = ''): string; static;
|
||||
class function KeymanHelpPath(const HelpFile: string): string; static;
|
||||
class function KeymanUpdateCachePath(const filename: string = ''): string; static;
|
||||
class function KeymanDesktopInstallPath(const filename: string = ''): string; static;
|
||||
class function KeymanEngineInstallPath(const filename: string = ''): string; static;
|
||||
class function KeymanDesktopInstallDir: string; static;
|
||||
|
|
@ -423,6 +427,11 @@ begin
|
|||
Result := '';
|
||||
end;
|
||||
|
||||
class function TKeymanPaths.KeymanUpdateCachePath(const filename: string): string;
|
||||
begin
|
||||
Result := GetFolderPath(CSIDL_LOCAL_APPDATA) + S_KeymanAppData_UpdateCache + filename;
|
||||
end;
|
||||
|
||||
class function TKeymanPaths.RunningFromSource(var keyman_root: string): Boolean;
|
||||
begin
|
||||
// On developer machines, if we are running within the source repo, then use
|
||||
|
|
|
|||
|
|
@ -175,8 +175,10 @@ const
|
|||
|
||||
SRegValue_CharMapSourceData = 'charmap source data'; // LM
|
||||
|
||||
SRegValue_AvailableLanguages = 'available languages'; //CU
|
||||
SRegValue_CurrentLanguage = 'current language'; //CU
|
||||
SRegValue_AvailableLanguages = 'available languages'; // CU
|
||||
SRegValue_CurrentLanguage = 'current language'; // CU
|
||||
|
||||
SRegValue_Update_State = 'update state'; // CU
|
||||
|
||||
{ Privacy }
|
||||
|
||||
|
|
@ -312,8 +314,10 @@ const
|
|||
SRegValue_ActiveProject_Filename = 'project filename';
|
||||
SRegValue_ActiveProject_SourcePath = 'source path';
|
||||
|
||||
SRegValue_AutomaticUpdates = 'automatic updates'; //CU
|
||||
SRegValue_CheckForUpdates = 'check for updates'; // CU
|
||||
SRegValue_LastUpdateCheckTime = 'last update check time'; // CU
|
||||
SRegValue_ApplyNow = 'apply now'; // CU Start the install now even though it will require an restart
|
||||
|
||||
SRegValue_UpdateCheck_UseProxy = 'update check use proxy'; // CU
|
||||
SRegValue_UpdateCheck_ProxyHost = 'update check proxy host'; // CU
|
||||
|
|
|
|||
|
|
@ -56,10 +56,8 @@ TEST_F(KmCoreKeyboardApiTests, LoadFromBlobNull) {
|
|||
// Setup
|
||||
km::core::path kmxfile = "";
|
||||
|
||||
std::unique_ptr<uint8_t> data(new uint8_t[0]);
|
||||
|
||||
// Execute
|
||||
auto status = km_core_keyboard_load_from_blob(kmxfile.stem().c_str(), data.get(), 0, &this->keyboard);
|
||||
auto status = km_core_keyboard_load_from_blob(kmxfile.stem().c_str(), nullptr, 0, &this->keyboard);
|
||||
|
||||
// Verify
|
||||
EXPECT_EQ(status, KM_CORE_STATUS_INVALID_ARGUMENT);
|
||||
|
|
|
|||
|
|
@ -499,9 +499,6 @@ export class KeyboardInfoCompiler implements KeymanCompiler {
|
|||
keyboard_info.languages[language] = {};
|
||||
}
|
||||
|
||||
const fontSource = [].concat(...kmpJsonData.keyboards.map(e => e.displayFont ? [e.displayFont] : []), ...kmpJsonData.keyboards.map(e => e.webDisplayFonts ?? []));
|
||||
const oskFontSource = [].concat(...kmpJsonData.keyboards.map(e => e.oskFont ? [e.oskFont] : []), ...kmpJsonData.keyboards.map(e => e.webOskFonts ?? []));
|
||||
|
||||
let commonScript = null;
|
||||
|
||||
for(const bcp47 of Object.keys(keyboard_info.languages)) {
|
||||
|
|
@ -528,6 +525,20 @@ export class KeyboardInfoCompiler implements KeymanCompiler {
|
|||
// do it right now.
|
||||
//
|
||||
|
||||
// The code below:
|
||||
// 1. Only includes fonts associated with keyboards which support the current bcp47 (filter)
|
||||
// 2. Joins the displayFont and webDisplayFonts data, and removes duplicates (...new Set())
|
||||
|
||||
const supportedKeyboards = kmpJsonData.keyboards.filter(k => k.languages.find(lang => lang.id == bcp47));
|
||||
const fontSource = [...new Set([].concat(
|
||||
...supportedKeyboards.map(e => e.displayFont ? [e.displayFont] : []),
|
||||
...supportedKeyboards.map(e => e.webDisplayFonts ?? [])
|
||||
))];
|
||||
const oskFontSource = [...new Set([].concat(
|
||||
...supportedKeyboards.map(e => e.oskFont ? [e.oskFont] : []),
|
||||
...supportedKeyboards.map(e => e.webOskFonts ?? [])
|
||||
))];
|
||||
|
||||
if(fontSource.length) {
|
||||
language.font = await this.fontSourceToKeyboardInfoFont(kpsFilename, kmpJsonData, fontSource);
|
||||
if(language.font == null) {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,16 @@ function GetKeyIdUnicodeType(value: string): TKeyIdType {
|
|||
|
||||
function KeyIdType(FId: string): TKeyIdType { // I4142
|
||||
FId = FId.toUpperCase();
|
||||
|
||||
// Validate key id format:
|
||||
// K_xxxx -- predefined virtual key - restricted character set
|
||||
// T_xxxx -- custom 'touch' virtual key - touch key id
|
||||
// U_ABCD_1234 -- Unicode key id (1+ chars)
|
||||
// x00 -- "ISO" key identifier (not currently supported in touch layout files)
|
||||
if(!/^((K_[A-Z0-9_?]+)|(T_\S+)|(U_[0-9A-F_]+))$/.test(FId)) {
|
||||
// note: |[A-Z][0-9][0-9] -- ISO key identifiers not currently supported
|
||||
return TKeyIdType.Key_Invalid;
|
||||
}
|
||||
switch(FId.charAt(0)) {
|
||||
case 'T':
|
||||
return TKeyIdType.Key_Touch;
|
||||
|
|
|
|||
550
developer/src/kmc-kmn/test/fixtures/kmw/error_touch_layout_invalid_identifier.keyman-touch-layout
vendored
Normal file
550
developer/src/kmc-kmn/test/fixtures/kmw/error_touch_layout_invalid_identifier.keyman-touch-layout
vendored
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
{
|
||||
"tablet": {
|
||||
"displayUnderlying": false,
|
||||
"layer": [
|
||||
{
|
||||
"id": "default",
|
||||
"row": [
|
||||
{
|
||||
"id": 1,
|
||||
"key": [
|
||||
{
|
||||
"id": "U_1E6B[_0307]",
|
||||
"text": "១"
|
||||
},
|
||||
{
|
||||
"id": "K_2",
|
||||
"text": "២"
|
||||
},
|
||||
{
|
||||
"id": "K_3",
|
||||
"text": "៣"
|
||||
},
|
||||
{
|
||||
"id": "K_4",
|
||||
"text": "៤"
|
||||
},
|
||||
{
|
||||
"id": "K_5",
|
||||
"text": "៥"
|
||||
},
|
||||
{
|
||||
"id": "K_6",
|
||||
"text": "៦"
|
||||
},
|
||||
{
|
||||
"id": "K_7",
|
||||
"text": "៧"
|
||||
},
|
||||
{
|
||||
"id": "K_8",
|
||||
"text": "៨"
|
||||
},
|
||||
{
|
||||
"id": "K_9",
|
||||
"text": "៩"
|
||||
},
|
||||
{
|
||||
"id": "K_0",
|
||||
"text": "០"
|
||||
},
|
||||
{
|
||||
"id": "K_HYPHEN",
|
||||
"text": "ឥ"
|
||||
},
|
||||
{
|
||||
"id": "K_EQUAL",
|
||||
"text": "ឲ"
|
||||
},
|
||||
{
|
||||
"id": "K_BKSP",
|
||||
"text": "*BkSp*",
|
||||
"width": "100",
|
||||
"sp": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"key": [
|
||||
{
|
||||
"id": "K_Q",
|
||||
"text": "ឆ",
|
||||
"pad": "75"
|
||||
},
|
||||
{
|
||||
"id": "K_W",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_E",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_R",
|
||||
"text": "រ"
|
||||
},
|
||||
{
|
||||
"id": "K_T",
|
||||
"text": "ត"
|
||||
},
|
||||
{
|
||||
"id": "K_Y",
|
||||
"text": "យ"
|
||||
},
|
||||
{
|
||||
"id": "K_U",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_I",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_O",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_P",
|
||||
"text": "ផ"
|
||||
},
|
||||
{
|
||||
"id": "K_LBRKT",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_RBRKT",
|
||||
"text": "ឪ"
|
||||
},
|
||||
{
|
||||
"id": "T_new_138",
|
||||
"text": "",
|
||||
"width": "10",
|
||||
"sp": "10"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"key": [
|
||||
{
|
||||
"id": "K_BKQUOTE",
|
||||
"text": "«"
|
||||
},
|
||||
{
|
||||
"id": "K_A",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_S",
|
||||
"text": "ស"
|
||||
},
|
||||
{
|
||||
"id": "K_D",
|
||||
"text": "ដ"
|
||||
},
|
||||
{
|
||||
"id": "K_F",
|
||||
"text": "ថ"
|
||||
},
|
||||
{
|
||||
"id": "K_G",
|
||||
"text": "ង"
|
||||
},
|
||||
{
|
||||
"id": "K_H",
|
||||
"text": "ហ"
|
||||
},
|
||||
{
|
||||
"id": "K_J",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_K",
|
||||
"text": "ក"
|
||||
},
|
||||
{
|
||||
"id": "K_L",
|
||||
"text": "ល"
|
||||
},
|
||||
{
|
||||
"id": "K_COLON",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_QUOTE",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_BKSLASH",
|
||||
"text": "ឮ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"key": [
|
||||
{
|
||||
"id": "K_SHIFT",
|
||||
"text": "*Shift*",
|
||||
"width": "160",
|
||||
"sp": "1",
|
||||
"nextlayer": "shift"
|
||||
},
|
||||
{
|
||||
"id": "K_oE2",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_Z",
|
||||
"text": "ឋ"
|
||||
},
|
||||
{
|
||||
"id": "K_X",
|
||||
"text": "ខ"
|
||||
},
|
||||
{
|
||||
"id": "K_C",
|
||||
"text": "ច"
|
||||
},
|
||||
{
|
||||
"id": "K_V",
|
||||
"text": "វ"
|
||||
},
|
||||
{
|
||||
"id": "K_B",
|
||||
"text": "ប"
|
||||
},
|
||||
{
|
||||
"id": "K_N",
|
||||
"text": "ន"
|
||||
},
|
||||
{
|
||||
"id": "K_M",
|
||||
"text": "ម"
|
||||
},
|
||||
{
|
||||
"id": "K_COMMA",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_PERIOD",
|
||||
"text": "។"
|
||||
},
|
||||
{
|
||||
"id": "K_SLASH",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "T_new_164",
|
||||
"text": "",
|
||||
"width": "10",
|
||||
"sp": "10"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"key": [
|
||||
{
|
||||
"id": "K_LCONTROL",
|
||||
"text": "*AltGr*",
|
||||
"width": "160",
|
||||
"sp": "1"
|
||||
},
|
||||
{
|
||||
"id": "K_LOPT",
|
||||
"text": "*Menu*",
|
||||
"width": "160",
|
||||
"sp": "1"
|
||||
},
|
||||
{
|
||||
"id": "K_SPACE",
|
||||
"text": "",
|
||||
"width": "930"
|
||||
},
|
||||
{
|
||||
"id": "K_ENTER",
|
||||
"text": "*Enter*",
|
||||
"width": "160",
|
||||
"sp": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "shift",
|
||||
"row": [
|
||||
{
|
||||
"id": 1,
|
||||
"key": [
|
||||
{
|
||||
"id": "K_1",
|
||||
"text": "!"
|
||||
},
|
||||
{
|
||||
"id": "K_2",
|
||||
"text": "ៗ"
|
||||
},
|
||||
{
|
||||
"id": "K_3",
|
||||
"text": "\""
|
||||
},
|
||||
{
|
||||
"id": "K_4",
|
||||
"text": "៛"
|
||||
},
|
||||
{
|
||||
"id": "K_5",
|
||||
"text": "%"
|
||||
},
|
||||
{
|
||||
"id": "K_6",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_7",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_8",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_9",
|
||||
"text": "("
|
||||
},
|
||||
{
|
||||
"id": "K_0",
|
||||
"text": ")"
|
||||
},
|
||||
{
|
||||
"id": "K_HYPHEN",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_EQUAL",
|
||||
"text": "="
|
||||
},
|
||||
{
|
||||
"id": "K_BKSP",
|
||||
"text": "*BkSp*",
|
||||
"width": "100",
|
||||
"sp": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"key": [
|
||||
{
|
||||
"id": "K_Q",
|
||||
"text": "ឈ",
|
||||
"pad": "75"
|
||||
},
|
||||
{
|
||||
"id": "K_W",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_E",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_R",
|
||||
"text": "ឬ"
|
||||
},
|
||||
{
|
||||
"id": "K_T",
|
||||
"text": "ទ"
|
||||
},
|
||||
{
|
||||
"id": "K_Y",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_U",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_I",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_O",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_P",
|
||||
"text": "ភ"
|
||||
},
|
||||
{
|
||||
"id": "K_LBRKT",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_RBRKT",
|
||||
"text": "ឧ"
|
||||
},
|
||||
{
|
||||
"id": "T_new_364",
|
||||
"text": "",
|
||||
"width": "10",
|
||||
"sp": "10"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"key": [
|
||||
{
|
||||
"id": "K_BKQUOTE",
|
||||
"text": "»"
|
||||
},
|
||||
{
|
||||
"id": "K_A",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_S",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_D",
|
||||
"text": "ឌ"
|
||||
},
|
||||
{
|
||||
"id": "K_F",
|
||||
"text": "ធ"
|
||||
},
|
||||
{
|
||||
"id": "K_G",
|
||||
"text": "អ"
|
||||
},
|
||||
{
|
||||
"id": "K_H",
|
||||
"text": "ះ"
|
||||
},
|
||||
{
|
||||
"id": "K_J",
|
||||
"text": "ញ"
|
||||
},
|
||||
{
|
||||
"id": "K_K",
|
||||
"text": "គ"
|
||||
},
|
||||
{
|
||||
"id": "K_L",
|
||||
"text": "ឡ"
|
||||
},
|
||||
{
|
||||
"id": "K_COLON",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_QUOTE",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_BKSLASH",
|
||||
"text": "ឭ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"key": [
|
||||
{
|
||||
"id": "K_SHIFT",
|
||||
"text": "*Shift*",
|
||||
"width": "160",
|
||||
"sp": "2",
|
||||
"nextlayer": "default"
|
||||
},
|
||||
{
|
||||
"id": "K_oE2",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_Z",
|
||||
"text": "ឍ"
|
||||
},
|
||||
{
|
||||
"id": "K_X",
|
||||
"text": "ឃ"
|
||||
},
|
||||
{
|
||||
"id": "K_C",
|
||||
"text": "ជ"
|
||||
},
|
||||
{
|
||||
"id": "K_V",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_B",
|
||||
"text": "ព"
|
||||
},
|
||||
{
|
||||
"id": "K_N",
|
||||
"text": "ណ"
|
||||
},
|
||||
{
|
||||
"id": "K_M",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_COMMA",
|
||||
"text": ""
|
||||
},
|
||||
{
|
||||
"id": "K_PERIOD",
|
||||
"text": "៕"
|
||||
},
|
||||
{
|
||||
"id": "K_SLASH",
|
||||
"text": "?"
|
||||
},
|
||||
{
|
||||
"id": "T_new_390",
|
||||
"text": "",
|
||||
"width": "10",
|
||||
"sp": "10"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"key": [
|
||||
{
|
||||
"id": "K_LCONTROL",
|
||||
"text": "*AltGr*",
|
||||
"width": "160",
|
||||
"sp": "1"
|
||||
},
|
||||
{
|
||||
"id": "K_LOPT",
|
||||
"text": "*Menu*",
|
||||
"width": "160",
|
||||
"sp": "1"
|
||||
},
|
||||
{
|
||||
"id": "K_SPACE",
|
||||
"text": "",
|
||||
"width": "930"
|
||||
},
|
||||
{
|
||||
"id": "K_ENTER",
|
||||
"text": "*Enter*",
|
||||
"width": "160",
|
||||
"sp": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"font": "Arial"
|
||||
}
|
||||
}
|
||||
10
developer/src/kmc-kmn/test/fixtures/kmw/error_touch_layout_invalid_identifier.kmn
vendored
Normal file
10
developer/src/kmc-kmn/test/fixtures/kmw/error_touch_layout_invalid_identifier.kmn
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
store(&VERSION) '15.0'
|
||||
store(&NAME) "error_touch_layout_invalid_identifier"
|
||||
store(©RIGHT) '© 2015-2024 SIL Global'
|
||||
store(&TARGETS) 'any'
|
||||
store(&LAYOUTFILE) 'error_touch_layout_invalid_identifier.keyman-touch-layout'
|
||||
store(&KEYBOARDVERSION) '1.3'
|
||||
|
||||
begin Unicode > use(main)
|
||||
|
||||
group(main) using keys
|
||||
|
|
@ -36,7 +36,9 @@ describe('KeymanWeb Compiler', function() {
|
|||
});
|
||||
|
||||
this.afterEach(function() {
|
||||
callbacks.printMessages();
|
||||
if(this.currentTest?.isFailed() || debug) {
|
||||
callbacks.printMessages();
|
||||
}
|
||||
callbacks.clear();
|
||||
});
|
||||
|
||||
|
|
@ -203,6 +205,19 @@ describe('KeymanWeb Compiler', function() {
|
|||
assert.isTrue(callbacks.hasMessage(KmwCompilerMessages.HINT_TouchLayoutUsesUnsupportedGesturesDownlevel));
|
||||
});
|
||||
|
||||
it('should give error ERROR_TouchLayoutInvalidIdentifier if a virtual key is badly formatted e.g. U_1234[_5678]', async function() {
|
||||
// #12870
|
||||
const filenames = generateTestFilenames('error_touch_layout_invalid_identifier');
|
||||
|
||||
let result = await kmnCompiler.run(filenames.source, null);
|
||||
assert.isNull(result);
|
||||
assert.isFalse(callbacks.hasMessage(KmnCompilerMessages.INFO_MinimumCoreEngineVersion));
|
||||
assert.isFalse(callbacks.hasMessage(KmwCompilerMessages.INFO_MinimumWebEngineVersion));
|
||||
assert.isTrue(callbacks.hasMessage(KmwCompilerMessages.ERROR_TouchLayoutInvalidIdentifier));
|
||||
assert.isTrue(callbacks.hasMessage(KmwCompilerMessages.ERROR_InvalidTouchLayoutFile));
|
||||
assert.lengthOf(callbacks.messages, 2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
async function run_test_keyboard(kmnCompiler: KmnCompiler, id: string):
|
||||
|
|
|
|||
90
docs/build/linux-ubuntu.md
vendored
90
docs/build/linux-ubuntu.md
vendored
|
|
@ -238,83 +238,25 @@ Android projects. `JAVA_HOME_11` is mostly used by CI.
|
|||
## Docker Builder
|
||||
|
||||
The Docker builder allows you to perform a build from anywhere Docker is supported.
|
||||
|
||||
To build the docker image:
|
||||
|
||||
```shell
|
||||
cd linux
|
||||
docker pull ubuntu:latest # (to make sure you have an up-to-date image)
|
||||
docker build . -t keymanapp/keyman-linux-builder:latest
|
||||
```
|
||||
|
||||
Once the image is built, it may be used to build parts of Keyman.
|
||||
|
||||
**Note** that it's not yet possible to run tests in the Docker container.
|
||||
|
||||
- core
|
||||
|
||||
```shell
|
||||
# build 'Keyman Core' in docker
|
||||
# keep linux build artifacts separate
|
||||
mkdir -p $(git rev-parse --show-toplevel)/core/build/linux
|
||||
docker run -it --rm -v $(git rev-parse --show-toplevel):/home/build/build \
|
||||
-v $(git rev-parse --show-toplevel)/core/build/linux:/home/build/build/core/build \
|
||||
keymanapp/keyman-linux-builder:latest \
|
||||
core/build.sh --debug
|
||||
```
|
||||
|
||||
- linux
|
||||
|
||||
```shell
|
||||
# build 'Keyman for Linux' installation in docker
|
||||
docker run -it --rm -v $(git rev-parse --show-toplevel):/home/build/build \
|
||||
--entrypoint /bin/bash keymanapp/keyman-linux-builder:latest \
|
||||
-c 'DESTDIR=/home/build /usr/bin/bashwrapper linux/build.sh --debug build install'
|
||||
```
|
||||
|
||||
- Keyman Web
|
||||
|
||||
```shell
|
||||
# build 'Keyman Web' in docker
|
||||
docker run --privileged -it --rm \
|
||||
-v $(git rev-parse --show-toplevel):/home/build/build \
|
||||
keymanapp/keyman-linux-builder:latest \
|
||||
web/build.sh --debug
|
||||
```
|
||||
|
||||
- Keyman for Android
|
||||
|
||||
```shell
|
||||
# build 'Keyman for Android' in docker
|
||||
docker run -it --rm -v $(git rev-parse --show-toplevel):/home/build/build \
|
||||
keymanapp/keyman-linux-builder:latest \
|
||||
android/build.sh --debug
|
||||
```
|
||||
|
||||
### Customizing the builder
|
||||
|
||||
You can use Docker [build args](https://docs.docker.com/build/guide/build-args/) to customize the image build. As an example, the following will build an image explicitly with Ubuntu 23.04 and Node.js 20. Check the [Dockerfile](../../linux/Dockerfile) for `ARG` entries.
|
||||
|
||||
```shell
|
||||
cd linux
|
||||
docker pull ubuntu:23.04 # (to make sure you have an up-to-date image)
|
||||
docker build . -t keymanapp/keyman-linux-builder:u23.04-node20 --build-arg OS_VERSION=23.04 --build-arg NODE_MAJOR=20
|
||||
````
|
||||
See [this README.md](../../resources/docker-images/README.md) for details.
|
||||
|
||||
### Using the builder with VSCode [Dev Containers](https://code.visualstudio.com/docs/devcontainers/tutorial)
|
||||
|
||||
1. Save the following as `.devcontainer/devcontainer.json`, updating the `image` to match the Docker image built above.
|
||||
1. Save the following as `.devcontainer/devcontainer.json`, updating the `image`
|
||||
to match the Docker image built above.
|
||||
|
||||
```json
|
||||
// file: .devcontainer/devcontainer.json
|
||||
{
|
||||
"name": "Keyman Ubuntu 23.04",
|
||||
"image": "keymanapp/keyman-linux-builder:u23.04-node18"
|
||||
}
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
|
||||
```
|
||||
```json
|
||||
// file: .devcontainer/devcontainer.json
|
||||
{
|
||||
"name": "Keyman Ubuntu 23.04",
|
||||
"image": "keymanapp/keyman-linux-builder:u23.04-node18"
|
||||
}
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options,
|
||||
// see the README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
|
||||
```
|
||||
|
||||
2. in VSCode, use the "Dev Containers: Open Folder In Container…" option and choose the Keyman directory.
|
||||
2. in VSCode, use the "Dev Containers: Open Folder In Container…" option and
|
||||
choose the Keyman directory.
|
||||
|
||||
3. You will be given a window which is running VSCode inside this builder image, regardless of your host OS.
|
||||
3. You will be given a window which is running VSCode inside this builder
|
||||
image, regardless of your host OS.
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ https://help.keyman.com/developer/engine/android/latest-version/
|
|||
| KEYMAN_MIN_VERSION_NPM | 10.5.1 |
|
||||
| KEYMAN_MIN_VERSION_VISUAL_STUDIO | 2019 |
|
||||
| KEYMAN_VERSION_CLDR | 45 |
|
||||
| KEYMAN_VERSION_GRADLE | 7.6.4 |
|
||||
| KEYMAN_VERSION_ICU | 73.1 |
|
||||
| KEYMAN_VERSION_ISO639_3 | 2024-05-22 |
|
||||
| KEYMAN_VERSION_JAVA | 11 |
|
||||
|
|
|
|||
|
|
@ -226,6 +226,24 @@
|
|||
/* Text showing name of spacebar caption - language + keyboard */
|
||||
"menu-settings-spacebar-item-languageKeyboard" = "ភាសា និងក្ដារចុច";
|
||||
|
||||
/* Label for the "Adjust Keyboard Height" item on the main settings screen */
|
||||
"menu-settings-adjust-keyboard-height" = "កែកម្ពស់ក្ដារចុច";
|
||||
|
||||
/* Title for the "Adjust Keyboard Height" settings child screen */
|
||||
"adjust-keyboard-height-title" = "កែក្ដារចុច";
|
||||
|
||||
/* Label for "Reset to Default Keyboard Height" button on the adjust height screen */
|
||||
"button-label-reset-default-keyboard-height" = "ប្ដូរកម្ពស់ក្ដារចុចទៅលំនាំដើម";
|
||||
|
||||
/* Instruction text to drag keyboard to resize */
|
||||
"keyboard-drag-instructions" = "រំកិលព្រួញដើម្បីកែកម្ពស់ក្ដារចុច";
|
||||
|
||||
/* Instruction to rotate to adjust landscape keyboard height (displayed when device is portrait) */
|
||||
"portrait-keyboard-rotate-instructions" = "បង្វិលឧបករណ៍ដើម្បីប្តូរទៅជាផ្ដេក";
|
||||
|
||||
/* Instruction to rotate to adjust portrait keyboard height (displayed when device is landscape) */
|
||||
"landscape-keyboard-rotate-instructions" = "បង្វិលឧបករណ៍ដើម្បីប្តូរទៅជាបញ្ឈរ";
|
||||
|
||||
/* Short text for notification: download failure for keyboard */
|
||||
"notification-download-failure-keyboard" = "មិនអាចទាញយកក្ដារចុចបានទេ";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,90 +0,0 @@
|
|||
# Copyright (c) 2022-2023 SIL Global. All rights reserved.
|
||||
#
|
||||
# builder image for a linux build
|
||||
# see ../docs/build/linux-ubuntu.md
|
||||
|
||||
ARG OS_VERSION=latest
|
||||
ARG OS_PLATFORM=amd64
|
||||
|
||||
FROM --platform=${OS_PLATFORM} ubuntu:${OS_VERSION}
|
||||
LABEL org.opencontainers.image.authors="SIL Global."
|
||||
LABEL org.opencontainers.image.url="https://github.com/keymanapp/keyman.git"
|
||||
LABEL org.opencontainers.image.title="Keyman Linux Build Image"
|
||||
|
||||
# We will switch to a build user after some installation
|
||||
USER root
|
||||
ENV HOME /home/build
|
||||
RUN useradd -c "Build user" --home-dir $HOME --create-home --shell /usr/bin/bashwrapper build
|
||||
VOLUME /home/build/build
|
||||
WORKDIR /home/build/build
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV DEBIAN_PRIORITY critical
|
||||
ENV DEBCONF_NOWARNINGS yes
|
||||
|
||||
# Update to the latest
|
||||
RUN apt-get -q -y update && \
|
||||
apt-get -q -y install devscripts equivs meson python3 python3-setuptools software-properties-common curl && \
|
||||
add-apt-repository ppa:keymanapp/keyman && \
|
||||
add-apt-repository ppa:keymanapp/keyman-alpha
|
||||
RUN apt-get -q -y update && \
|
||||
apt-get -q -y upgrade
|
||||
|
||||
# Install dependencies
|
||||
ADD debian/control /tmp/control
|
||||
# Answer 'yes' to install questions
|
||||
RUN (yes | mk-build-deps --install /tmp/control) || true && \
|
||||
rm /tmp/control
|
||||
|
||||
# Install Node
|
||||
ARG NODE_MAJOR=18
|
||||
RUN apt-get install -q -y ca-certificates curl gnupg && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_"${NODE_MAJOR}".x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && apt-get update && apt-get install nodejs -y
|
||||
|
||||
ARG EMSCRIPTEN_VERSION=3.1.44
|
||||
# Install emscripten
|
||||
RUN cd /usr/share && \
|
||||
git clone https://github.com/emscripten-core/emsdk.git && \
|
||||
cd emsdk && \
|
||||
./emsdk install ${EMSCRIPTEN_VERSION} && \
|
||||
./emsdk activate ${EMSCRIPTEN_VERSION} && \
|
||||
echo "#!/bin/bash" > /usr/bin/bashwrapper && \
|
||||
echo "export EMSCRIPTEN_BASE=/usr/share/emsdk/upstream/emscripten" >> /usr/bin/bashwrapper
|
||||
|
||||
# Keyman Web
|
||||
RUN curl --output google-chrome-stable_current_amd64.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \
|
||||
apt-get -q -y install ./google-chrome-stable_current_amd64.deb && \
|
||||
rm google-chrome-stable_current_amd64.deb && \
|
||||
echo "export CHROME_BIN=/opt/google/chrome/chrome" >> /usr/bin/bashwrapper
|
||||
|
||||
# Keyman for Android
|
||||
RUN apt-get -q -y install gradle maven pandoc sdkmanager jq && \
|
||||
sdkmanager platform-tools && \
|
||||
yes | sdkmanager --licenses && \
|
||||
chown -R build:build /opt/android-sdk/ && \
|
||||
echo "export ANDROID_HOME=/opt/android-sdk" >> /usr/bin/bashwrapper && \
|
||||
echo "export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64" >> /usr/bin/bashwrapper
|
||||
|
||||
# Finish bashwrapper script and adjust permissions
|
||||
RUN echo "\${@:-bash}" >> /usr/bin/bashwrapper && \
|
||||
chmod +x /usr/bin/bashwrapper && \
|
||||
chown -R build:build $HOME
|
||||
|
||||
# now, switch to build user
|
||||
USER build
|
||||
|
||||
# Pre-install gradle. This will put files in ~/.gradle which will speed up builds.
|
||||
RUN mkdir -p $HOME/tmp/gradle/wrapper && \
|
||||
# KMEA uses gradle-7.5.1-bin
|
||||
curl --location --output $HOME/tmp/gradle/wrapper/gradle-wrapper.jar https://raw.githubusercontent.com/keymanapp/keyman/master/android/KMEA/gradle/wrapper/gradle-wrapper.jar && \
|
||||
curl --location --output $HOME/tmp/gradle/wrapper/gradle-wrapper.properties https://raw.githubusercontent.com/keymanapp/keyman/master/android/KMEA/gradle/wrapper/gradle-wrapper.properties && \
|
||||
curl --location --output $HOME/tmp/gradlew https://raw.githubusercontent.com/keymanapp/keyman/master/android/KMEA/gradlew && \
|
||||
chmod +x $HOME/tmp/gradlew && \
|
||||
$HOME/tmp/gradlew --quiet && \
|
||||
# Some projects use gradle-7.5.1-all, so we pre-install that as well
|
||||
curl --location --output $HOME/tmp/gradle/wrapper/gradle-wrapper.jar https://raw.githubusercontent.com/keymanapp/keyman/master/android/Samples/KMSample1/gradle/wrapper/gradle-wrapper.jar && \
|
||||
curl --location --output $HOME/tmp/gradle/wrapper/gradle-wrapper.properties https://raw.githubusercontent.com/keymanapp/keyman/master/android/Samples/KMSample1/gradle/wrapper/gradle-wrapper.properties && \
|
||||
curl --location --output $HOME/tmp/gradlew https://raw.githubusercontent.com/keymanapp/keyman/master/android/Samples/KMSample1/gradlew && \
|
||||
chmod +x $HOME/tmp/gradlew && \
|
||||
$HOME/tmp/gradlew --quiet && \
|
||||
rm -rf $HOME/tmp
|
||||
|
||||
ENTRYPOINT [ "/usr/bin/bashwrapper" ]
|
||||
|
|
@ -388,6 +388,11 @@
|
|||
<!-- Introduced: 7.0.230.0 -->
|
||||
<string name="koShowWelcome" comment="Startup options - show/hide welcome screen">Show welcome screen</string>
|
||||
|
||||
<!-- Context: Configuration Dialog - Options tab -->
|
||||
<!-- String Type: FormatString -->
|
||||
<!-- Introduced: 18.0.96.0 -->
|
||||
<string name="koAutomaticUpdate" comment="Automatically download updates in the background, for installation later">Automatically download updates in the background, for installation later</string>
|
||||
|
||||
<!-- Context: Configuration Dialog - Options tab -->
|
||||
<!-- String Type: FormatString -->
|
||||
<!-- Introduced: 7.0.230.0 -->
|
||||
|
|
|
|||
|
|
@ -86,13 +86,12 @@ This somewhat unwieldy incantation handles all our build environments.
|
|||
The intent is to get a good solid consistent path for the script so that we can
|
||||
safely include the build script, no matter what `pwd` is when the script is run.
|
||||
|
||||
|
||||
The only modification permissible in this block is the
|
||||
`<relative-path-to-repo-root>` text which will be a series of `../` paths taking
|
||||
us to the repository root from the location of the script itself.
|
||||
|
||||
It is essential to make the include relative to the repo root, even for scripts
|
||||
under the resources/ folder. Doing this gives us significant performance
|
||||
under the `resources/` folder. Doing this gives us significant performance
|
||||
benefits.
|
||||
|
||||
Inclusion of other scripts should be kept outside this standard build script
|
||||
|
|
@ -1117,4 +1116,4 @@ Note: it is recommended that you use `$(builder_term text)` instead of
|
|||
[`builder_echo`]: #builderecho-function
|
||||
[`builder_die`]: #builderdie-function
|
||||
[`builder_echo_debug`]: #builderechodebug-function
|
||||
[`builder_is_debug_build`]: #builderisdebugbuild-function
|
||||
[`builder_is_debug_build`]: #builderisdebugbuild-function
|
||||
|
|
|
|||
|
|
@ -104,9 +104,9 @@ echo "increment-version.sh: running resources/build/version"
|
|||
pushd "$KEYMAN_ROOT"
|
||||
ABORT=0
|
||||
if [[ -z "$fromversion" ]]; then
|
||||
node resources/build/version/build/src/index.js history version -t "$GITHUB_TOKEN" -b "$base" $HISTORY_FORCE || ABORT=$?
|
||||
node resources/build/version/build/src/index.js history version -t "$GITHUB_TOKEN" -b "$base" $HISTORY_FORCE --github-pr || ABORT=$?
|
||||
else
|
||||
node resources/build/version/build/src/index.js history version -t "$GITHUB_TOKEN" -b "$base" $HISTORY_FORCE --from "$fromversion" --to "$toversion" || ABORT=$?
|
||||
node resources/build/version/build/src/index.js history version -t "$GITHUB_TOKEN" -b "$base" $HISTORY_FORCE --github-pr --from "$fromversion" --to "$toversion" || ABORT=$?
|
||||
fi
|
||||
|
||||
if [[ $ABORT = 50 ]]; then
|
||||
|
|
@ -179,7 +179,7 @@ if [ "$action" == "commit" ]; then
|
|||
# In order to avoid potential git conflicts, we run the history collater
|
||||
# again on the master HISTORY.md. Note that the script always exits 1 to
|
||||
# indicate it hasn't updated VERSION.md. We could tweak that in the future.
|
||||
node resources/build/version/lib/index.js history --no-write-github-comment -t "$GITHUB_TOKEN" -b "$base" || true
|
||||
node resources/build/version/lib/index.js history --no-write-github-comment --github-pr -t "$GITHUB_TOKEN" -b "$base" || true
|
||||
|
||||
# If HISTORY.md has been updated, then we want to create a branch and push
|
||||
# it for review
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ KEYMAN_MIN_VERSION_EMSCRIPTEN=3.1.58 # Use KEYMAN_USE_EMSDK to automati
|
|||
KEYMAN_MIN_VERSION_VISUAL_STUDIO=2019
|
||||
KEYMAN_MIN_VERSION_MESON=1.0.0
|
||||
|
||||
KEYMAN_VERSION_ICU=73.1 # See /core/subprojects/icu-minimal.wrap
|
||||
KEYMAN_VERSION_GRADLE=7.6.4 # See /android/KMEA/gradle/wrapper/gradle-wrapper.properties
|
||||
KEYMAN_VERSION_ICU=73.1 # See /core/subprojects/icu-minimal.wrap
|
||||
|
||||
# Language and runtime versions
|
||||
KEYMAN_VERSION_JAVA=11 # We're using Java/OpenJDK 11
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ export const sendCommentToPullRequestAndRelatedIssues = async (
|
|||
*/
|
||||
|
||||
export const fixupHistory = async (
|
||||
octokit: GitHub, base: string, force: boolean, writeGithubComment: boolean, from?: string, to?: string
|
||||
octokit: GitHub, base: string, force: boolean, writeGithubComment: boolean, useGitHubPRInfo: boolean, from?: string, to?: string
|
||||
): Promise<number> => {
|
||||
|
||||
//
|
||||
|
|
@ -194,7 +194,7 @@ export const fixupHistory = async (
|
|||
let pulls: PRInformation[] = [];
|
||||
|
||||
try {
|
||||
pulls = await reportHistory(octokit, base, force, false, from, to);
|
||||
pulls = await reportHistory(octokit, base, force, useGitHubPRInfo, from, to);
|
||||
} catch(e) {
|
||||
logWarning(String(e));
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ const main = async (): Promise<void> => {
|
|||
|
||||
if(argv._.includes('history')) {
|
||||
logInfo(`# Validating history for ${version}`);
|
||||
changeCount = await fixupHistory(octokit, argv.base, argv.force, argv['write-github-comment'], argv.from, argv.to);
|
||||
changeCount = await fixupHistory(octokit, argv.base, argv.force, argv['write-github-comment'], argv['github-pr'], argv.from, argv.to);
|
||||
logInfo(`# ${changeCount} change(s) found for ${version}\n`);
|
||||
}
|
||||
|
||||
|
|
|
|||
65
resources/docker-images/README.md
Normal file
65
resources/docker-images/README.md
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# Container
|
||||
|
||||
Docker containers that can be used to build Keyman on the respective
|
||||
platforms. They contain everything that a CI build agent needs to
|
||||
build for the platform.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You'll need Docker Buildx installed to successfully be able to build the
|
||||
container images. This is most easily achieved by installing the [official
|
||||
Docker version](https://docs.docker.com/engine/install/ubuntu/).
|
||||
|
||||
Currently it is not possible to use Podman instead of Docker due to a number
|
||||
of bugs and incompatibilities in the Podman implementation.
|
||||
|
||||
## Building the images
|
||||
|
||||
To build the docker images:
|
||||
|
||||
```shell
|
||||
resources/docker-images/build.sh
|
||||
```
|
||||
|
||||
By default this will create 64-bit images for building
|
||||
Keyman Core, Keyman for Android, Keyman for Linux and
|
||||
Keyman for Web. These images are based on the Ubuntu 24.04
|
||||
with Node 20 and Emscripten 3.1.58 (for the exact versions,
|
||||
see [`minimum-versions.inc.sh`](../build/minimum-versions.inc.sh))
|
||||
and are named e.g. `keyman-core-ci:default`.
|
||||
|
||||
The versions can be changed, e.g.
|
||||
|
||||
```shell
|
||||
resources/docker-images/build.sh --ubuntu-version jammy --node 20
|
||||
```
|
||||
|
||||
This will create an image named e.g. `keyman-core-ci:jammy-node20`.
|
||||
|
||||
Once the image is built, it may be used to build parts of Keyman.
|
||||
|
||||
## Building locally
|
||||
|
||||
It is possible to build locally with these images:
|
||||
|
||||
```shell
|
||||
# build 'Keyman Core' in docker
|
||||
resources/docker-images/run.sh core -- core/build.sh --debug build
|
||||
```
|
||||
|
||||
Note: For Core and Linux we put the generated binaries in a
|
||||
container specific directory because they are platform dependent.
|
||||
|
||||
If you build both with Docker and directly with the build scripts, it is
|
||||
advisable to run a `git clean -dxf` before switching between the two. The
|
||||
reason is that the Docker images use a different user, so that paths
|
||||
will be different.
|
||||
|
||||
## Running tests locally
|
||||
|
||||
To run the tests locally, use the `run.sh` script:
|
||||
|
||||
```shell
|
||||
# Run common/web tests
|
||||
resources/docker-images/run.sh web -- common/web/build.sh --debug test
|
||||
```
|
||||
68
resources/docker-images/android/Dockerfile
Normal file
68
resources/docker-images/android/Dockerfile
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# Keyman is copyright (C) SIL Global. MIT License.
|
||||
|
||||
ARG BASE_VERSION=default
|
||||
FROM keymanapp/keyman-base-ci:${BASE_VERSION}
|
||||
LABEL org.opencontainers.image.authors="SIL Global."
|
||||
LABEL org.opencontainers.image.url="https://github.com/keymanapp/keyman.git"
|
||||
LABEL org.opencontainers.image.title="Keyman Android Build Image"
|
||||
|
||||
# Keyman for Android
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
|
||||
# Starting with Ubuntu 24.04 sdkmanager is no longer available, instead
|
||||
# a version dependent package allows to install the cmdline tools
|
||||
ARG JAVA_VERSION=11
|
||||
RUN <<EOF
|
||||
OS_VER=$(lsb_release -r -s 2>/dev/null)
|
||||
echo "OS_VER=${OS_VER}"
|
||||
if (( ${OS_VER%%.*} > 22 )); then
|
||||
PKG_SDKMANAGER=google-android-cmdline-tools-13.0-installer
|
||||
DIR_SDK=/usr/lib/android-sdk
|
||||
else
|
||||
PKG_SDKMANAGER=sdkmanager
|
||||
DIR_SDK=/opt/android-sdk
|
||||
fi
|
||||
apt-get -q -y install gradle maven pandoc $PKG_SDKMANAGER jq openjdk-${JAVA_VERSION}-jdk
|
||||
sdkmanager platform-tools
|
||||
yes | sdkmanager --licenses
|
||||
chown -R build:build $DIR_SDK
|
||||
echo "export ANDROID_HOME=$DIR_SDK" >> /usr/bin/bashwrapper
|
||||
echo "export JAVA_HOME_${JAVA_VERSION}=/usr/lib/jvm/java-${JAVA_VERSION}-openjdk-amd64" >> /usr/bin/bashwrapper
|
||||
EOF
|
||||
|
||||
# Finish bashwrapper script and adjust permissions
|
||||
RUN <<EOF cat >> /usr/bin/bashwrapper
|
||||
|
||||
if [[ "\$@" =~ test ]] && [ -f /usr/bin/run-tests.sh ]; then
|
||||
/usr/bin/run-tests.sh "\${@:-bash}"
|
||||
else
|
||||
"\${@:-bash}"
|
||||
fi
|
||||
EOF
|
||||
|
||||
# now, switch to build user
|
||||
USER build
|
||||
|
||||
VOLUME /home/build/build
|
||||
WORKDIR /home/build/build
|
||||
|
||||
# Pre-install gradle. This will put files in ~/.gradle which will speed up builds.
|
||||
# Note it would be safer to copy these files directly from our repo rather than
|
||||
# getting it over the Internet, but Docker doesn't allow us to copy files
|
||||
# from outside the current directory when building the image.
|
||||
RUN mkdir -p $HOME/tmp/gradle/wrapper && \
|
||||
# KMEA uses gradle-7.6.4-bin
|
||||
curl --location --output $HOME/tmp/gradle/wrapper/gradle-wrapper.jar https://raw.githubusercontent.com/keymanapp/keyman/master/android/KMEA/gradle/wrapper/gradle-wrapper.jar && \
|
||||
curl --location --output $HOME/tmp/gradle/wrapper/gradle-wrapper.properties https://raw.githubusercontent.com/keymanapp/keyman/master/android/KMEA/gradle/wrapper/gradle-wrapper.properties && \
|
||||
curl --location --output $HOME/tmp/gradlew https://raw.githubusercontent.com/keymanapp/keyman/master/android/KMEA/gradlew && \
|
||||
chmod +x $HOME/tmp/gradlew && \
|
||||
$HOME/tmp/gradlew --quiet && \
|
||||
# Some projects use gradle-7.6.4-all, so we pre-install that as well
|
||||
curl --location --output $HOME/tmp/gradle/wrapper/gradle-wrapper.jar https://raw.githubusercontent.com/keymanapp/keyman/master/android/Samples/KMSample1/gradle/wrapper/gradle-wrapper.jar && \
|
||||
curl --location --output $HOME/tmp/gradle/wrapper/gradle-wrapper.properties https://raw.githubusercontent.com/keymanapp/keyman/master/android/Samples/KMSample1/gradle/wrapper/gradle-wrapper.properties && \
|
||||
curl --location --output $HOME/tmp/gradlew https://raw.githubusercontent.com/keymanapp/keyman/master/android/Samples/KMSample1/gradlew && \
|
||||
chmod +x $HOME/tmp/gradlew && \
|
||||
$HOME/tmp/gradlew --quiet && \
|
||||
rm -rf $HOME/tmp
|
||||
|
||||
ENTRYPOINT [ "/usr/bin/bashwrapper" ]
|
||||
59
resources/docker-images/base/Dockerfile
Normal file
59
resources/docker-images/base/Dockerfile
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# Keyman is copyright (C) SIL Global. MIT License.
|
||||
|
||||
ARG UBUNTU_VERSION=latest
|
||||
FROM ubuntu:${UBUNTU_VERSION}
|
||||
|
||||
LABEL org.opencontainers.image.authors="SIL Global."
|
||||
LABEL org.opencontainers.image.url="https://github.com/keymanapp/keyman.git"
|
||||
LABEL org.opencontainers.image.title="Keyman Build Base Image"
|
||||
|
||||
# We will switch to a build user after some installation
|
||||
USER root
|
||||
ENV HOME=/home/build
|
||||
RUN grep ubuntu /etc/passwd && userdel ubuntu || true && \
|
||||
rm -rf /home/ubuntu && \
|
||||
useradd -c "Build user" --uid 1000 --home-dir $HOME --create-home --shell /usr/bin/bashwrapper build
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV DEBIAN_PRIORITY=critical
|
||||
ENV DEBCONF_NOWARNINGS=yes
|
||||
|
||||
# Update to the latest
|
||||
RUN apt-get -q -y update && \
|
||||
apt-get -q -y install ca-certificates curl gnupg meson software-properties-common sudo && \
|
||||
add-apt-repository ppa:keymanapp/keyman && \
|
||||
add-apt-repository ppa:keymanapp/keyman-alpha
|
||||
RUN apt-get -q -y update && \
|
||||
apt-get -q -y upgrade
|
||||
|
||||
# Allow build user to use `sudo`
|
||||
RUN echo "build ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||
|
||||
RUN <<EOF cat > /usr/bin/bashwrapper
|
||||
#!/bin/bash
|
||||
export KEYMAN_USE_NVM=1
|
||||
export DOCKER_RUNNING=true
|
||||
EOF
|
||||
|
||||
# Install NVM
|
||||
RUN NVM_RELEASE=$(curl -s https://api.github.com/repos/nvm-sh/nvm/releases/latest | grep tag_name | cut -d : -f 2 | cut -d '"' -f 2) && \
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_RELEASE}/install.sh | bash
|
||||
RUN <<EOF cat >> /usr/bin/bashwrapper
|
||||
PATH=/home/build/.keyman/node:\$PATH
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
. /home/build/.nvm/nvm.sh
|
||||
EOF
|
||||
|
||||
RUN chmod +x /usr/bin/bashwrapper && \
|
||||
chown -R build:build $HOME
|
||||
|
||||
USER build
|
||||
# Pre-install node
|
||||
ARG REQUIRED_NODE_VERSION=unset
|
||||
RUN echo "HOME=\${HOME}; REQUIRED_NODE_VERSION=${REQUIRED_NODE_VERSION}" && \
|
||||
export NVM_DIR="/home/build/.nvm" && \
|
||||
. /home/build/.nvm/nvm.sh && \
|
||||
nvm install "${REQUIRED_NODE_VERSION}" && \
|
||||
nvm use "${REQUIRED_NODE_VERSION}"
|
||||
|
||||
USER root
|
||||
122
resources/docker-images/build.sh
Executable file
122
resources/docker-images/build.sh
Executable file
|
|
@ -0,0 +1,122 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
## START STANDARD BUILD SCRIPT INCLUDE
|
||||
# adjust relative paths as necessary
|
||||
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
||||
. "${THIS_SCRIPT%/*}/../../resources/build/builder.inc.sh"
|
||||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
################################ Main script ################################
|
||||
|
||||
. "${KEYMAN_ROOT}/resources/build/minimum-versions.inc.sh"
|
||||
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
|
||||
|
||||
builder_describe \
|
||||
"Build docker images" \
|
||||
":android" \
|
||||
":base" \
|
||||
":core" \
|
||||
":linux" \
|
||||
":web" \
|
||||
"--ubuntu-version=UBUNTU_VERSION The Ubuntu version (default: ${KEYMAN_DEFAULT_VERSION_UBUNTU_CONTAINER})" \
|
||||
"--no-cache Force rebuild of docker images" \
|
||||
"build Build docker images" \
|
||||
"test Test the docker images by running configure,build,test for all or the specified platforms"
|
||||
|
||||
builder_parse "$@"
|
||||
|
||||
_add_build_args() {
|
||||
local var=$1
|
||||
local default_var=$2
|
||||
local name=$3
|
||||
local value
|
||||
|
||||
if [[ -n "${!var:-}" ]]; then
|
||||
value="${!var}"
|
||||
else
|
||||
value="${!default_var:-}"
|
||||
fi
|
||||
|
||||
build_args+=(--build-arg="${var}=${value}")
|
||||
|
||||
if [[ -n "${build_version:-}" ]]; then
|
||||
build_version="${build_version}-${name:-}${value}"
|
||||
else
|
||||
build_version="${name}${value}"
|
||||
fi
|
||||
}
|
||||
|
||||
_convert_parameters_to_build_args() {
|
||||
build_args=()
|
||||
build_version=
|
||||
local required_node_version
|
||||
# shellcheck disable=SC2034
|
||||
required_node_version="$(_print_expected_node_version)"
|
||||
|
||||
_add_build_args UBUNTU_VERSION KEYMAN_DEFAULT_VERSION_UBUNTU_CONTAINER ""
|
||||
_add_build_args JAVA_VERSION KEYMAN_VERSION_JAVA java
|
||||
_add_build_args REQUIRED_NODE_VERSION required_node_version node
|
||||
_add_build_args REQUIRED_EMSCRIPTEN_VERSION KEYMAN_MIN_VERSION_EMSCRIPTEN emsdk
|
||||
|
||||
if [[ -n "${BASE_VERSION:-}" ]]; then
|
||||
build_args+=(--build-arg="BASE_VERSION=${BASE_VERSION}")
|
||||
fi
|
||||
}
|
||||
|
||||
_is_default_values() {
|
||||
[[ -z "${UBUNTU_VERSION:-}" ]] && [[ -z "${JAVA_VERSION:-}" ]]
|
||||
}
|
||||
|
||||
build_action() {
|
||||
local platform=$1
|
||||
|
||||
builder_echo debug "Building image for ${platform}"
|
||||
|
||||
_convert_parameters_to_build_args
|
||||
|
||||
if [[ "${platform}" == "base" ]]; then
|
||||
docker pull --platform "amd64" "ubuntu:${UBUNTU_VERSION:-${KEYMAN_DEFAULT_VERSION_UBUNTU_CONTAINER}}"
|
||||
elif [[ "${platform}" == "linux" ]]; then
|
||||
cp "${KEYMAN_ROOT}/linux/debian/control" "${platform}"
|
||||
fi
|
||||
|
||||
if builder_has_option --no-cache; then
|
||||
OPTION_NO_CACHE="--no-cache"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2164
|
||||
cd "${platform}"
|
||||
# shellcheck disable=SC2248,SC2086
|
||||
docker build ${OPTION_NO_CACHE:-} --platform amd64 -t "keymanapp/keyman-${platform}-ci:${build_version}" "${build_args[@]}" .
|
||||
# If the user didn't specify particular versions we will additionaly create an image
|
||||
# with the tag 'default'.
|
||||
if _is_default_values; then
|
||||
builder_echo debug "Setting default tag for ${platform}"
|
||||
docker build --platform amd64 -t "keymanapp/keyman-${platform}-ci:default" "${build_args[@]}" .
|
||||
fi
|
||||
# shellcheck disable=SC2164,SC2103
|
||||
cd -
|
||||
builder_echo success "Docker image 'keymanapp/keyman-${platform}-ci:${build_version}' built"
|
||||
}
|
||||
|
||||
test_action() {
|
||||
local platform=$1
|
||||
|
||||
builder_echo debug "Testing image for ${platform}"
|
||||
./run.sh "${platform}" -- ./build.sh configure,build,test:"${platform}"
|
||||
}
|
||||
|
||||
if builder_has_action build; then
|
||||
build_action base
|
||||
BASE_VERSION="${build_version}"
|
||||
builder_run_action build:android build_action android
|
||||
builder_run_action build:core build_action core
|
||||
builder_run_action build:linux build_action linux
|
||||
builder_run_action build:web build_action web
|
||||
fi
|
||||
|
||||
builder_run_action test:core test_action core
|
||||
builder_run_action test:linux test_action linux
|
||||
builder_run_action test:web test_action web
|
||||
# Android uses artifacts from web, so it has to come after web
|
||||
builder_run_action test:android test_action android
|
||||
54
resources/docker-images/core/Dockerfile
Normal file
54
resources/docker-images/core/Dockerfile
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Keyman is copyright (C) SIL Global. MIT License.
|
||||
#
|
||||
# ARGS used in this file:
|
||||
# - ARG BASE_VERSION
|
||||
# - ARG REQUIRED_EMSCRIPTEN_VERSION
|
||||
|
||||
ARG BASE_VERSION=default
|
||||
FROM keymanapp/keyman-base-ci:${BASE_VERSION}
|
||||
|
||||
LABEL org.opencontainers.image.authors="SIL Global."
|
||||
LABEL org.opencontainers.image.url="https://github.com/keymanapp/keyman.git"
|
||||
LABEL org.opencontainers.image.title="Keyman Core Build Image"
|
||||
|
||||
USER root
|
||||
RUN apt-get install -qy git jq llvm meson pkgconf \
|
||||
xvfb xserver-xephyr metacity
|
||||
|
||||
# Pre-install emscripten
|
||||
USER build
|
||||
ARG REQUIRED_EMSCRIPTEN_VERSION=unset
|
||||
RUN echo "Installing emscripten version ${REQUIRED_EMSCRIPTEN_VERSION}" && \
|
||||
export EMSDK_KEEP_DOWNLOADS=1 && \
|
||||
cd /home/build/ && \
|
||||
git clone https://github.com/emscripten-core/emsdk.git && \
|
||||
cd emsdk && \
|
||||
./emsdk install ${REQUIRED_EMSCRIPTEN_VERSION} && \
|
||||
./emsdk activate ${REQUIRED_EMSCRIPTEN_VERSION}
|
||||
USER root
|
||||
RUN echo "export EMSCRIPTEN_BASE=/home/build/emsdk/upstream/emscripten" >> /usr/bin/bashwrapper && \
|
||||
echo "export KEYMAN_USE_EMSDK=1" >> /usr/bin/bashwrapper
|
||||
|
||||
# Finish bashwrapper script and adjust permissions
|
||||
RUN <<EOF cat >> /usr/bin/bashwrapper
|
||||
|
||||
if [[ "\$@" =~ test ]] && [ -f /usr/bin/run-tests.sh ]; then
|
||||
/usr/bin/run-tests.sh "\${@:-bash}"
|
||||
else
|
||||
"\${@:-bash}"
|
||||
fi
|
||||
EOF
|
||||
|
||||
# now, switch to build user
|
||||
USER build
|
||||
|
||||
# Pre-install node
|
||||
RUN export NVM_DIR="/home/build/.nvm" && \
|
||||
. /home/build/.nvm/nvm.sh && \
|
||||
cd /home/build/emsdk/upstream/emscripten && \
|
||||
npm install
|
||||
|
||||
VOLUME /home/build/build
|
||||
WORKDIR /home/build/build
|
||||
|
||||
ENTRYPOINT [ "/usr/bin/bashwrapper" ]
|
||||
1
resources/docker-images/linux/.gitignore
vendored
Normal file
1
resources/docker-images/linux/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
control
|
||||
52
resources/docker-images/linux/Dockerfile
Normal file
52
resources/docker-images/linux/Dockerfile
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Keyman is copyright (C) SIL Global. MIT License.
|
||||
|
||||
ARG BASE_VERSION=default
|
||||
FROM keymanapp/keyman-base-ci:${BASE_VERSION}
|
||||
LABEL org.opencontainers.image.authors="SIL Global."
|
||||
LABEL org.opencontainers.image.url="https://github.com/keymanapp/keyman.git"
|
||||
LABEL org.opencontainers.image.title="Keyman Linux Build Image"
|
||||
|
||||
# Install dependencies
|
||||
ADD control /tmp/control
|
||||
# Answer 'yes' to install questions
|
||||
RUN apt-get install -qy python3 python3-setuptools python3-coverage \
|
||||
devscripts equivs libdatetime-perl lcov gcovr xvfb \
|
||||
xserver-xephyr metacity mutter dbus-x11 weston xwayland && \
|
||||
(yes | mk-build-deps --install /tmp/control) || true && \
|
||||
rm /tmp/control
|
||||
|
||||
# Install lcov for code coverage
|
||||
# Update to the latest and install packages needed for Linux coverage reporting
|
||||
# and integration tests. We need at least version 2.0 of lcov. However,
|
||||
# version 2.0-4 from Noble doesn't work either on Jammy. So we use
|
||||
# version 2.0-1 from Mantic.
|
||||
RUN LCOV_VERSION=$(dpkg -s lcov | grep Version | cut -d' ' -f2) && \
|
||||
if dpkg --compare-versions "${LCOV_VERSION}" lt 2.0; then \
|
||||
curl -sS -o /tmp/lcov.deb --location http://mirrors.kernel.org/ubuntu/pool/universe/l/lcov/lcov_2.0-1_all.deb && \
|
||||
apt-get -qy install /tmp/lcov.deb && \
|
||||
rm /tmp/lcov.deb ; \
|
||||
fi
|
||||
|
||||
RUN mkdir -p /var/run/1000 && \
|
||||
chown build:build /var/run/1000 && \
|
||||
echo "export XDG_RUNTIME_DIR=/var/run/1000" >> /usr/bin/bashwrapper
|
||||
|
||||
COPY run-tests.sh /usr/bin/run-tests.sh
|
||||
|
||||
# Finish bashwrapper script and adjust permissions
|
||||
RUN <<EOF cat >> /usr/bin/bashwrapper
|
||||
|
||||
if [[ "\$@" =~ test ]] && [ -f /usr/bin/run-tests.sh ]; then
|
||||
/usr/bin/run-tests.sh "\${@:-bash}"
|
||||
else
|
||||
"\${@:-bash}"
|
||||
fi
|
||||
EOF
|
||||
|
||||
# now, switch to build user
|
||||
USER build
|
||||
|
||||
VOLUME /home/build/build
|
||||
WORKDIR /home/build/build
|
||||
|
||||
ENTRYPOINT [ "/usr/bin/bashwrapper" ]
|
||||
24
resources/docker-images/linux/run-tests.sh
Executable file
24
resources/docker-images/linux/run-tests.sh
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
if [[ -z "${DOCKER_RUNNING:-}" ]]; then
|
||||
echo "This script is intended to be run inside a docker container."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Start system dbus
|
||||
sudo dbus-daemon --system --fork
|
||||
|
||||
# Start session dbus
|
||||
# shellcheck disable=SC2046 # SC2046: quote this to prevent word-splitting
|
||||
export $(dbus-launch)
|
||||
|
||||
# Start Wayland
|
||||
weston --no-config --socket=wayland-0 --backend=headless &
|
||||
export WAYLAND_DISPLAY=wayland-0
|
||||
|
||||
# Start X11 (on Wayland)
|
||||
Xwayland &
|
||||
export DISPLAY=:0
|
||||
|
||||
"${@:-bash}"
|
||||
59
resources/docker-images/run.sh
Executable file
59
resources/docker-images/run.sh
Executable file
|
|
@ -0,0 +1,59 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
## START STANDARD BUILD SCRIPT INCLUDE
|
||||
# adjust relative paths as necessary
|
||||
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
||||
. "${THIS_SCRIPT%/*}/../../resources/build/builder.inc.sh"
|
||||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. "${KEYMAN_ROOT}/resources/build/minimum-versions.inc.sh"
|
||||
|
||||
################################ Main script ################################
|
||||
|
||||
builder_describe \
|
||||
"Run build.sh script inside of a docker image. Pass the build script and parameters after --." \
|
||||
"android" \
|
||||
"core" \
|
||||
"linux" \
|
||||
"web" \
|
||||
"--ubuntu-version=UBUNTU_VERSION The Ubuntu version (default: ${KEYMAN_DEFAULT_VERSION_UBUNTU_CONTAINER})"
|
||||
|
||||
builder_parse "$@"
|
||||
|
||||
run_android() {
|
||||
docker run -it --rm -v "${KEYMAN_ROOT}":/home/build/build \
|
||||
-v "${KEYMAN_ROOT}/core/build/docker-core":/home/build/build/core/build \
|
||||
keymanapp/keyman-android-ci:default \
|
||||
"${builder_extra_params[@]}"
|
||||
}
|
||||
|
||||
run_core() {
|
||||
docker run -it --rm -v "${KEYMAN_ROOT}":/home/build/build \
|
||||
-v "${KEYMAN_ROOT}/core/build/docker-core":/home/build/build/core/build \
|
||||
keymanapp/keyman-core-ci:default \
|
||||
"${builder_extra_params[@]}"
|
||||
}
|
||||
|
||||
run_linux() {
|
||||
mkdir -p "${KEYMAN_ROOT}/linux/build/docker-linux"
|
||||
docker run -it --privileged --rm -v "${KEYMAN_ROOT}":/home/build/build \
|
||||
-v "${KEYMAN_ROOT}/core/build/docker-core":/home/build/build/core/build \
|
||||
-v "${KEYMAN_ROOT}/linux/build/docker-linux":/home/build/build/linux/build \
|
||||
-e DESTDIR=/tmp \
|
||||
keymanapp/keyman-linux-ci:default \
|
||||
"${builder_extra_params[@]}"
|
||||
}
|
||||
|
||||
run_web() {
|
||||
docker run -it --privileged --rm -v "${KEYMAN_ROOT}":/home/build/build \
|
||||
-v "${KEYMAN_ROOT}/core/build/docker-core":/home/build/build/core/build \
|
||||
keymanapp/keyman-web-ci:default \
|
||||
"${builder_extra_params[@]}"
|
||||
}
|
||||
|
||||
mkdir -p "${KEYMAN_ROOT}/core/build/docker-core"
|
||||
|
||||
builder_run_action android run_android
|
||||
builder_run_action core run_core
|
||||
builder_run_action linux run_linux
|
||||
builder_run_action web run_web
|
||||
77
resources/docker-images/web/Dockerfile
Normal file
77
resources/docker-images/web/Dockerfile
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# Keyman is copyright (C) SIL Global. MIT License.
|
||||
#
|
||||
# ARGS used in this file:
|
||||
# - ARG BASE_VERSION=default
|
||||
# - ARG REQUIRED_EMSCRIPTEN_VERSION=unset
|
||||
|
||||
ARG BASE_VERSION=default
|
||||
FROM keymanapp/keyman-base-ci:${BASE_VERSION}
|
||||
|
||||
LABEL org.opencontainers.image.authors="SIL Global."
|
||||
LABEL org.opencontainers.image.url="https://github.com/keymanapp/keyman.git"
|
||||
LABEL org.opencontainers.image.title="Keyman for Web Build Image"
|
||||
|
||||
USER root
|
||||
RUN apt-get install -qy git jq xvfb xserver-xephyr metacity
|
||||
# For playwright:
|
||||
RUN apt-get install -qy libevent-2.1-7t64 libxslt1.1 libwoff1 libvpx9 \
|
||||
libgstreamer-plugins-bad1.0-0 libwebpdemux2 libharfbuzz-icu0 \
|
||||
libenchant-2-2 libsecret-1-0 libhyphen0 libmanette-0.2-0 libflite1 \
|
||||
gstreamer1.0-libav
|
||||
|
||||
COPY run-tests.sh /usr/bin/run-tests.sh
|
||||
|
||||
# Pre-install emscripten
|
||||
USER build
|
||||
ARG REQUIRED_EMSCRIPTEN_VERSION=unset
|
||||
RUN echo "Installing emscripten version ${REQUIRED_EMSCRIPTEN_VERSION}" && \
|
||||
export EMSDK_KEEP_DOWNLOADS=1 && \
|
||||
cd /home/build/ && \
|
||||
git clone https://github.com/emscripten-core/emsdk.git && \
|
||||
cd emsdk && \
|
||||
./emsdk install ${REQUIRED_EMSCRIPTEN_VERSION} && \
|
||||
./emsdk activate ${REQUIRED_EMSCRIPTEN_VERSION}
|
||||
USER root
|
||||
RUN echo "export EMSCRIPTEN_BASE=/home/build/emsdk/upstream/emscripten" >> /usr/bin/bashwrapper && \
|
||||
echo "export KEYMAN_USE_EMSDK=1" >> /usr/bin/bashwrapper
|
||||
|
||||
# Keyman Web
|
||||
RUN curl --output google-chrome-stable_current_amd64.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \
|
||||
apt-get -qy install ./google-chrome-stable_current_amd64.deb && \
|
||||
rm google-chrome-stable_current_amd64.deb && \
|
||||
echo "export CHROME_BIN=/opt/google/chrome/chrome" >> /usr/bin/bashwrapper
|
||||
|
||||
RUN <<EOF cat > /etc/apt/preferences.d/mozilla
|
||||
Package: *
|
||||
Pin: origin packages.mozilla.org
|
||||
Pin-Priority: 1000
|
||||
EOF
|
||||
RUN curl https://packages.mozilla.org/apt/repo-signing-key.gpg > /etc/apt/keyrings/packages.mozilla.org.asc && \
|
||||
echo "deb [signed-by=/etc/apt/keyrings/packages.mozilla.org.asc] https://packages.mozilla.org/apt mozilla main" >> /etc/apt/sources.list.d/mozilla.list && \
|
||||
apt-get update && \
|
||||
apt-get -qy install firefox && \
|
||||
echo "export FIREFOX_BIN=/usr/bin/firefox" >> /usr/bin/bashwrapper
|
||||
|
||||
# Finish bashwrapper script and adjust permissions
|
||||
RUN <<EOF cat >> /usr/bin/bashwrapper
|
||||
|
||||
if [[ "\$@" =~ test ]] && [ -f /usr/bin/run-tests.sh ]; then
|
||||
/usr/bin/run-tests.sh "\${@:-bash}"
|
||||
else
|
||||
"\${@:-bash}"
|
||||
fi
|
||||
EOF
|
||||
|
||||
# now, switch to build user
|
||||
USER build
|
||||
|
||||
# Pre-install node
|
||||
RUN export NVM_DIR="/home/build/.nvm" && \
|
||||
. /home/build/.nvm/nvm.sh && \
|
||||
cd /home/build/emsdk/upstream/emscripten && \
|
||||
npm install
|
||||
|
||||
VOLUME /home/build/build
|
||||
WORKDIR /home/build/build
|
||||
|
||||
ENTRYPOINT [ "/usr/bin/bashwrapper" ]
|
||||
17
resources/docker-images/web/run-tests.sh
Executable file
17
resources/docker-images/web/run-tests.sh
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env bash
|
||||
if [[ -z "${DOCKER_RUNNING:-}" ]]; then
|
||||
echo "This script is intended to be run inside a docker container."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
set -e
|
||||
echo "Starting Xvfb..."
|
||||
Xvfb -screen 0 1024x768x24 :33 &> /dev/null &
|
||||
sleep 1
|
||||
echo "Starting Xephyr..."
|
||||
DISPLAY=:33 Xephyr :32 -screen 1024x768 &> /dev/null &
|
||||
sleep 1
|
||||
echo "Starting metacity"
|
||||
metacity --display=:32 &> /dev/null &
|
||||
export DISPLAY=:32
|
||||
"${@:-bash}"
|
||||
|
|
@ -277,10 +277,14 @@ verify_npm_setup() {
|
|||
popd > /dev/null
|
||||
}
|
||||
|
||||
_print_expected_node_version() {
|
||||
"$JQ" -r '.engines.node' "$KEYMAN_ROOT/package.json"
|
||||
}
|
||||
|
||||
# Use nvm to select a node version according to package.json
|
||||
# see /docs/build/node.md
|
||||
_select_node_version_with_nvm() {
|
||||
local REQUIRED_NODE_VERSION="$("$JQ" -r '.engines.node' "$KEYMAN_ROOT/package.json")"
|
||||
local REQUIRED_NODE_VERSION="$(_print_expected_node_version)"
|
||||
local CURRENT_NODE_VERSION
|
||||
|
||||
if [[ $BUILDER_OS != win ]]; then
|
||||
|
|
|
|||
|
|
@ -166,7 +166,10 @@ builder_run_child_actions build:engine/attachment
|
|||
# Uses engine/interfaces (due to resource-path config interface)
|
||||
builder_run_child_actions build:engine/keyboard-storage
|
||||
|
||||
# Uses engine/interfaces, engine/keyboard-storage, & engine/osk
|
||||
# Builds the predictive-text components
|
||||
builder_run_child_actions build:engine/predictive-text
|
||||
|
||||
# Uses engine/interfaces, engine/keyboard-storage, engine/predictive-text, & engine/osk
|
||||
builder_run_child_actions build:engine/main
|
||||
|
||||
# Uses all but engine/element-wrappers and engine/attachment
|
||||
|
|
@ -190,7 +193,7 @@ builder_run_child_actions build:test-pages
|
|||
builder_run_action build:_all build_action
|
||||
|
||||
# Run tests
|
||||
# builder_run_child_actions test
|
||||
builder_run_child_actions test
|
||||
builder_run_action test:_all test_action
|
||||
|
||||
function do_test_help() {
|
||||
|
|
|
|||
65
web/src/engine/predictive-text/build.sh
Executable file
65
web/src/engine/predictive-text/build.sh
Executable file
|
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Compile keymanweb predictive-text components.
|
||||
|
||||
## START STANDARD BUILD SCRIPT INCLUDE
|
||||
# adjust relative paths as necessary
|
||||
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
||||
. "${THIS_SCRIPT%/*}/../../../../resources/build/builder.inc.sh"
|
||||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
|
||||
|
||||
# ################################ Main script ################################
|
||||
|
||||
builder_describe "Builds predictive-text components used within Keyman Engine for Web (KMW)." \
|
||||
"clean" \
|
||||
"configure" \
|
||||
"build" \
|
||||
"test" \
|
||||
":templates Builds the model templates utilized by compiled lexical models" \
|
||||
":wordbreakers Builds the wordbreakers provided for lexical model use" \
|
||||
":worker-main Builds the predictive-text worker interface module" \
|
||||
":worker-thread Builds the predictive-text worker" \
|
||||
":_all (Meta build target used when targets are not specified)" \
|
||||
"--ci+ Set to utilize CI-based test configurations & reporting."
|
||||
|
||||
# Possible TODO?
|
||||
# "upload-symbols Uploads build product to Sentry for error report symbolification. Only defined for $DOC_BUILD_EMBED_WEB" \
|
||||
|
||||
builder_parse "$@"
|
||||
|
||||
config=release
|
||||
if builder_is_debug_build; then
|
||||
config=debug
|
||||
fi
|
||||
|
||||
builder_describe_outputs \
|
||||
configure "/node_modules" \
|
||||
build:templates "/web/src/engine/predictive-text/build/obj/index.js" \
|
||||
build:wordbreakers "/web/src/engine/wordbreakers/build/main/obj/index.js" \
|
||||
build:worker-main "/web/src/engine/worker-main/build/obj/lmlayer.js" \
|
||||
build:worker-thread "/web/src/engine/worker-thread/build/obj/worker-main.wrapped.js"
|
||||
|
||||
BUNDLE_CMD="node ${KEYMAN_ROOT}/web/src/tools/es-bundling/build/common-bundle.mjs"
|
||||
|
||||
#### Build action definitions ####
|
||||
|
||||
# We can run all clean & configure actions at once without much issue.
|
||||
|
||||
builder_run_child_actions clean
|
||||
builder_run_child_actions configure
|
||||
|
||||
## Build actions
|
||||
|
||||
builder_run_child_actions build:wordbreakers
|
||||
|
||||
builder_run_child_actions build:templates
|
||||
builder_run_child_actions build:worker-thread
|
||||
builder_run_child_actions build:worker-main
|
||||
|
||||
# If doing CI testing, the predictive-text child actions have their own build configuration.
|
||||
# For local testing, though, we can allow them to proceed.
|
||||
if ! builder_has_option --ci; then
|
||||
builder_run_child_actions test
|
||||
fi
|
||||
|
|
@ -57,12 +57,13 @@ function do_build() {
|
|||
function do_test() {
|
||||
local TEST_OPTIONS=
|
||||
if builder_has_option --ci; then
|
||||
TEST_OPTIONS=--ci
|
||||
# We'll test the included libraries here for now. At some point, we may wish
|
||||
# to establish a ci.sh script for predictive-text to handle this instead.
|
||||
./unit_tests/test.sh test:libraries test:headless test:browser --ci
|
||||
else
|
||||
# If we're not in --ci mode, then this doesn't need to trigger the sibling projects' tests.
|
||||
./unit_tests/test.sh test:headless test:browser
|
||||
fi
|
||||
|
||||
# We'll test the included libraries here for now. At some point, we may wish
|
||||
# to establish a ci.sh script for predictive-text to handle this instead.
|
||||
./unit_tests/test.sh test:libraries test:headless test:browser $TEST_OPTIONS
|
||||
}
|
||||
|
||||
builder_run_action configure do_configure
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ uses
|
|||
InterfaceHotkeys in '..\..\global\delphi\general\InterfaceHotkeys.pas',
|
||||
utilsystem in '..\..\..\..\common\windows\delphi\general\utilsystem.pas',
|
||||
Upload_Settings in '..\..\..\..\common\windows\delphi\general\Upload_Settings.pas',
|
||||
UfrmOnlineUpdateNewVersion in 'main\UfrmOnlineUpdateNewVersion.pas' {frmOnlineUpdateNewVersion},
|
||||
OnlineUpdateCheck in 'main\OnlineUpdateCheck.pas',
|
||||
utilxml in '..\..\..\..\common\windows\delphi\general\utilxml.pas',
|
||||
UfrmInstallKeyboardFromWeb in 'install\UfrmInstallKeyboardFromWeb.pas' {frmInstallKeyboardFromWeb},
|
||||
|
|
@ -77,7 +76,6 @@ uses
|
|||
UserMessages in '..\..\..\..\common\windows\delphi\general\UserMessages.pas',
|
||||
UILanguages in 'util\UILanguages.pas',
|
||||
UfrmKeyboardOptions in 'main\UfrmKeyboardOptions.pas' {frmKeyboardOptions},
|
||||
UfrmOnlineUpdateIcon in 'main\UfrmOnlineUpdateIcon.pas' {frmOnlineUpdateIcon},
|
||||
KeymanTrayIcon in '..\..\engine\keyman\KeymanTrayIcon.pas',
|
||||
UImportOlderVersionKeyboards10 in 'main\UImportOlderVersionKeyboards10.pas',
|
||||
VisualKeyboard in '..\..\..\..\common\windows\delphi\visualkeyboard\VisualKeyboard.pas',
|
||||
|
|
@ -177,7 +175,15 @@ uses
|
|||
Keyman.Configuration.System.HttpServer.App.TextEditorFonts in 'startup\help\Keyman.Configuration.System.HttpServer.App.TextEditorFonts.pas',
|
||||
Keyman.Configuration.System.HttpServer.App.Locale in 'web\Keyman.Configuration.System.HttpServer.App.Locale.pas',
|
||||
Keyman.System.AndroidStringToKeymanLocaleString in '..\..\..\..\common\windows\delphi\general\Keyman.System.AndroidStringToKeymanLocaleString.pas',
|
||||
Keyman.Configuration.System.Main in 'main\Keyman.Configuration.System.Main.pas';
|
||||
Keyman.Configuration.System.Main in 'main\Keyman.Configuration.System.Main.pas',
|
||||
UpdateXMLRenderer in 'render\UpdateXMLRenderer.pas',
|
||||
Keyman.System.UpdateCheckStorage in 'main\Keyman.System.UpdateCheckStorage.pas',
|
||||
Keyman.System.RemoteUpdateCheck in 'main\Keyman.System.RemoteUpdateCheck.pas',
|
||||
Keyman.System.UpdateStateMachine in 'main\Keyman.System.UpdateStateMachine.pas',
|
||||
Keyman.System.DownloadUpdate in 'main\Keyman.System.DownloadUpdate.pas',
|
||||
Keyman.System.ExecutionHistory in '..\..\..\..\common\windows\delphi\general\Keyman.System.ExecutionHistory.pas',
|
||||
Keyman.Configuration.UI.UfrmStartInstallNow in 'main\Keyman.Configuration.UI.UfrmStartInstallNow.pas' {frmInstallNow},
|
||||
Keyman.Configuration.UI.UfrmStartInstall in 'main\Keyman.Configuration.UI.UfrmStartInstall.pas' {frmStartInstall};
|
||||
|
||||
{$R VERSION.RES}
|
||||
{$R manifest.res}
|
||||
|
|
|
|||
|
|
@ -171,9 +171,6 @@
|
|||
<DCCReference Include="..\..\global\delphi\general\InterfaceHotkeys.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\general\utilsystem.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\general\Upload_Settings.pas"/>
|
||||
<DCCReference Include="main\UfrmOnlineUpdateNewVersion.pas">
|
||||
<Form>frmOnlineUpdateNewVersion</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="main\OnlineUpdateCheck.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\general\utilxml.pas"/>
|
||||
<DCCReference Include="install\UfrmInstallKeyboardFromWeb.pas">
|
||||
|
|
@ -224,9 +221,6 @@
|
|||
<DCCReference Include="main\UfrmKeyboardOptions.pas">
|
||||
<Form>frmKeyboardOptions</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="main\UfrmOnlineUpdateIcon.pas">
|
||||
<Form>frmOnlineUpdateIcon</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\engine\keyman\KeymanTrayIcon.pas"/>
|
||||
<DCCReference Include="main\UImportOlderVersionKeyboards10.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\visualkeyboard\VisualKeyboard.pas"/>
|
||||
|
|
@ -354,6 +348,20 @@
|
|||
<DCCReference Include="web\Keyman.Configuration.System.HttpServer.App.Locale.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\general\Keyman.System.AndroidStringToKeymanLocaleString.pas"/>
|
||||
<DCCReference Include="main\Keyman.Configuration.System.Main.pas"/>
|
||||
<DCCReference Include="render\UpdateXMLRenderer.pas"/>
|
||||
<DCCReference Include="main\Keyman.System.UpdateCheckStorage.pas"/>
|
||||
<DCCReference Include="main\Keyman.System.RemoteUpdateCheck.pas"/>
|
||||
<DCCReference Include="main\Keyman.System.UpdateStateMachine.pas"/>
|
||||
<DCCReference Include="main\Keyman.System.DownloadUpdate.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\general\Keyman.System.ExecutionHistory.pas"/>
|
||||
<DCCReference Include="main\Keyman.Configuration.UI.UfrmStartInstallNow.pas">
|
||||
<Form>frmInstallNow</Form>
|
||||
<FormType>dfm</FormType>
|
||||
</DCCReference>
|
||||
<DCCReference Include="main\Keyman.Configuration.UI.UfrmStartInstall.pas">
|
||||
<Form>frmStartInstall</Form>
|
||||
<FormType>dfm</FormType>
|
||||
</DCCReference>
|
||||
<None Include="Profiling\AQtimeModule1.aqt"/>
|
||||
<BuildConfiguration Include="Debug">
|
||||
<Key>Cfg_2</Key>
|
||||
|
|
@ -415,13 +423,19 @@
|
|||
<Platform value="Win64">False</Platform>
|
||||
</Platforms>
|
||||
<Deployment Version="3">
|
||||
<DeployFile LocalName="kmshell.rsm" Configuration="Debug" Class="DebugSymbols">
|
||||
<DeployFile LocalName="bin\Win32\Debug\kmshell.rsm" Configuration="Debug" Class="DebugSymbols">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>kmshell.rsm</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployFile LocalName="kmshell.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<DeployFile LocalName="bin\Win32\Debug\kmshell.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>kmshell.exe</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployFile LocalName="bin\Win32\Debug\kmshell.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>kmshell.exe</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
|
|
@ -1228,6 +1242,7 @@
|
|||
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
|
||||
</Deployment>
|
||||
<ModelSupport>False</ModelSupport>
|
||||
</BorlandProject>
|
||||
<ProjectFileVersion>12</ProjectFileVersion>
|
||||
</ProjectExtensions>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
``` mermaid
|
||||
stateDiagram
|
||||
[*] --> Idle
|
||||
Idle --> UpdateAvailable
|
||||
UpdateAvailable --> Downloading
|
||||
Downloading --> Installing
|
||||
Downloading --> WaitingRestart
|
||||
WaitingRestart --> Installing
|
||||
Installing --> Idle
|
||||
```
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
object frmStartInstall: TfrmStartInstall
|
||||
Left = 0
|
||||
Top = 0
|
||||
BorderIcons = [biSystemMenu]
|
||||
BorderStyle = bsDialog
|
||||
Caption = 'Keyman Update'
|
||||
ClientHeight = 142
|
||||
ClientWidth = 322
|
||||
Color = clBtnFace
|
||||
Font.Charset = DEFAULT_CHARSET
|
||||
Font.Color = clWindowText
|
||||
Font.Height = -11
|
||||
Font.Name = 'Tahoma'
|
||||
Font.Style = []
|
||||
OldCreateOrder = False
|
||||
Position = poScreenCenter
|
||||
PixelsPerInch = 96
|
||||
TextHeight = 13
|
||||
object lblInstallUpdate: TLabel
|
||||
Left = 72
|
||||
Top = 48
|
||||
Width = 180
|
||||
Height = 19
|
||||
Caption = 'Keyman update available.'
|
||||
Font.Charset = DEFAULT_CHARSET
|
||||
Font.Color = clWindowText
|
||||
Font.Height = -16
|
||||
Font.Name = 'Tahoma'
|
||||
Font.Style = []
|
||||
ParentFont = False
|
||||
end
|
||||
object cmdInstall: TButton
|
||||
Left = 140
|
||||
Top = 104
|
||||
Width = 75
|
||||
Height = 25
|
||||
Caption = 'Install'
|
||||
ModalResult = 1
|
||||
TabOrder = 0
|
||||
end
|
||||
object cmdLater: TButton
|
||||
Left = 234
|
||||
Top = 104
|
||||
Width = 75
|
||||
Height = 25
|
||||
Caption = 'Close'
|
||||
ModalResult = 8
|
||||
TabOrder = 1
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
Keyman is copyright (C) SIL Global. MIT License.
|
||||
|
||||
// TODO: #12887 Localise all the labels and captions.
|
||||
}
|
||||
unit Keyman.Configuration.UI.UfrmStartInstall;
|
||||
interface
|
||||
|
||||
uses
|
||||
System.Classes,
|
||||
System.SysUtils,
|
||||
System.Variants,
|
||||
Vcl.Controls,
|
||||
Vcl.Dialogs,
|
||||
Vcl.ExtCtrls,
|
||||
Vcl.Forms,
|
||||
Vcl.Graphics,
|
||||
Vcl.StdCtrls,
|
||||
Winapi.Messages,
|
||||
Winapi.Windows,
|
||||
UfrmKeymanBase,
|
||||
UserMessages;
|
||||
|
||||
type
|
||||
TfrmStartInstall = class(TfrmKeymanBase)
|
||||
cmdInstall: TButton;
|
||||
cmdLater: TButton;
|
||||
lblInstallUpdate: TLabel;
|
||||
private
|
||||
public
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
|
||||
end.
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
object frmStartInstallNow: TfrmStartInstallNow
|
||||
Left = 0
|
||||
Top = 0
|
||||
BorderIcons = [biSystemMenu]
|
||||
BorderStyle = bsDialog
|
||||
Caption = 'Keyman Update'
|
||||
ClientHeight = 164
|
||||
ClientWidth = 354
|
||||
Color = clBtnFace
|
||||
Font.Charset = DEFAULT_CHARSET
|
||||
Font.Color = clWindowText
|
||||
Font.Height = -11
|
||||
Font.Name = 'Tahoma'
|
||||
Font.Style = []
|
||||
OldCreateOrder = False
|
||||
Position = poScreenCenter
|
||||
PixelsPerInch = 96
|
||||
TextHeight = 13
|
||||
object lblUpdateMessage: TLabel
|
||||
Left = 32
|
||||
Top = 48
|
||||
Width = 290
|
||||
Height = 41
|
||||
Caption = 'Your computer will be restarted if you update now.'
|
||||
Font.Charset = DEFAULT_CHARSET
|
||||
Font.Color = clWindowText
|
||||
Font.Height = -16
|
||||
Font.Name = 'Tahoma'
|
||||
Font.Style = []
|
||||
ParentFont = False
|
||||
WordWrap = True
|
||||
end
|
||||
object cmdInstall: TButton
|
||||
Left = 147
|
||||
Top = 120
|
||||
Width = 75
|
||||
Height = 25
|
||||
Caption = 'Update now'
|
||||
ModalResult = 1
|
||||
TabOrder = 0
|
||||
end
|
||||
object cmdLater: TButton
|
||||
Left = 247
|
||||
Top = 120
|
||||
Width = 75
|
||||
Height = 25
|
||||
Caption = 'Close'
|
||||
ModalResult = 8
|
||||
TabOrder = 1
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
Keyman is copyright (C) SIL Global. MIT License.
|
||||
|
||||
// TODO: #12887 Localise all the labels and captions.
|
||||
}
|
||||
unit Keyman.Configuration.UI.UfrmStartInstallNow;
|
||||
interface
|
||||
|
||||
uses
|
||||
System.Classes,
|
||||
System.SysUtils,
|
||||
System.Variants,
|
||||
Vcl.Controls,
|
||||
Vcl.Dialogs,
|
||||
Vcl.ExtCtrls,
|
||||
Vcl.Forms,
|
||||
Vcl.Graphics,
|
||||
Vcl.StdCtrls,
|
||||
Winapi.Messages,
|
||||
Winapi.Windows,
|
||||
UfrmKeymanBase,
|
||||
UserMessages;
|
||||
|
||||
type
|
||||
TfrmStartInstallNow = class(TfrmKeymanBase)
|
||||
cmdInstall: TButton;
|
||||
cmdLater: TButton;
|
||||
lblUpdateMessage: TLabel;
|
||||
private
|
||||
public
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
(*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*)
|
||||
unit Keyman.System.DownloadUpdate;
|
||||
|
||||
interface
|
||||
uses
|
||||
System.Classes,
|
||||
System.SysUtils,
|
||||
Sentry.Client,
|
||||
httpuploader,
|
||||
Keyman.System.KeymanSentryClient,
|
||||
Keyman.System.UpdateCheckResponse,
|
||||
KeymanPaths;
|
||||
|
||||
type
|
||||
TDownloadUpdateParams = record
|
||||
TotalSize: Integer;
|
||||
TotalDownloads: Integer;
|
||||
StartPosition: Integer;
|
||||
end;
|
||||
|
||||
TDownloadUpdate = class
|
||||
private
|
||||
FShowErrors: Boolean;
|
||||
FDownload: TDownloadUpdateParams;
|
||||
(**
|
||||
*
|
||||
* Performs updates download in the background.
|
||||
* @params SavePath The path where the downloaded files will be saved.
|
||||
*
|
||||
*@returns A Boolean value indicating the overall result of the
|
||||
* download process.
|
||||
*)
|
||||
function DoDownloadUpdates(SavePath: string; Params: TUpdateCheckResponse): Boolean;
|
||||
|
||||
public
|
||||
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
|
||||
|
||||
function DownloadUpdates : Boolean;
|
||||
// TODO: #12888 verify filesizes match the ucr metadata so we know we don't have partial downloads.
|
||||
//function VerifyAllFilesDownloaded : Boolean;
|
||||
property ShowErrors: Boolean read FShowErrors write FShowErrors;
|
||||
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
uses
|
||||
System.StrUtils,
|
||||
System.Types,
|
||||
ErrorControlledRegistry,
|
||||
GlobalProxySettings,
|
||||
keymanapi_TLB,
|
||||
KeymanVersion,
|
||||
Keyman.System.UpdateCheckStorage,
|
||||
KLog,
|
||||
kmint,
|
||||
OnlineUpdateCheckMessages,
|
||||
RegistryKeys,
|
||||
Upload_Settings,
|
||||
utilkmshell;
|
||||
|
||||
procedure ErrorLogMessage(ErrorLogMessage: string);
|
||||
begin
|
||||
KL.Log(ErrorLogMessage);
|
||||
TKeymanSentryClient.Client.MessageEvent(Sentry.Client.SENTRY_LEVEL_ERROR,
|
||||
ErrorLogMessage);
|
||||
end;
|
||||
|
||||
constructor TDownloadUpdate.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
FShowErrors := True;
|
||||
KL.Log('TDownloadUpdate.Create');
|
||||
end;
|
||||
|
||||
destructor TDownloadUpdate.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TDownloadUpdate.DoDownloadUpdates(SavePath: string; Params: TUpdateCheckResponse): Boolean;
|
||||
var
|
||||
i : Integer;
|
||||
http: THttpUploader;
|
||||
fs: TFileStream;
|
||||
|
||||
function DownloadFile(const url, savepath: string): Boolean;
|
||||
begin
|
||||
try
|
||||
http := THttpUploader.Create(nil);
|
||||
try
|
||||
http.Proxy.Server := GetProxySettings.Server;
|
||||
http.Proxy.Port := GetProxySettings.Port;
|
||||
http.Proxy.Username := GetProxySettings.Username;
|
||||
http.Proxy.Password := GetProxySettings.Password;
|
||||
http.Request.Agent := API_UserAgent;
|
||||
|
||||
http.Request.SetURL(url);
|
||||
http.Upload;
|
||||
if http.Response.StatusCode = 200 then
|
||||
begin
|
||||
fs := TFileStream.Create(savepath, fmCreate);
|
||||
try
|
||||
fs.Write(http.Response.PMessageBody^, http.Response.MessageBodyLength);
|
||||
finally
|
||||
fs.Free;
|
||||
end;
|
||||
Result := True;
|
||||
end
|
||||
else // I2742
|
||||
begin
|
||||
// If it fails we set to false but will try the other files
|
||||
Exit(False);
|
||||
end;
|
||||
finally
|
||||
http.Free;
|
||||
end;
|
||||
except
|
||||
on E:EHTTPUploader do
|
||||
begin
|
||||
if (E.ErrorCode = 12007) or (E.ErrorCode = 12029)
|
||||
then ErrorLogMessage(S_OnlineUpdate_UnableToContact)
|
||||
else ErrorLogMessage(WideFormat(S_OnlineUpdate_UnableToContact_Error, [E.Message]));
|
||||
Result := False;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
Result := False;
|
||||
|
||||
FDownload.TotalSize := 0;
|
||||
FDownload.TotalDownloads := 0;
|
||||
|
||||
// Keyboard Packages
|
||||
FDownload.StartPosition := 0;
|
||||
for i := 0 to High(Params.Packages) do
|
||||
begin
|
||||
Inc(FDownload.TotalDownloads);
|
||||
Inc(FDownload.TotalSize, Params.Packages[i].DownloadSize);
|
||||
Params.Packages[i].SavePath := SavePath + Params.Packages[i].FileName;
|
||||
if not DownloadFile(Params.Packages[i].DownloadURL, Params.Packages[i].SavePath) then // I2742
|
||||
begin
|
||||
Params.Packages[i].Install := False; // Download failed but install other files
|
||||
end;
|
||||
FDownload.StartPosition := FDownload.StartPosition + Params.Packages[i].DownloadSize;
|
||||
end;
|
||||
|
||||
// Keyman Installer
|
||||
Inc(FDownload.TotalDownloads);
|
||||
Inc(FDownload.TotalSize, Params.InstallSize);
|
||||
if not DownloadFile(Params.InstallURL, SavePath + Params.FileName) then // I2742
|
||||
begin
|
||||
ErrorLogMessage('DoDownloadUpdates Failed to download' + Params.InstallURL);
|
||||
end
|
||||
else
|
||||
begin
|
||||
// If installer has downloaded that is success even
|
||||
// if zero packages were downloaded.
|
||||
Result := True;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDownloadUpdate.DownloadUpdates: Boolean;
|
||||
var
|
||||
DownloadBackGroundSavePath : String;
|
||||
ucr: TUpdateCheckResponse;
|
||||
begin
|
||||
DownloadBackGroundSavePath := IncludeTrailingPathDelimiter(TKeymanPaths.KeymanUpdateCachePath);
|
||||
if TUpdateCheckStorage.LoadUpdateCacheData(ucr) then
|
||||
begin
|
||||
Result := DoDownloadUpdates(DownloadBackGroundSavePath, ucr);
|
||||
KL.Log('DownloadUpdates.DownloadUpdates: DownloadResult = '+IntToStr(Ord(Result)));
|
||||
end
|
||||
else
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
(**
|
||||
* Keyman is copyright (C) SIL International. MIT License.
|
||||
*
|
||||
* Keyman.System.RemoteUpdateCheck: Checks for keyboard package and Keyman
|
||||
* for Windows updates.
|
||||
*)
|
||||
unit Keyman.System.RemoteUpdateCheck; // I3306
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.Classes,
|
||||
System.SysUtils,
|
||||
KeymanPaths,
|
||||
httpuploader,
|
||||
Keyman.System.UpdateCheckResponse;
|
||||
|
||||
const
|
||||
CheckPeriod: Integer = 7; // Days between checking for updates
|
||||
|
||||
type
|
||||
ERemoteUpdateCheck = class(Exception);
|
||||
|
||||
TRemoteUpdateCheckResult = (wucUnknown, wucSuccess, wucNoUpdates, wucFailure, wucOffline);
|
||||
|
||||
TRemoteUpdateCheckDownloadParams = record
|
||||
TotalSize: Integer;
|
||||
TotalDownloads: Integer;
|
||||
StartPosition: Integer;
|
||||
end;
|
||||
|
||||
TRemoteUpdateCheck = class
|
||||
private
|
||||
FForce: Boolean;
|
||||
FRemoteResult: TRemoteUpdateCheckResult;
|
||||
FErrorMessage: string;
|
||||
FShowErrors: Boolean;
|
||||
(**
|
||||
* Performs an online query of both the main keyman package and
|
||||
* the keyboard packages. It utilizes the kmcom API to retrieve the current
|
||||
* packages. The function then performs an HTTP request to query the remote
|
||||
* versions of these packages.
|
||||
* The resulting information is stored in the TUpdateCheckResponse
|
||||
* variable and seralized to disk.
|
||||
*
|
||||
* @returns A TBackgroundUpdateResult indicating the result of the update
|
||||
* check.
|
||||
*)
|
||||
function DoRun: TRemoteUpdateCheckResult;
|
||||
public
|
||||
|
||||
constructor Create(AForce: Boolean);
|
||||
destructor Destroy; override;
|
||||
function Run: TRemoteUpdateCheckResult;
|
||||
property ShowErrors: Boolean read FShowErrors write FShowErrors;
|
||||
end;
|
||||
|
||||
(**
|
||||
* This function checks if a week or CheckPeriod time has passed since the last
|
||||
* update check.
|
||||
*
|
||||
* @returns True if it has been longer then CheckPeriod time since last update
|
||||
*)
|
||||
function ConfigCheckContinue: Boolean;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.WideStrUtils,
|
||||
System.Win.Registry,
|
||||
Winapi.Windows,
|
||||
Winapi.WinINet,
|
||||
Sentry.Client,
|
||||
|
||||
GlobalProxySettings,
|
||||
KLog,
|
||||
keymanapi_TLB,
|
||||
KeymanVersion,
|
||||
Keyman.System.KeymanSentryClient,
|
||||
Keyman.System.UpdateCheckStorage,
|
||||
kmint,
|
||||
ErrorControlledRegistry,
|
||||
RegistryKeys,
|
||||
Upload_Settings,
|
||||
|
||||
OnlineUpdateCheckMessages;
|
||||
|
||||
{ TRemoteUpdateCheck }
|
||||
|
||||
constructor TRemoteUpdateCheck.Create(AForce: Boolean);
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
FShowErrors := True;
|
||||
FRemoteResult := wucUnknown;
|
||||
|
||||
FForce := AForce;
|
||||
|
||||
KL.Log('TRemoteUpdateCheck.Create');
|
||||
end;
|
||||
|
||||
destructor TRemoteUpdateCheck.Destroy;
|
||||
begin
|
||||
if (FErrorMessage <> '') and FShowErrors then
|
||||
TKeymanSentryClient.Client.MessageEvent(Sentry.Client.SENTRY_LEVEL_ERROR,
|
||||
'"+FErrorMessage+"');
|
||||
|
||||
KL.Log('TRemoteUpdateCheck.Destroy: FErrorMessage = ' + FErrorMessage);
|
||||
KL.Log('TRemoteUpdateCheck.Destroy: FRemoteResult = ' +
|
||||
IntToStr(Ord(FRemoteResult)));
|
||||
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TRemoteUpdateCheck.Run: TRemoteUpdateCheckResult;
|
||||
begin
|
||||
Result := DoRun;
|
||||
FRemoteResult := Result;
|
||||
end;
|
||||
|
||||
function TRemoteUpdateCheck.DoRun: TRemoteUpdateCheckResult;
|
||||
var
|
||||
flags: DWord;
|
||||
i: Integer;
|
||||
ucr: TUpdateCheckResponse;
|
||||
pkg: IKeymanPackage;
|
||||
Registry: TRegistryErrorControlled;
|
||||
http: THttpUploader;
|
||||
proceed: Boolean;
|
||||
begin
|
||||
{ FProxyHost := '';
|
||||
FProxyPort := 0; }
|
||||
|
||||
{ Check if user is currently online }
|
||||
if not InternetGetConnectedState(@flags, 0) then
|
||||
begin
|
||||
Result := wucOffline;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
proceed := ConfigCheckContinue;
|
||||
if not proceed and not FForce then
|
||||
begin
|
||||
Result := wucNoUpdates;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
try
|
||||
http := THttpUploader.Create(nil);
|
||||
try
|
||||
http.Fields.Add('version', ansistring(CKeymanVersionInfo.Version));
|
||||
http.Fields.Add('tier', ansistring(CKeymanVersionInfo.Tier));
|
||||
if FForce then
|
||||
http.Fields.Add('manual', '1')
|
||||
else
|
||||
http.Fields.Add('manual', '0');
|
||||
|
||||
for i := 0 to kmcom.Packages.Count - 1 do
|
||||
begin
|
||||
pkg := kmcom.Packages[i];
|
||||
|
||||
// Due to limitations in PHP parsing of query string parameters names with
|
||||
// space or period, we need to split the parameters up. The legacy pattern
|
||||
// is still supported on the server side. Relates to #4886.
|
||||
http.Fields.Add(ansistring('packageid_' + IntToStr(i)),
|
||||
ansistring(pkg.ID));
|
||||
http.Fields.Add(ansistring('packageversion_' + IntToStr(i)),
|
||||
ansistring(pkg.Version));
|
||||
pkg := nil;
|
||||
end;
|
||||
|
||||
http.Proxy.Server := GetProxySettings.Server;
|
||||
http.Proxy.Port := GetProxySettings.Port;
|
||||
http.Proxy.Username := GetProxySettings.Username;
|
||||
http.Proxy.Password := GetProxySettings.Password;
|
||||
|
||||
http.Request.HostName := API_Server;
|
||||
http.Request.Protocol := API_Protocol;
|
||||
http.Request.UrlPath := API_Path_UpdateCheck_Windows;
|
||||
// OnStatus :=
|
||||
http.Upload;
|
||||
if http.Response.StatusCode = 200 then
|
||||
begin
|
||||
if ucr.Parse(http.Response.MessageBodyAsString, 'bundle', CKeymanVersionInfo.Version) then
|
||||
begin
|
||||
TUpdateCheckStorage.SaveUpdateCacheData(ucr);
|
||||
Result := wucSuccess;
|
||||
end
|
||||
else
|
||||
begin
|
||||
FErrorMessage := ucr.ErrorMessage;
|
||||
Result := wucFailure;
|
||||
end;
|
||||
end
|
||||
else
|
||||
raise ERemoteUpdateCheck.Create('Error '+IntToStr(http.Response.StatusCode));
|
||||
finally
|
||||
http.Free;
|
||||
end;
|
||||
except
|
||||
on E: EHTTPUploader do
|
||||
begin
|
||||
if (E.ErrorCode = 12007) or (E.ErrorCode = 12029) then
|
||||
FErrorMessage := S_OnlineUpdate_UnableToContact
|
||||
else
|
||||
FErrorMessage := WideFormat(S_OnlineUpdate_UnableToContact_Error,
|
||||
[E.Message]);
|
||||
Result := wucFailure;
|
||||
end;
|
||||
on E: Exception do
|
||||
begin
|
||||
FErrorMessage := E.Message;
|
||||
Result := wucFailure;
|
||||
end;
|
||||
end;
|
||||
|
||||
Registry := TRegistryErrorControlled.Create; // I2890
|
||||
try
|
||||
if Registry.OpenKey(SRegKey_KeymanDesktop_CU, True) then
|
||||
Registry.WriteDateTime(SRegValue_LastUpdateCheckTime, Now);
|
||||
finally
|
||||
Registry.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function ConfigCheckContinue: Boolean;
|
||||
var
|
||||
Registry: TRegistryErrorControlled;
|
||||
begin
|
||||
{ Verify that it has been at least CheckPeriod days since last update check }
|
||||
Result := False;
|
||||
try
|
||||
Registry := TRegistryErrorControlled.Create; // I2890
|
||||
try
|
||||
if Registry.OpenKeyReadOnly(SRegKey_KeymanDesktop_CU) then
|
||||
begin
|
||||
if Registry.ValueExists(SRegValue_CheckForUpdates) and
|
||||
not Registry.ReadBool(SRegValue_CheckForUpdates) then
|
||||
begin
|
||||
Exit;
|
||||
end;
|
||||
if Registry.ValueExists(SRegValue_LastUpdateCheckTime) and
|
||||
(Now - Registry.ReadDateTime(SRegValue_LastUpdateCheckTime) >
|
||||
CheckPeriod) then
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
Registry.Free;
|
||||
end;
|
||||
except
|
||||
on E: ERegistryException do
|
||||
begin
|
||||
Result := False;
|
||||
TKeymanSentryClient.Client.MessageEvent(Sentry.Client.SENTRY_LEVEL_ERROR,
|
||||
E.Message);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
unit Keyman.System.UpdateCheckStorage;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Keyman.System.UpdateCheckResponse;
|
||||
|
||||
type
|
||||
TUpdateCheckStorage = class sealed
|
||||
private
|
||||
class function MetadataFilename: string; static;
|
||||
public
|
||||
class function HasUpdates: Boolean; static;
|
||||
class function LoadUpdateCacheData(var data: TUpdateCheckResponse): Boolean; static;
|
||||
class procedure SaveUpdateCacheData(const data: TUpdateCheckResponse); static;
|
||||
class function HasKeyboardPackages(const data: TUpdateCheckResponse): Boolean; static;
|
||||
class function HasKeymanInstallFile(const data: TUpdateCheckResponse): Boolean; static;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.RegularExpressions,
|
||||
|
||||
KeymanPaths,
|
||||
KeymanVersion;
|
||||
|
||||
{ TUpdateCheckStorage }
|
||||
|
||||
class function TUpdateCheckStorage.MetadataFilename: string;
|
||||
begin
|
||||
Result := TKeymanPaths.KeymanUpdateCachePath(TKeymanPaths.S_UpdateCache_Metadata);
|
||||
end;
|
||||
|
||||
class procedure TUpdateCheckStorage.SaveUpdateCacheData(
|
||||
const data: TUpdateCheckResponse);
|
||||
begin
|
||||
ForceDirectories(TKeymanPaths.KeymanUpdateCachePath);
|
||||
data.SaveToFile(MetadataFilename);
|
||||
end;
|
||||
|
||||
class function TUpdateCheckStorage.HasUpdates: Boolean;
|
||||
begin
|
||||
Result := FileExists(MetadataFilename);
|
||||
end;
|
||||
|
||||
class function TUpdateCheckStorage.LoadUpdateCacheData(var data: TUpdateCheckResponse): Boolean;
|
||||
begin
|
||||
Result :=
|
||||
HasUpdates and
|
||||
data.LoadFromFile(MetadataFilename, 'bundle', CKeymanVersionInfo.Version);
|
||||
end;
|
||||
|
||||
class function TUpdateCheckStorage.HasKeyboardPackages(const data: TUpdateCheckResponse): Boolean;
|
||||
var
|
||||
i : Integer;
|
||||
fileName : string;
|
||||
KeyboardRegex: TRegEx;
|
||||
begin
|
||||
Result := False;
|
||||
KeyboardRegex := TRegEx.Create('\.k..$');
|
||||
for i := 0 to High(data.Packages) do
|
||||
begin
|
||||
fileName := data.Packages[i].FileName;
|
||||
if KeyboardRegex.IsMatch(fileName) then
|
||||
Result := True;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TUpdateCheckStorage.HasKeymanInstallFile(const data: TUpdateCheckResponse): Boolean;
|
||||
var
|
||||
fileExtension: string;
|
||||
begin
|
||||
fileExtension := LowerCase(ExtractFileExt(data.FileName));
|
||||
if fileExtension = '.exe' then
|
||||
Result := True
|
||||
else
|
||||
Result := False
|
||||
end;
|
||||
|
||||
end.
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -98,11 +98,11 @@ type
|
|||
|
||||
FShowErrors: Boolean;
|
||||
FDownload: TOnlineUpdateCheckDownloadParams;
|
||||
FCheckOnly: Boolean;
|
||||
|
||||
function DownloadUpdates: Boolean;
|
||||
procedure DoDownloadUpdates(AOwner: TfrmDownloadProgress; var Result: Boolean);
|
||||
function DoRun: TOnlineUpdateCheckResult;
|
||||
procedure ShowUpdateForm;
|
||||
procedure ShutDown;
|
||||
procedure DownloadUpdatesHTTPStatus(Sender: THTTPUploader;
|
||||
const Message: string; Position, Total: Int64); // I2855
|
||||
|
|
@ -112,7 +112,9 @@ type
|
|||
public
|
||||
|
||||
public
|
||||
constructor Create(AOwner: TCustomForm; AForce, ASilent: Boolean);
|
||||
function ResponseToParams(const ucr: TUpdateCheckResponse): TOnlineUpdateCheckParams;
|
||||
|
||||
constructor Create(AOwner: TCustomForm; AForce, ASilent: Boolean; ACheckOnly: Boolean = False);
|
||||
destructor Destroy; override;
|
||||
function Run: TOnlineUpdateCheckResult;
|
||||
property ShowErrors: Boolean read FShowErrors write FShowErrors;
|
||||
|
|
@ -146,6 +148,7 @@ uses
|
|||
KLog,
|
||||
keymanapi_TLB,
|
||||
KeymanVersion,
|
||||
Keyman.System.UpdateCheckStorage,
|
||||
kmint,
|
||||
ErrorControlledRegistry,
|
||||
RegistryKeys,
|
||||
|
|
@ -153,8 +156,6 @@ uses
|
|||
utildir,
|
||||
utilexecute,
|
||||
OnlineUpdateCheckMessages,
|
||||
UfrmOnlineUpdateIcon,
|
||||
UfrmOnlineUpdateNewVersion,
|
||||
utilkmshell,
|
||||
utilsystem,
|
||||
utiluac,
|
||||
|
|
@ -165,7 +166,7 @@ const
|
|||
|
||||
{ TOnlineUpdateCheck }
|
||||
|
||||
constructor TOnlineUpdateCheck.Create(AOwner: TCustomForm; AForce, ASilent: Boolean);
|
||||
constructor TOnlineUpdateCheck.Create(AOwner: TCustomForm; AForce, ASilent: Boolean; ACheckOnly: Boolean);
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
|
|
@ -176,6 +177,7 @@ begin
|
|||
|
||||
FSilent := ASilent;
|
||||
FForce := AForce;
|
||||
FCheckOnly := ACheckOnly;
|
||||
|
||||
KL.Log('TOnlineUpdateCheck.Create');
|
||||
end;
|
||||
|
|
@ -388,86 +390,6 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure TOnlineUpdateCheck.ShowUpdateForm;
|
||||
var
|
||||
i: Integer;
|
||||
FRequiresAdmin: Boolean;
|
||||
FOwnerHandle: THandle;
|
||||
begin
|
||||
if Assigned(FOwner)
|
||||
then FOwnerHandle := FOwner.Handle
|
||||
else FOwnerHandle := Application.Handle;
|
||||
|
||||
{ We have an update available }
|
||||
with OnlineUpdateNewVersion(FOwner) do
|
||||
try
|
||||
Params := Self.FParams;
|
||||
if ShowModal <> mrYes then
|
||||
begin
|
||||
Self.FParams.Result := oucUnknown;
|
||||
Self.FErrorMessage := '';
|
||||
Exit;
|
||||
end;
|
||||
|
||||
Self.FParams := Params;
|
||||
finally
|
||||
Free;
|
||||
end;
|
||||
|
||||
if not DownloadUpdates then
|
||||
begin
|
||||
Self.FParams.Result := oucUnknown; // I2742
|
||||
Exit;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if not kmcom.SystemInfo.IsAdministrator then
|
||||
begin
|
||||
FRequiresAdmin := FParams.Keyman.Install;
|
||||
for i := 0 to High(FParams.Packages) do
|
||||
if FParams.Packages[i].Install then
|
||||
begin
|
||||
FRequiresAdmin := True;
|
||||
Break;
|
||||
end;
|
||||
end
|
||||
else
|
||||
FRequiresAdmin := False;
|
||||
|
||||
if FRequiresAdmin then
|
||||
begin
|
||||
if CanElevate then
|
||||
begin
|
||||
SavePackageUpgradesToDownloadTempPath;
|
||||
if WaitForElevatedConfiguration(FOwnerHandle, '-ou "'+DownloadTempPath+'"', not FParams.Keyman.Install) <> 0 then // I2513
|
||||
FParams.Result := oucFailure
|
||||
else if FParams.Keyman.Install then
|
||||
FParams.Result := oucShutDown
|
||||
else
|
||||
FParams.Result := oucSuccess;
|
||||
end
|
||||
else
|
||||
begin
|
||||
ShowMessage('Some of these updates require an Administrator to complete installation. Please login as an Administrator and re-run the update.');
|
||||
FParams.Result := oucFailure;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
FParams.Result := oucSuccess;
|
||||
for i := 0 to High(FParams.Packages) do
|
||||
if FParams.Packages[i].Install then
|
||||
if not DoInstallPackage(FParams.Packages[i]) then FParams.Result := oucFailure;
|
||||
|
||||
if FParams.Keyman.Install then
|
||||
begin
|
||||
DoInstallKeyman;
|
||||
FParams.Result := oucShutDown;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TOnlineUpdateCheck.ShutDown;
|
||||
begin
|
||||
if Assigned(Application) then
|
||||
|
|
@ -477,10 +399,9 @@ end;
|
|||
function TOnlineUpdateCheck.DoRun: TOnlineUpdateCheckResult;
|
||||
var
|
||||
flags: DWord;
|
||||
i, n: Integer;
|
||||
pkg: IKeymanPackage;
|
||||
j: Integer;
|
||||
i: Integer;
|
||||
ucr: TUpdateCheckResponse;
|
||||
pkg: IKeymanPackage;
|
||||
begin
|
||||
{FProxyHost := '';
|
||||
FProxyPort := 0;}
|
||||
|
|
@ -567,54 +488,9 @@ begin
|
|||
begin
|
||||
if ucr.Parse(Response.MessageBodyAsString, 'bundle', CKeymanVersionInfo.Version) then
|
||||
begin
|
||||
SetLength(FParams.Packages,0);
|
||||
for i := Low(ucr.Packages) to High(ucr.Packages) do
|
||||
begin
|
||||
n := kmcom.Packages.IndexOf(ucr.Packages[i].ID);
|
||||
if n >= 0 then
|
||||
begin
|
||||
pkg := kmcom.Packages[n];
|
||||
j := Length(FParams.Packages);
|
||||
SetLength(FParams.Packages, j+1);
|
||||
FParams.Packages[j].NewID := ucr.Packages[i].NewID;
|
||||
FParams.Packages[j].ID := ucr.Packages[i].ID;
|
||||
FParams.Packages[j].Description := ucr.Packages[i].Name;
|
||||
FParams.Packages[j].OldVersion := pkg.Version;
|
||||
FParams.Packages[j].NewVersion := ucr.Packages[i].NewVersion;
|
||||
FParams.Packages[j].DownloadSize := ucr.Packages[i].DownloadSize;
|
||||
FParams.Packages[j].DownloadURL := ucr.Packages[i].DownloadURL;
|
||||
FParams.Packages[j].FileName := ucr.Packages[i].FileName;
|
||||
pkg := nil;
|
||||
end
|
||||
else
|
||||
FErrorMessage := 'Unable to find package '+ucr.Packages[i].ID;
|
||||
end;
|
||||
|
||||
case ucr.Status of
|
||||
ucrsNoUpdate:
|
||||
begin
|
||||
FErrorMessage := ucr.ErrorMessage;
|
||||
end;
|
||||
ucrsUpdateReady:
|
||||
begin
|
||||
FParams.Keyman.OldVersion := ucr.CurrentVersion;
|
||||
FParams.Keyman.NewVersion := ucr.NewVersion;
|
||||
FParams.Keyman.DownloadURL := ucr.InstallURL;
|
||||
FParams.Keyman.DownloadSize := ucr.InstallSize;
|
||||
FParams.Keyman.FileName := ucr.FileName;
|
||||
end;
|
||||
end;
|
||||
|
||||
if (Length(FParams.Packages) > 0) or (FParams.Keyman.DownloadURL <> '') then
|
||||
begin
|
||||
if not FSilent then
|
||||
ShowUpdateForm
|
||||
else
|
||||
begin
|
||||
ShowUpdateIcon;
|
||||
end;
|
||||
Result := FParams.Result;
|
||||
end;
|
||||
ResponseToParams(ucr);
|
||||
TUpdateCheckStorage.SaveUpdateCacheData(ucr);
|
||||
Result := FParams.Result;
|
||||
end
|
||||
else
|
||||
begin
|
||||
|
|
@ -651,6 +527,52 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function TOnlineUpdateCheck.ResponseToParams(const ucr: TUpdateCheckResponse): TOnlineUpdateCheckParams;
|
||||
var
|
||||
i, j, n: Integer;
|
||||
pkg: IKeymanPackage;
|
||||
begin
|
||||
SetLength(FParams.Packages,0);
|
||||
for i := Low(ucr.Packages) to High(ucr.Packages) do
|
||||
begin
|
||||
n := kmcom.Packages.IndexOf(ucr.Packages[i].ID);
|
||||
if n >= 0 then
|
||||
begin
|
||||
pkg := kmcom.Packages[n];
|
||||
j := Length(FParams.Packages);
|
||||
SetLength(FParams.Packages, j+1);
|
||||
FParams.Packages[j].NewID := ucr.Packages[i].NewID;
|
||||
FParams.Packages[j].ID := ucr.Packages[i].ID;
|
||||
FParams.Packages[j].Description := ucr.Packages[i].Name;
|
||||
FParams.Packages[j].OldVersion := pkg.Version;
|
||||
FParams.Packages[j].NewVersion := ucr.Packages[i].NewVersion;
|
||||
FParams.Packages[j].DownloadSize := ucr.Packages[i].DownloadSize;
|
||||
FParams.Packages[j].DownloadURL := ucr.Packages[i].DownloadURL;
|
||||
FParams.Packages[j].FileName := ucr.Packages[i].FileName;
|
||||
pkg := nil;
|
||||
end
|
||||
else
|
||||
FErrorMessage := 'Unable to find package '+ucr.Packages[i].ID;
|
||||
end;
|
||||
|
||||
case ucr.Status of
|
||||
ucrsNoUpdate:
|
||||
begin
|
||||
FErrorMessage := ucr.ErrorMessage;
|
||||
end;
|
||||
ucrsUpdateReady:
|
||||
begin
|
||||
FParams.Keyman.OldVersion := ucr.CurrentVersion;
|
||||
FParams.Keyman.NewVersion := ucr.NewVersion;
|
||||
FParams.Keyman.DownloadURL := ucr.InstallURL;
|
||||
FParams.Keyman.DownloadSize := ucr.InstallSize;
|
||||
FParams.Keyman.FileName := ucr.FileName;
|
||||
end;
|
||||
end;
|
||||
|
||||
Result := FParams;
|
||||
end;
|
||||
|
||||
procedure OnlineUpdateAdmin(OwnerForm: TCustomForm; Path: string);
|
||||
var
|
||||
Package: TOnlineUpdateCheckParamsPackage;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
(*
|
||||
Name: UImportOlderVersionSettings
|
||||
Copyright: Copyright (C) 2003-2017 SIL International.
|
||||
Documentation:
|
||||
Description:
|
||||
Documentation:
|
||||
Description:
|
||||
Create Date: 22 Feb 2011
|
||||
|
||||
Modified Date: 3 Jun 2014
|
||||
Authors: mcdurdin
|
||||
Related Files:
|
||||
Dependencies:
|
||||
Related Files:
|
||||
Dependencies:
|
||||
|
||||
Bugs:
|
||||
Todo:
|
||||
Notes:
|
||||
Bugs:
|
||||
Todo:
|
||||
Notes:
|
||||
History: 22 Feb 2011 - mcdurdin - I2651 - Install does not set desired default options
|
||||
22 Feb 2011 - mcdurdin - I2753 - Firstrun crashes because start with windows and auto update check options are set in Engine instead of Desktop
|
||||
03 May 2011 - mcdurdin - I2890 - Record diagnostic data when encountering registry errors
|
||||
|
|
@ -24,7 +24,7 @@ unit UImportOlderVersionSettings;
|
|||
|
||||
interface
|
||||
|
||||
function FirstRunInstallDefaults(DoDefaults,DoStartWithWindows,DoCheckForUpdates: Boolean; FDisablePackages, FDefaultUILanguage: string; DoAutomaticallyReportUsage: Boolean): Boolean; // I2753
|
||||
function FirstRunInstallDefaults(DoDefaults,DoStartWithWindows,DoCheckForUpdates,DoAutomaticUpdates: Boolean; FDisablePackages, FDefaultUILanguage: string; DoAutomaticallyReportUsage: Boolean): Boolean; // I2753
|
||||
|
||||
implementation
|
||||
|
||||
|
|
@ -41,14 +41,24 @@ uses
|
|||
keymanapi_TLB,
|
||||
ErrorControlledRegistry,
|
||||
RegistryKeys,
|
||||
Keyman.System.UpdateStateMachine,
|
||||
UImportOlderKeyboardUtils;
|
||||
|
||||
function FirstRunInstallDefaults(DoDefaults,DoStartWithWindows,DoCheckForUpdates: Boolean; FDisablePackages, FDefaultUILanguage: string; DoAutomaticallyReportUsage: Boolean): Boolean; // I2753
|
||||
function FirstRunInstallDefaults(DoDefaults,DoStartWithWindows,DoCheckForUpdates,DoAutomaticUpdates: Boolean; FDisablePackages, FDefaultUILanguage: string; DoAutomaticallyReportUsage: Boolean): Boolean; // I2753
|
||||
var
|
||||
n, I: Integer;
|
||||
v: Integer;
|
||||
p: string;
|
||||
UpdateSM : TUpdateStateMachine;
|
||||
begin
|
||||
// send event to statemachine (should result in setting state to idle)
|
||||
UpdateSM := TUpdateStateMachine.Create(False);
|
||||
try
|
||||
UpdateSM.HandleFirstRun;
|
||||
finally
|
||||
UpdateSM.Free;
|
||||
end;
|
||||
|
||||
{ Copy over all the user settings and set defaults for version 8.0: http://blog.tavultesoft.com/2011/02/keyman-desktop-80-default-options.html }
|
||||
|
||||
if DoDefaults then // I2753
|
||||
|
|
@ -136,6 +146,7 @@ begin
|
|||
|
||||
if DoStartWithWindows then kmcom.Options['koStartWithWindows'].Value := True; // I2753
|
||||
if DoCheckForUpdates then kmcom.Options['koCheckForUpdates'].Value := True; // I2753
|
||||
if DoAutomaticUpdates then kmcom.Options['koAutomaticUpdate'].Value := True;
|
||||
if DoAutomaticallyReportUsage then kmcom.Options['koAutomaticallyReportUsage'].Value := True;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ uses
|
|||
Winapi.Windows,
|
||||
|
||||
keymanapi_TLB,
|
||||
Sentry.Client,
|
||||
XMLRenderer,
|
||||
KeyboardListXMLRenderer,
|
||||
UfrmKeymanBase,
|
||||
|
|
@ -141,13 +142,14 @@ type
|
|||
|
||||
procedure Support_Diagnostics;
|
||||
procedure Support_Online;
|
||||
procedure Support_UpdateCheck;
|
||||
procedure Support_ProxyConfig;
|
||||
procedure Support_ContactSupport(params: TStringList); // I4390
|
||||
|
||||
procedure OpenSite(params: TStringList);
|
||||
procedure DoApply;
|
||||
procedure DoRefresh;
|
||||
procedure Update_CheckNow;
|
||||
procedure Update_ApplyNow;
|
||||
|
||||
protected
|
||||
procedure FireCommand(const command: WideString; params: TStringList); override;
|
||||
|
|
@ -184,12 +186,15 @@ uses
|
|||
LanguagesXMLRenderer,
|
||||
MessageIdentifierConsts,
|
||||
MessageIdentifiers,
|
||||
OnlineUpdateCheck,
|
||||
Keyman.System.ExecutionHistory,
|
||||
Keyman.System.KeymanSentryClient,
|
||||
Keyman.System.RemoteUpdateCheck,
|
||||
OptionsXMLRenderer,
|
||||
Keyman.Configuration.System.UmodWebHttpServer,
|
||||
Keyman.Configuration.System.HttpServer.App.ConfigMain,
|
||||
Keyman.Configuration.UI.InstallFile,
|
||||
Keyman.Configuration.UI.UfrmSettingsManager,
|
||||
Keyman.Configuration.UI.UfrmStartInstallNow,
|
||||
RegistryKeys,
|
||||
SupportXMLRenderer,
|
||||
UfrmChangeHotkey,
|
||||
|
|
@ -202,12 +207,14 @@ uses
|
|||
UfrmTextEditor,
|
||||
uninstall,
|
||||
Upload_Settings,
|
||||
UpdateXMLRenderer,
|
||||
utildir,
|
||||
utilexecute,
|
||||
utilkmshell,
|
||||
utilhttp,
|
||||
utiluac,
|
||||
utilxml;
|
||||
utilxml,
|
||||
KeymanPaths;
|
||||
|
||||
type
|
||||
PHKL = ^HKL;
|
||||
|
|
@ -301,6 +308,7 @@ begin
|
|||
FXMLRenderers.Add(TOptionsXMLRenderer.Create(FXMLRenderers));
|
||||
FXMLRenderers.Add(TLanguagesXMLRenderer.Create(FXMLRenderers));
|
||||
FXMLRenderers.Add(TSupportXMLRenderer.Create(FXMLRenderers));
|
||||
FXMLRenderers.Add(TUpdateXMLRenderer.Create(FXMLRenderers));
|
||||
|
||||
xml := FXMLRenderers.RenderToString(s);
|
||||
sharedData.Init(
|
||||
|
|
@ -342,9 +350,11 @@ begin
|
|||
|
||||
else if command = 'support_diagnostics' then Support_Diagnostics
|
||||
else if command = 'support_online' then Support_Online
|
||||
else if command = 'support_updatecheck' then Support_UpdateCheck
|
||||
else if command = 'support_proxyconfig' then Support_ProxyConfig
|
||||
|
||||
else if command = 'update_checknow' then Update_CheckNow
|
||||
else if command = 'update_applynow' then Update_ApplyNow
|
||||
|
||||
else if command = 'contact_support' then Support_ContactSupport(params) // I4390
|
||||
|
||||
else if command = 'opensite' then OpenSite(params)
|
||||
|
|
@ -789,29 +799,49 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmMain.Support_UpdateCheck;
|
||||
procedure TfrmMain.Update_CheckNow;
|
||||
// TODO: epic-windows-update
|
||||
// Get an instance to the state machine and call handle check so the state can change to update
|
||||
// available.
|
||||
var UpdateCheck : TRemoteUpdateCheck;
|
||||
begin
|
||||
with TOnlineUpdateCheck.Create(Self, True, False) do
|
||||
UpdateCheck := TRemoteUpdateCheck.Create(True);
|
||||
try
|
||||
case Run of
|
||||
oucShutDown:
|
||||
begin
|
||||
try
|
||||
if kmcom.Control.IsKeymanRunning then
|
||||
try
|
||||
kmcom.Control.StopKeyman;
|
||||
except
|
||||
on E:Exception do KL.Log(E.Message);
|
||||
end;
|
||||
except
|
||||
on E:Exception do KL.Log(E.Message);
|
||||
end;
|
||||
end;
|
||||
oucSuccess:
|
||||
DoRefresh;
|
||||
end
|
||||
UpdateCheck.Run;
|
||||
finally
|
||||
Free;
|
||||
UpdateCheck.Free;
|
||||
end;
|
||||
DoRefresh;
|
||||
end;
|
||||
|
||||
procedure TfrmMain.Update_ApplyNow;
|
||||
var
|
||||
ShellPath : string;
|
||||
FResult, InstallNow: Boolean;
|
||||
frmStartInstallNow: TfrmStartInstallNow;
|
||||
begin
|
||||
InstallNow := True;
|
||||
// Confirm User is ok that this will require a reset
|
||||
if HasKeymanRun then
|
||||
begin
|
||||
frmStartInstallNow := TfrmStartInstallNow.Create(nil);
|
||||
try
|
||||
if frmStartInstallNow.ShowModal = mrOk then
|
||||
InstallNow := True
|
||||
else
|
||||
InstallNow := False;
|
||||
finally
|
||||
frmStartInstallNow.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
if InstallNow = True then
|
||||
begin
|
||||
ShellPath := TKeymanPaths.KeymanDesktopInstallPath(TKeymanPaths.S_KMShell);
|
||||
FResult := TUtilExecute.Shell(0, ShellPath, '', '-an');
|
||||
if not FResult then
|
||||
TKeymanSentryClient.Client.MessageEvent(Sentry.Client.SENTRY_LEVEL_ERROR,
|
||||
'TrmfMain: Shell Execute Update_ApplyNow Failed');
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
|
|||
|
|
@ -80,8 +80,12 @@ type
|
|||
fmUninstallPackage, fmRegistryAdd, fmRegistryRemove,
|
||||
fmMain, fmHelp, fmHelpKMShell,
|
||||
fmMigrate, fmSplash, fmStart,
|
||||
fmUpgradeKeyboards, fmOnlineUpdateCheck,// I2548
|
||||
fmOnlineUpdateAdmin, fmTextEditor,
|
||||
fmUpgradeKeyboards, // I2548
|
||||
fmTextEditor,
|
||||
fmInstallKeyboardPackageAdmin,
|
||||
fmBackgroundUpdateCheck,
|
||||
fmBackgroundDownload,
|
||||
fmApplyInstallNow,
|
||||
fmFirstRun, // I2562
|
||||
fmKeyboardWelcome, // I2569
|
||||
fmKeyboardPrint, // I2329
|
||||
|
|
@ -113,13 +117,14 @@ uses
|
|||
Keyman.Configuration.System.TIPMaintenance,
|
||||
Keyman.Configuration.System.UImportOlderVersionKeyboards11To13,
|
||||
Keyman.Configuration.UI.UfrmSettingsManager,
|
||||
Keyman.Configuration.UI.UfrmStartInstall,
|
||||
Keyman.System.KeymanStartTask,
|
||||
KeymanPaths,
|
||||
KLog,
|
||||
kmint,
|
||||
KMShellHints,
|
||||
KeymanMutex,
|
||||
OnlineUpdateCheck,
|
||||
Keyman.System.RemoteUpdateCheck,
|
||||
RegistryKeys,
|
||||
UfrmBaseKeyboard,
|
||||
UfrmKeymanBase,
|
||||
|
|
@ -141,6 +146,7 @@ uses
|
|||
UpgradeMnemonicLayout,
|
||||
utilfocusappwnd,
|
||||
utilkmshell,
|
||||
Keyman.System.UpdateStateMachine,
|
||||
|
||||
KeyboardTIPCheck,
|
||||
|
||||
|
|
@ -240,7 +246,7 @@ begin
|
|||
else if s = '-uk' then FMode := fmUninstallKeyboard { I1201 - Fix crash uninstalling admin-installed keyboards and packages }
|
||||
else if s = '-ukl' then FMode := fmUninstallKeyboardLanguage // I3624
|
||||
else if s = '-up' then FMode := fmUninstallPackage { I1201 - Fix crash uninstalling admin-installed keyboards and packages }
|
||||
else if s = '-ou' then FMode := fmOnlineUpdateAdmin { I1730 - Check update of keyboards (admin elevation) }
|
||||
else if s = '-ikp' then FMode := fmInstallKeyboardPackageAdmin
|
||||
else if s = '-a' then FMode := fmAbout
|
||||
else if s = '-ra' then FMode := fmRegistryAdd
|
||||
else if s = '-rr' then FMode := fmRegistryRemove
|
||||
|
|
@ -248,7 +254,9 @@ begin
|
|||
else if s = '-?' then FMode := fmHelpKMShell
|
||||
else if s = '-h' then FMode := fmHelp
|
||||
else if s = '-t' then FMode := fmTextEditor
|
||||
else if s = '-ouc' then FMode := fmOnlineUpdateCheck
|
||||
else if s = '-buc' then FMode := fmBackgroundUpdateCheck
|
||||
else if s = '-bd' then FMode := fmBackgroundDownload
|
||||
else if s = '-an' then FMode := fmApplyInstallNow
|
||||
else if s = '-basekeyboard' then FMode := fmBaseKeyboard // I4169
|
||||
else if s = '-nowelcome' then FNoWelcome := True
|
||||
else if s = '-kw' then FMode := fmKeyboardWelcome // I2569
|
||||
|
|
@ -381,6 +389,9 @@ var
|
|||
kdl: IKeymanDefaultLanguage;
|
||||
FIcon: string;
|
||||
FMutex: TKeymanMutex; // I2720
|
||||
BUpdateSM : TUpdateStateMachine;
|
||||
frmStartInstall: TfrmStartInstall;
|
||||
UserCanceled : Boolean;
|
||||
function FirstKeyboardFileName: WideString;
|
||||
begin
|
||||
if KeyboardFileNames.Count = 0
|
||||
|
|
@ -428,6 +439,55 @@ begin
|
|||
Exit;
|
||||
end;
|
||||
|
||||
BUpdateSM := TUpdateStateMachine.Create(False);
|
||||
try
|
||||
if (FMode = fmBackgroundUpdateCheck) then
|
||||
begin
|
||||
BUpdateSM.HandleCheck;
|
||||
Exit;
|
||||
end
|
||||
else if (FMode = fmBackgroundDownload) then
|
||||
begin
|
||||
BUpdateSM.HandleDownload;
|
||||
Exit;
|
||||
end
|
||||
else if (FMode = fmApplyInstallNow) then
|
||||
begin
|
||||
BUpdateSM.HandleInstallNow;
|
||||
Exit;
|
||||
end
|
||||
else if (FMode = fmInstallKeyboardPackageAdmin) then
|
||||
begin
|
||||
BUpdateSM.HandleInstallPackages;
|
||||
Exit;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// The following logic around the WaitingRestartState should be
|
||||
// encapsulated in the state machine however as we want separation of
|
||||
// UI elements from the state machine we have bring some of logic here.
|
||||
UserCanceled := False;
|
||||
if BUpdateSM.ReadyToInstall and
|
||||
(not FSilent and (FMode in [fmStart, fmSplash, fmMain, fmAbout])) then
|
||||
begin
|
||||
frmStartInstall := TfrmStartInstall.Create(nil);
|
||||
try
|
||||
if frmStartInstall.ShowModal = mrOk then
|
||||
UserCanceled := False
|
||||
else
|
||||
UserCanceled := True
|
||||
finally
|
||||
frmStartInstall.Free;
|
||||
end;
|
||||
end;
|
||||
if not UserCanceled and (BUpdateSM.HandleKmShell = 1) then
|
||||
Exit;
|
||||
end;
|
||||
finally
|
||||
BUpdateSM.Free;
|
||||
end;
|
||||
|
||||
|
||||
if not FSilent or (FMode = fmUpgradeMnemonicLayout) then // I4553
|
||||
begin
|
||||
// Note: will elevate and re-run if required
|
||||
|
|
@ -469,17 +529,6 @@ begin
|
|||
then ExitCode := 0
|
||||
else ExitCode := 2;
|
||||
|
||||
fmOnlineUpdateAdmin:
|
||||
OnlineUpdateAdmin(nil, FirstKeyboardFileName);
|
||||
|
||||
fmOnlineUpdateCheck:
|
||||
with TOnlineUpdateCheck.Create(nil, FForce, FSilent) do
|
||||
try
|
||||
Run;
|
||||
finally
|
||||
Free;
|
||||
end;
|
||||
|
||||
fmUpgradeKeyboards:// I2548
|
||||
begin
|
||||
if FQuery='13,backup' then
|
||||
|
|
@ -619,6 +668,7 @@ begin
|
|||
Pos('installdefaults', FQuery) > 0,
|
||||
Pos('startwithwindows', FQuery) > 0,
|
||||
Pos('checkforupdates', FQuery) > 0,
|
||||
Pos('automaticupdates', FQuery) > 0,
|
||||
FDisablePackages,
|
||||
FDefaultUILanguage,
|
||||
Pos('automaticallyreportusage', FQuery) > 0); // I2651, I2753
|
||||
|
|
|
|||
94
windows/src/desktop/kmshell/render/UpdateXMLRenderer.pas
Normal file
94
windows/src/desktop/kmshell/render/UpdateXMLRenderer.pas
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
(*
|
||||
Name: UpdateXMLRenderer
|
||||
Copyright: Copyright (C) SIL International.
|
||||
*)
|
||||
unit UpdateXMLRenderer;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
XMLRenderer,
|
||||
Windows;
|
||||
|
||||
type
|
||||
TUpdateXMLRenderer = class(TXMLRenderer)
|
||||
protected
|
||||
function XMLData: WideString; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
StrUtils,
|
||||
SysUtils,
|
||||
VersionInfo,
|
||||
kmint,
|
||||
KeymanVersion,
|
||||
keymanapi_TLB,
|
||||
Keyman.System.LocaleStrings,
|
||||
Keyman.System.UpdateCheckResponse,
|
||||
Keyman.System.UpdateCheckStorage,
|
||||
MessageIdentifierConsts,
|
||||
MessageIdentifiers,
|
||||
utilxml;
|
||||
|
||||
{ TUpdateXMLRenderer }
|
||||
|
||||
function TUpdateXMLRenderer.XMLData: WideString;
|
||||
var
|
||||
xml: string;
|
||||
ucr: TUpdateCheckResponse;
|
||||
i, n : Integer;
|
||||
pkg: IKeymanPackage;
|
||||
begin
|
||||
xml := '';
|
||||
|
||||
if TUpdateCheckStorage.LoadUpdateCacheData(ucr) then
|
||||
begin
|
||||
if (ucr.InstallURL <> '') then
|
||||
begin
|
||||
xml := xml +
|
||||
'<Update>'+
|
||||
'<index>0</index>'+
|
||||
IfThen(not kmcom.SystemInfo.IsAdministrator, '<RequiresAdmin />')+
|
||||
'<Keyman>'+
|
||||
'<Text>'+xmlencode(TLocaleStrings.MsgFromIdFormat(kmcom, SKUpdate_KeymanText, [ucr.NewVersion]))+'</Text>'+
|
||||
'<NewVersion>'+xmlencode(ucr.NewVersion)+'</NewVersion>'+
|
||||
'<OldVersion>'+xmlencode(ucr.CurrentVersion)+'</OldVersion>'+
|
||||
'<DownloadSize>'+xmlencode(Format('%d', [ucr.InstallSize div 1024]))+'KB</DownloadSize>'+
|
||||
'<DownloadURL>'+xmlencode(ucr.InstallURL)+'</DownloadURL>'+
|
||||
'</Keyman>'+
|
||||
'</Update>';
|
||||
end;
|
||||
|
||||
for i := 0 to High(ucr.Packages) do
|
||||
begin
|
||||
n := kmcom.Packages.IndexOf(ucr.Packages[i].ID);
|
||||
if n >= 0 then
|
||||
begin
|
||||
pkg := kmcom.Packages[n];
|
||||
|
||||
xml := xml +
|
||||
'<Update>'+
|
||||
'<index>'+IntToStr(i+1)+'</index>'+
|
||||
IfThen(not kmcom.SystemInfo.IsAdministrator, '<RequiresAdmin />')+
|
||||
'<Package>'+
|
||||
'<Text>'+xmlencode(TLocaleStrings.MsgFromIdFormat(kmcom, SKUpdate_PackageText,
|
||||
[ucr.Packages[i].Name, ucr.Packages[i].NewVersion]))+'</Text>'+
|
||||
'<NewVersion>'+xmlencode(ucr.Packages[i].NewVersion)+'</NewVersion>'+
|
||||
'<OldVersion>'+xmlencode(pkg.version)+'</OldVersion>'+
|
||||
'<DownloadSize>'+xmlencode(Format('%d', [ucr.Packages[i].DownloadSize div 1024]))+'KB</DownloadSize>'+
|
||||
'<DownloadURL>'+xmlencode(ucr.Packages[i].DownloadURL)+'</DownloadURL>'+
|
||||
'</Package>'+
|
||||
'</Update>';
|
||||
pkg := nil;
|
||||
end;
|
||||
// else Package not found, skip
|
||||
end;
|
||||
end;
|
||||
|
||||
Result := '<Updates>'+xml+'</Updates>';
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
|
@ -90,7 +90,6 @@ uses
|
|||
MessageIdentifierConsts,
|
||||
MessageIdentifiers,
|
||||
KeymanMutex,
|
||||
OnlineUpdateCheck,
|
||||
PngImage,
|
||||
ErrorControlledRegistry,
|
||||
RegistryKeys,
|
||||
|
|
@ -268,8 +267,7 @@ begin
|
|||
|
||||
if kmcom.Options[KeymanOptionName(TUtilKeymanOption.koCheckForUpdates)].Value then
|
||||
begin
|
||||
if not kmcom.Control.IsOnlineUpdateCheckOpen then
|
||||
RunConfiguration(0, '-ouc -s');
|
||||
RunConfiguration(0, '-buc -s');
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
(*
|
||||
Name: UfrmDownloadProgress
|
||||
Copyright: Copyright (C) SIL International.
|
||||
Documentation:
|
||||
Description:
|
||||
Documentation:
|
||||
Description:
|
||||
Create Date: 4 Dec 2006
|
||||
|
||||
Modified Date: 18 May 2012
|
||||
Authors: mcdurdin
|
||||
Related Files:
|
||||
Dependencies:
|
||||
Related Files:
|
||||
Dependencies:
|
||||
|
||||
Bugs:
|
||||
Todo:
|
||||
Notes:
|
||||
Bugs:
|
||||
Todo:
|
||||
Notes:
|
||||
History: 04 Dec 2006 - mcdurdin - Initial version
|
||||
05 Dec 2006 - mcdurdin - Localize caption
|
||||
15 Jan 2007 - mcdurdin - Use font from locale.xml
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ unit utilkmshell; // I3306 // I4181
|
|||
interface
|
||||
|
||||
uses
|
||||
System.UITypes,
|
||||
System.UITypes, System.IOUtils, System.Types,
|
||||
Dialogs, Windows, ComObj, shlobj, controls, sysutils, classes;
|
||||
|
||||
const
|
||||
|
|
@ -96,6 +96,7 @@ procedure SplitString(const instr: string; var outstr1, outstr2: string; const s
|
|||
function ValidDirectory(const dir: string): string;
|
||||
|
||||
function GetLongFile(APath:String):String;
|
||||
procedure GetFileNamesInDirectory(const directoryPath: string; var fileNames: TStringDynArray);
|
||||
|
||||
function TSFInstalled: Boolean;
|
||||
|
||||
|
|
@ -540,6 +541,19 @@ begin
|
|||
until Length(APath)=0;
|
||||
end; {Peter Haas}
|
||||
|
||||
procedure GetFileNamesInDirectory(const directoryPath: string; var fileNames: TStringDynArray);
|
||||
|
||||
begin
|
||||
// Check if the directory exists
|
||||
if TDirectory.Exists(directoryPath) then
|
||||
begin
|
||||
// Retrieve file names within the directory
|
||||
fileNames := TDirectory.GetFiles(directoryPath);
|
||||
end
|
||||
else
|
||||
KL.Log('Directory does not exist.');
|
||||
end;
|
||||
|
||||
{ TString }
|
||||
|
||||
constructor TString.Create(const AString: string);
|
||||
|
|
|
|||
|
|
@ -499,6 +499,20 @@ table tr
|
|||
padding: 1px 0 1px 10px;
|
||||
}
|
||||
|
||||
.grid_container_update {
|
||||
display: grid;
|
||||
position: relative;
|
||||
grid-template-columns: 50px 1fr 1fr 1fr;
|
||||
margin: 10px 50px 10px 64px;
|
||||
/* From https://geary.co/internal-borders-css-grid/ */
|
||||
overflow: hidden;
|
||||
gap: var(--gap);
|
||||
--gap: 2em;
|
||||
--line-offset: calc(var(--gap) / 2);
|
||||
--line-thickness: 1px;
|
||||
--line-color: black;
|
||||
}
|
||||
|
||||
.grid_container.grid_disabled
|
||||
{
|
||||
opacity: 0.5;
|
||||
|
|
@ -508,11 +522,36 @@ table tr
|
|||
{
|
||||
position: relative;
|
||||
font-size: 12px;
|
||||
margin: 0px;
|
||||
padding: 1px;
|
||||
margin: 0 0 0 5px;
|
||||
}
|
||||
|
||||
.grid_item::before,
|
||||
.grid_item::after
|
||||
{
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-color: var(--line-color);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* row borders */
|
||||
.grid_item::after
|
||||
{
|
||||
inline-size: 100vw;
|
||||
block-size: var(--line-thickness);
|
||||
inset-inline-start: 0;
|
||||
inset-block-start: calc(var(--line-offset) * -1);
|
||||
}
|
||||
|
||||
/* column borders */
|
||||
.grid_item::before
|
||||
{
|
||||
inline-size: var(--line-thickness);
|
||||
block-size: 100vh;
|
||||
inset-inline-start: calc(var(--line-offset) * -1);
|
||||
}
|
||||
|
||||
.grid_item_title{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
@ -1099,17 +1138,42 @@ th
|
|||
height: 16px;
|
||||
}
|
||||
|
||||
#keepintouch_content {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
.update_title
|
||||
{
|
||||
background: url('keyman-title.png') 96px 13px no-repeat;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
#keepintouch_frame {
|
||||
box-sizing: border-box;
|
||||
width:100%;
|
||||
height:100%;
|
||||
border:none;
|
||||
user-select: none;
|
||||
.update_title img
|
||||
{
|
||||
margin: 13px 0 0 10px;
|
||||
}
|
||||
|
||||
.update_edition
|
||||
{
|
||||
float: left;
|
||||
font-size: 16px;
|
||||
margin-left: 64px;
|
||||
}
|
||||
|
||||
#update_status
|
||||
{
|
||||
font-size: 13px;
|
||||
margin-left: 64px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
#update_content {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 5px 10px 5px 10px;
|
||||
}
|
||||
|
||||
.update_controls
|
||||
{
|
||||
margin-left: 64px;
|
||||
}
|
||||
|
||||
/* QRCodes */
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ function windowResize()
|
|||
e = _$('subcontent_pro');
|
||||
if(e) e.style.height = h;
|
||||
_$('subcontent_support').style.height = h;
|
||||
_$('subcontent_keepintouch').style.height = h;
|
||||
_$('subcontent_update').style.height = h;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
<xsl:include href="keyman_options.xsl"/>
|
||||
<xsl:include href="keyman_hotkeys.xsl"/>
|
||||
<xsl:include href="keyman_support.xsl"/>
|
||||
<xsl:include href="keyman_keepintouch.xsl"/>
|
||||
<xsl:include href="keyman_update.xsl"/>
|
||||
|
||||
<xsl:include href="keyman_footer.xsl"/>
|
||||
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<div class="contentpage" id="content_options"><xsl:call-template name="content_options" /></div>
|
||||
<div class="contentpage" id="content_hotkeys"><xsl:call-template name="content_hotkeys" /></div>
|
||||
<div class="contentpage" id="content_support"><xsl:call-template name="content_support" /></div>
|
||||
<div class="contentpage" id="content_keepintouch"><xsl:call-template name="content_keepintouch" /></div>
|
||||
<div class="contentpage" id="content_update"><xsl:call-template name="content_update" /></div>
|
||||
</div>
|
||||
<div id="footerframe">
|
||||
<xsl:call-template name="footerframe" />
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:template name="content_keepintouch">
|
||||
|
||||
<script>
|
||||
window['menuframe_activate_keepintouch'] = function() {
|
||||
document.getElementById('keepintouch_frame').src = '<xsl:value-of select='/Keyman/keyman-com' />/go/windows/<xsl:value-of select="/Keyman/version-info/@versionRelease" />/keep-in-touch?embed=1';
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="header">
|
||||
<xsl:call-template name="header_helplinks" />
|
||||
<xsl:value-of select="$locale/string[@name='S_KeepInTouch']"/>
|
||||
</div>
|
||||
|
||||
<div id="subcontent_keepintouch" class="content">
|
||||
<div id="keepintouch_content">
|
||||
<iframe id='keepintouch_frame'></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -9,20 +9,20 @@
|
|||
<xsl:variable name="locale_Options"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Options']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Hotkeys"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Hotkeys']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Support"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Support']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_KeepInTouch"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_KeepInTouch']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Update"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Update']" /></xsl:call-template></xsl:variable>
|
||||
|
||||
<xsl:variable name="locale_Keyboards_AccessChar"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Keyboards_AccessChar']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Options_AccessChar"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Options_AccessChar']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Hotkeys_AccessChar"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Hotkeys_AccessChar']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Support_AccessChar"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Support_AccessChar']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_KeepInTouch_AccessChar"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_KeepInTouch_AccessChar']" /></xsl:call-template></xsl:variable>
|
||||
<xsl:variable name="locale_Update_AccessChar"><xsl:call-template name="escape-apos"><xsl:with-param name="text" select="$locale/string[@name='S_Update_AccessChar']" /></xsl:call-template></xsl:variable>
|
||||
|
||||
<script type="text/javascript">
|
||||
menuframe_add('/app/', 'keyboardlist', '<xsl:value-of select="$locale_Keyboards"/>', '<xsl:value-of select="$locale_Keyboards_AccessChar"/>');
|
||||
menuframe_add('/app/', 'options', '<xsl:value-of select="$locale_Options"/>', '<xsl:value-of select="$locale_Options_AccessChar"/>');
|
||||
menuframe_add('/app/', 'hotkeys', '<xsl:value-of select="$locale_Hotkeys"/>', '<xsl:value-of select="$locale_Hotkeys_AccessChar"/>');
|
||||
menuframe_add('/app/', 'support', '<xsl:value-of select="$locale_Support"/>', '<xsl:value-of select="$locale_Support_AccessChar"/>');
|
||||
menuframe_add('/app/', 'keepintouch', '<xsl:value-of select="$locale_KeepInTouch"/>', '<xsl:value-of select="$locale_KeepInTouch_AccessChar"/>');
|
||||
menuframe_add('/app/', 'update', '<xsl:value-of select="$locale_Update"/>', '<xsl:value-of select="$locale_Update_AccessChar"/>');
|
||||
</script>
|
||||
<span class="menuframe" id="menuframe_footer"><xsl:text></xsl:text></span>
|
||||
</xsl:template>
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@
|
|||
<ul>
|
||||
<li><a><xsl:attribute name="href">keyman:link?url=<xsl:value-of select="/Keyman/keyman-com"/>/</xsl:attribute>keyman.com</a></li>
|
||||
<li><a href="keyman:support_diagnostics"><xsl:value-of select="$locale/string[@name='S_Menu_Diagnostics_Diagnostics']"/></a></li>
|
||||
<li><a href="keyman:support_updatecheck"><xsl:value-of select="$locale/string[@name='S_Button_CheckForUpdates']"/></a></li>
|
||||
<li><a>
|
||||
<xsl:attribute name="href">keyman:link?url=<xsl:value-of select="/Keyman/keyman-com" />/go/<xsl:value-of select="/Keyman/version-info/@versionRelease" />/support</xsl:attribute
|
||||
><xsl:value-of select="$locale/string[@name='S_Button_OnlineSupport']"/></a></li>
|
||||
|
|
|
|||
136
windows/src/desktop/kmshell/xml/keyman_update.xsl
Normal file
136
windows/src/desktop/kmshell/xml/keyman_update.xsl
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:template name="content_update">
|
||||
<xsl:variable name="isNewKeymanVersionAvailable" select="boolean(/Keyman/Updates/Update/Keyman/NewVersion)"/>
|
||||
<xsl:variable name="isNewKeyboardVersionAvailable" select="boolean(/Keyman/Updates/Update/Package/NewVersion)"/>
|
||||
|
||||
<div class="header">
|
||||
<xsl:call-template name="header_helplinks" />
|
||||
<xsl:value-of select="$locale/string[@name='S_Update']"/>
|
||||
</div>
|
||||
|
||||
<div id="subcontent_update" class="content">
|
||||
<div id="update_content">
|
||||
|
||||
<div class="update_title">
|
||||
<img src="/app/keyman-desktop.png" />
|
||||
</div>
|
||||
|
||||
<div class="update_edition">
|
||||
<xsl:value-of select="$locale/string[@name='S_Support_Version']"/> <xsl:value-of select="/Keyman/version-info/@versionWithTag" />
|
||||
</div>
|
||||
|
||||
<div id="update_status">
|
||||
<xsl:if test="$isNewKeymanVersionAvailable or $isNewKeyboardVersionAvailable">
|
||||
Updates are available which will be applied when Windows is next restarted:
|
||||
</xsl:if>
|
||||
<xsl:if test="not($isNewKeymanVersionAvailable or $isNewKeyboardVersionAvailable)">
|
||||
No updates are available.
|
||||
</xsl:if>
|
||||
</div>
|
||||
|
||||
<div class="grid_container_update" id="update_details">
|
||||
<div class='grid_item'>Select</div>
|
||||
<div class='grid_item'><xsl:value-of select="$locale/string[@name='S_Update_ComponentHead']"/></div>
|
||||
<div class='grid_item'><xsl:value-of select="$locale/string[@name='S_Update_OldVersionHead']"/></div>
|
||||
<div class='grid_item'><xsl:value-of select="$locale/string[@name='S_Update_SizeHead']"/></div>
|
||||
|
||||
<xsl:apply-templates select="/Keyman/Updates/Update" />
|
||||
|
||||
</div>
|
||||
|
||||
<div class="update_controls" id="update_controls">
|
||||
|
||||
<xsl:choose>
|
||||
<xsl:when test="$isNewKeymanVersionAvailable or $isNewKeyboardVersionAvailable">
|
||||
<xsl:call-template name="button">
|
||||
<xsl:with-param name="caption"><xsl:value-of select="$locale/string[@name='S_Button_Update_ApplyNow']"/></xsl:with-param>
|
||||
<xsl:with-param name="command">keyman:update_applynow</xsl:with-param>
|
||||
<xsl:with-param name="width">220px</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:call-template name="button">
|
||||
<xsl:with-param name="caption"><xsl:value-of select="$locale/string[@name='S_Button_Update_ApplyNow']"/></xsl:with-param>
|
||||
<xsl:with-param name="command"></xsl:with-param>
|
||||
<xsl:with-param name="width">220px</xsl:with-param>
|
||||
<xsl:with-param name="disabled">1</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
|
||||
<xsl:call-template name="button">
|
||||
<xsl:with-param name="caption"><xsl:value-of select="$locale/string[@name='S_Button_Update_CheckNow']"/></xsl:with-param>
|
||||
<xsl:with-param name="command">keyman:update_checknow</xsl:with-param>
|
||||
<xsl:with-param name="width">220px</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</div>
|
||||
|
||||
<!-- <li><a href="keyman:support_updatecheck"><xsl:value-of select="$locale/string[@name='S_Button_CheckForUpdates']"/></a></li> -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="/Keyman/Updates/Update">
|
||||
|
||||
<div class="UpdateCheckBox grid_item">
|
||||
<input type="checkbox">
|
||||
<xsl:attribute name="onclick">javascript:updateTick("<xsl:value-of select="index" />");</xsl:attribute>
|
||||
<xsl:attribute name="id">Update_<xsl:value-of select="index" /></xsl:attribute>
|
||||
<xsl:if test="not(@DefaultUnchecked)"><xsl:attribute name="checked">checked</xsl:attribute></xsl:if>
|
||||
<xsl:attribute name="name">Update_<xsl:value-of select="index" /></xsl:attribute>
|
||||
</input>
|
||||
<xsl:if test="RequiresAdmin">
|
||||
<span><xsl:attribute name="id">Update_<xsl:value-of select="index" />_RequiresAdmin</xsl:attribute></span>
|
||||
</xsl:if>
|
||||
</div>
|
||||
<xsl:choose>
|
||||
<xsl:when test="Package/Text != ''">
|
||||
<div class='grid_item'>
|
||||
<label>
|
||||
<xsl:attribute name="for">Update_<xsl:value-of select="index"/></xsl:attribute>
|
||||
<xsl:value-of select="Package/Text"/>
|
||||
</label>
|
||||
</div>
|
||||
<div class='grid_item'>
|
||||
<xsl:value-of select="Package/OldVersion"/>
|
||||
</div>
|
||||
<div class='grid_item'>
|
||||
<xsl:value-of select="Package/DownloadSize"/>
|
||||
</div>
|
||||
</xsl:when>
|
||||
<xsl:when test="Keyman/DownloadURL != ''">
|
||||
<div class='grid_item'>
|
||||
<label>
|
||||
<xsl:attribute name="for">Update_<xsl:value-of select="index"/></xsl:attribute>
|
||||
<xsl:value-of select="Keyman/Text"/>
|
||||
</label>
|
||||
</div>
|
||||
<div class='grid_item'>
|
||||
<xsl:value-of select="Keyman/OldVersion"/>
|
||||
</div>
|
||||
<div class='grid_item'>
|
||||
<xsl:value-of select="Keyman/DownloadSize"/>
|
||||
</div>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<div class='grid_item'>
|
||||
<div id="DownloadFrom">
|
||||
<xsl:value-of select="$locale/string[@name='S_Update_DownloadFrom']"/>
|
||||
</div>
|
||||
<div id="URL">
|
||||
<a href="keyman:openwebsite">
|
||||
<xsl:value-of select="/Keyman/DownloadURL"/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class='grid_item'>
|
||||
<xsl:value-of select="Keyman/DownloadVersion"/>
|
||||
</div>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
BIN
windows/src/desktop/kmshell/xml/menuframe_update.png
Normal file
BIN
windows/src/desktop/kmshell/xml/menuframe_update.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -417,6 +417,11 @@
|
|||
<!-- Introduced: 7.0.230.0 -->
|
||||
<string name="koShowWelcome" comment="Startup options - show/hide welcome screen">Show welcome screen</string>
|
||||
|
||||
<!-- Context: Configuration Dialog - Options tab -->
|
||||
<!-- String Type: FormatString -->
|
||||
<!-- Introduced: 18.0.96.0 -->
|
||||
<string name="koAutomaticUpdate" comment="Automatically check for updates and download">Automatically check for updates and download</string>
|
||||
|
||||
<!-- Context: Configuration Dialog - Options tab -->
|
||||
<!-- String Type: FormatString -->
|
||||
<!-- Introduced: 7.0.230.0 -->
|
||||
|
|
@ -586,8 +591,6 @@
|
|||
<!-- Introduced: 7.0.230.0 -->
|
||||
<string name="S_Menu_Diagnostics_Diagnostics" comment="Support button submenu - performs a diagnostic report">Diagnostics</string>
|
||||
|
||||
|
||||
|
||||
<!-- Context: Download Keyboard Dialog -->
|
||||
<!-- String Type: PlainText -->
|
||||
<!-- Introduced: 7.0.230.0 -->
|
||||
|
|
@ -712,6 +715,10 @@ keyboard that you use in Windows. Keyman keyboards will adapt automatically to
|
|||
|
||||
|
||||
|
||||
<!-- Context: Online Update Dialog -->
|
||||
<!-- String Type: PlainText -->
|
||||
<!-- Introduced: 18.0.230.0 -->
|
||||
<string name="S_Update" comment="Update tab name">Update</string>
|
||||
|
||||
<!-- Context: Online Update Dialog -->
|
||||
<!-- String Type: PlainText -->
|
||||
|
|
@ -803,6 +810,16 @@ keyboard that you use in Windows. Keyman keyboards will adapt automatically to
|
|||
|
||||
|
||||
|
||||
<!-- Context: Update Dialog -->
|
||||
<!-- String Type: FormatString -->
|
||||
<!-- Introduced: 17.0233.0 -->
|
||||
<string name="S_Button_Update_ApplyNow" comment="Apply update now button - update dialog">Apply update now</string>
|
||||
|
||||
<!-- Context: Update Dialog -->
|
||||
<!-- String Type: FormatString -->
|
||||
<!-- Introduced: 17.0233.0 -->
|
||||
<string name="S_Button_Update_CheckNow" comment="Check for updates now button - update dialog">Check for new updates</string>
|
||||
|
||||
|
||||
<!-- Context: Splash Dialog -->
|
||||
<!-- String Type: PlainText -->
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ type
|
|||
InstallSuccess: Boolean);
|
||||
function InstallMSI(msiLocation: TInstallInfoFileLocation; var InstallDefaults: Boolean; ContinueSetup: Boolean): Boolean;
|
||||
procedure ConfigFirstRun(StartKeyman,StartWithWindows,
|
||||
CheckForUpdates,StartDisabled,StartWithConfiguration,InstallDefaults,
|
||||
CheckForUpdates,AutomaticUpdates,StartDisabled,StartWithConfiguration,InstallDefaults,
|
||||
AutomaticallyReportUsage: Boolean);
|
||||
procedure PrepareForReboot(res: Cardinal; InstallDefaults: Boolean);
|
||||
function RestartWindows: Boolean;
|
||||
|
|
@ -101,7 +101,7 @@ type
|
|||
destructor Destroy; override;
|
||||
procedure CheckInternetConnectedState;
|
||||
function DoInstall(Handle: THandle;
|
||||
StartAfterInstall, StartWithWindows, CheckForUpdates, StartDisabled,
|
||||
StartAfterInstall, StartWithWindows, CheckForUpdates, AutomaticUpdates, StartDisabled,
|
||||
StartWithConfiguration, InstallDefaults, AutomaticallyReportUsage, ContinueSetup: Boolean): Boolean;
|
||||
procedure LogError(const msg: WideString; ShowDialogIfNotSilent: Boolean = True);
|
||||
procedure LogInfo(const msg: string; ShowDialogIfNotSilent: Boolean = False);
|
||||
|
|
@ -194,7 +194,7 @@ begin
|
|||
end;
|
||||
|
||||
function TRunTools.DoInstall(Handle: THandle;
|
||||
StartAfterInstall, StartWithWindows, CheckForUpdates, StartDisabled,
|
||||
StartAfterInstall, StartWithWindows, CheckForUpdates, AutomaticUpdates, StartDisabled,
|
||||
StartWithConfiguration, InstallDefaults, AutomaticallyReportUsage, ContinueSetup: Boolean): Boolean;
|
||||
var
|
||||
msiLocation: TInstallInfoFileLocation;
|
||||
|
|
@ -224,7 +224,7 @@ begin
|
|||
Exit(False);
|
||||
end;
|
||||
|
||||
ConfigFirstRun(StartAfterInstall,StartWithWindows,CheckForUpdates,
|
||||
ConfigFirstRun(StartAfterInstall,StartWithWindows,CheckForUpdates,AutomaticUpdates,
|
||||
StartDisabled,StartWithConfiguration,InstallDefaults,AutomaticallyReportUsage);
|
||||
|
||||
Result := True;
|
||||
|
|
@ -588,7 +588,7 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure TRunTools.ConfigFirstRun(StartKeyman,StartWithWindows,CheckForUpdates,
|
||||
procedure TRunTools.ConfigFirstRun(StartKeyman,StartWithWindows,CheckForUpdates,AutomaticUpdates,
|
||||
StartDisabled,StartWithConfiguration,InstallDefaults,AutomaticallyReportUsage: Boolean);
|
||||
var
|
||||
i: Integer;
|
||||
|
|
@ -686,6 +686,7 @@ begin
|
|||
|
||||
if StartWithWindows then s := s + 'StartWithWindows,';
|
||||
if CheckForUpdates then s := s + 'CheckForUpdates,';
|
||||
if AutomaticUpdates then s := s + 'AutomaticUpdates,';
|
||||
if AutomaticallyReportUsage then s := s + 'AutomaticallyReportUsage,';
|
||||
|
||||
if InstallDefaults then
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ type
|
|||
FCanUpgrade9: Boolean;
|
||||
FCanUpgrade10: Boolean;
|
||||
FCheckForUpdates: Boolean;
|
||||
FAutomaticUpdates: Boolean;
|
||||
FStartAfterInstall: Boolean;
|
||||
FStartWithWindows: Boolean;
|
||||
FAutomaticallyReportUsage: Boolean;
|
||||
|
|
@ -523,7 +524,7 @@ begin
|
|||
SetupMSI; // I2644
|
||||
|
||||
if GetRunTools.DoInstall(Handle, FStartAfterInstall, FStartWithWindows, FCheckForUpdates,
|
||||
FInstallInfo.StartDisabled, FInstallInfo.StartWithConfiguration, FInstallDefaults,
|
||||
FAutomaticUpdates, FInstallInfo.StartDisabled, FInstallInfo.StartWithConfiguration, FInstallDefaults,
|
||||
FAutomaticallyReportUsage, FContinueSetup) then
|
||||
begin
|
||||
if not Silent and not FStartAfterInstall then // I2610
|
||||
|
|
@ -1032,6 +1033,7 @@ procedure TfrmRunDesktop.GetDefaultSettings; // I2651
|
|||
begin
|
||||
FStartWithWindows := True; // I2607
|
||||
FCheckForUpdates := True; // I2609
|
||||
FAutomaticUpdates := True;
|
||||
|
||||
try
|
||||
with CreateHKCURegistry do // I2749
|
||||
|
|
@ -1041,6 +1043,8 @@ begin
|
|||
FCheckForUpdates := ValueExists(SRegValue_CheckForUpdates) and ReadBool(SRegValue_CheckForUpdates);
|
||||
FStartWithWindows := ValueExists(SRegValue_UpgradeRunKeyman) or
|
||||
(OpenKeyReadOnly('\' + SRegKey_WindowsRun_CU) and ValueExists(SRegValue_WindowsRun_Keyman));
|
||||
FAutomaticUpdates := not ValueExists(SRegValue_AutomaticUpdates) or ReadBool(SRegValue_AutomaticUpdates);
|
||||
|
||||
end
|
||||
else if FCanUpgrade10 and OpenKeyReadOnly(SRegKey_KeymanEngine100_ProductOptions_Desktop_CU) then // I4293
|
||||
begin
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ object frmKeyman7Main: TfrmKeyman7Main
|
|||
Left = 28
|
||||
Top = 40
|
||||
end
|
||||
object tmrOnlineUpdateCheck: TTimer
|
||||
object tmrBackgroundUpdateCheck: TTimer
|
||||
Enabled = False
|
||||
Interval = 300000
|
||||
OnTimer = tmrOnlineUpdateCheckTimer
|
||||
OnTimer = tmrBackgroundUpdateCheckTimer
|
||||
Left = 280
|
||||
Top = 104
|
||||
end
|
||||
|
|
|
|||
|
|
@ -198,13 +198,13 @@ type
|
|||
TfrmKeyman7Main = class(TForm)
|
||||
mnu: TPopupMenu;
|
||||
tmrTestKeymanFunctioning: TTimer;
|
||||
tmrOnlineUpdateCheck: TTimer;
|
||||
tmrBackgroundUpdateCheck: TTimer;
|
||||
tmrCheckInputPane: TTimer;
|
||||
tmrRefresh: TTimer;
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
procedure tmrTestKeymanFunctioningTimer(Sender: TObject);
|
||||
procedure tmrOnlineUpdateCheckTimer(Sender: TObject);
|
||||
procedure tmrBackgroundUpdateCheckTimer(Sender: TObject);
|
||||
procedure tmrCheckInputPaneTimer(Sender: TObject);
|
||||
procedure tmrRefreshTimer(Sender: TObject);
|
||||
private
|
||||
|
|
@ -1838,7 +1838,7 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmKeyman7Main.tmrOnlineUpdateCheckTimer(Sender: TObject);
|
||||
procedure TfrmKeyman7Main.tmrBackgroundUpdateCheckTimer(Sender: TObject);
|
||||
begin
|
||||
with TRegistryErrorControlled.Create do // I2890
|
||||
try
|
||||
|
|
@ -1846,7 +1846,7 @@ begin
|
|||
begin
|
||||
if ValueExists(SRegValue_CheckForUpdates) and not ReadBool(SRegValue_CheckForUpdates) then Exit;
|
||||
if ValueExists(SRegValue_LastUpdateCheckTime) and (Now - ReadDateTime(SRegValue_LastUpdateCheckTime) < 7) then Exit;
|
||||
TKeymanDesktopShell.RunKeymanConfiguration('-ouc');
|
||||
TKeymanDesktopShell.RunKeymanConfiguration('-buc');
|
||||
end;
|
||||
finally
|
||||
Free;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ uses
|
|||
UfrmOSKPlugInBase in 'viskbd\UfrmOSKPlugInBase.pas' {frmOSKPlugInBase},
|
||||
UfrmOSKCharacterMap in 'viskbd\UfrmOSKCharacterMap.pas' {frmOSKCharacterMap},
|
||||
UfrmOSKEntryHelper in 'viskbd\UfrmOSKEntryHelper.pas' {frmOSKEntryHelper},
|
||||
TTInfo in '..\..\..\..\common\windows\delphi\general\TTInfo.pas',
|
||||
ttinfo in '..\..\..\..\common\windows\delphi\general\ttinfo.pas',
|
||||
UnicodeData in '..\..\..\..\common\windows\delphi\charmap\UnicodeData.pas',
|
||||
CharacterMapSettings in '..\..\..\..\common\windows\delphi\charmap\CharacterMapSettings.pas',
|
||||
CharacterRanges in '..\..\..\..\common\windows\delphi\charmap\CharacterRanges.pas',
|
||||
|
|
@ -112,7 +112,8 @@ uses
|
|||
Sentry.Client.Vcl in '..\..\..\..\common\windows\delphi\ext\sentry\Sentry.Client.Vcl.pas',
|
||||
sentry in '..\..\..\..\common\windows\delphi\ext\sentry\sentry.pas',
|
||||
Keyman.System.KeymanSentryClient in '..\..\..\..\common\windows\delphi\general\Keyman.System.KeymanSentryClient.pas',
|
||||
Keyman.System.LocaleStrings in '..\..\global\delphi\cust\Keyman.System.LocaleStrings.pas';
|
||||
Keyman.System.LocaleStrings in '..\..\global\delphi\cust\Keyman.System.LocaleStrings.pas',
|
||||
Keyman.System.ExecutionHistory in '..\..\..\..\common\windows\delphi\general\Keyman.System.ExecutionHistory.pas';
|
||||
|
||||
{$R ICONS.RES}
|
||||
{$R VERSION.RES}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
<DCCReference Include="viskbd\UfrmOSKEntryHelper.pas">
|
||||
<Form>frmOSKEntryHelper</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\general\TTInfo.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\general\ttinfo.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\charmap\UnicodeData.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\charmap\CharacterMapSettings.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\charmap\CharacterRanges.pas"/>
|
||||
|
|
@ -238,6 +238,7 @@
|
|||
<DCCReference Include="..\..\..\..\common\windows\delphi\ext\sentry\sentry.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\general\Keyman.System.KeymanSentryClient.pas"/>
|
||||
<DCCReference Include="..\..\global\delphi\cust\Keyman.System.LocaleStrings.pas"/>
|
||||
<DCCReference Include="..\..\..\..\common\windows\delphi\general\Keyman.System.ExecutionHistory.pas"/>
|
||||
<None Include="Profiling\AQtimeModule1.aqt"/>
|
||||
<BuildConfiguration Include="Debug">
|
||||
<Key>Cfg_2</Key>
|
||||
|
|
@ -299,21 +300,21 @@
|
|||
<Platform value="Win64">False</Platform>
|
||||
</Platforms>
|
||||
<Deployment Version="3">
|
||||
<DeployFile LocalName="keyman.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<DeployFile LocalName="Profiling\AQtimeModule1.aqt" Configuration="Debug" Class="ProjectFile">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>keyman.exe</RemoteName>
|
||||
<RemoteDir>.\</RemoteDir>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployFile LocalName="keyman.rsm" Configuration="Debug" Class="DebugSymbols">
|
||||
<DeployFile LocalName="bin\Win32\Debug\keyman.rsm" Configuration="Debug" Class="DebugSymbols">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>keyman.rsm</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployFile LocalName="Profiling\AQtimeModule1.aqt" Configuration="Debug" Class="ProjectFile">
|
||||
<DeployFile LocalName="bin\Win32\Debug\keyman.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>.\</RemoteDir>
|
||||
<RemoteName>keyman.exe</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
|
|
|
|||
|
|
@ -40,9 +40,11 @@ uses
|
|||
System.Win.Registry,
|
||||
|
||||
GetOsVersion,
|
||||
Keyman.System.ExecutionHistory,
|
||||
Keyman.System.Security,
|
||||
Keyman.Winapi.VersionHelpers,
|
||||
KeymanVersion,
|
||||
Klog,
|
||||
RegistryKeys,
|
||||
UfrmKeyman7Main,
|
||||
UserMessages;
|
||||
|
|
@ -76,9 +78,10 @@ var
|
|||
hMutex: Cardinal;
|
||||
begin
|
||||
|
||||
|
||||
if not ValidateParameters(FCommand) then Exit;
|
||||
|
||||
RecordKeymanStarted;
|
||||
|
||||
hProgramMutex := CreateMutex(nil, False, 'KeymanEXE70');
|
||||
if hProgramMutex = 0 then
|
||||
begin
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ end;
|
|||
|
||||
procedure TKeymanControl.OpenUpdateCheck;
|
||||
begin
|
||||
RunKeymanConfiguration('-ouc');
|
||||
RunKeymanConfiguration('-buc');
|
||||
end;
|
||||
|
||||
procedure TKeymanControl.StartKeyman;
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ type
|
|||
GroupName: string;
|
||||
end;
|
||||
|
||||
const KeymanOptionInfo: array[0..16] of TKeymanOptionInfo = ( // I3331 // I3620 // I4552
|
||||
const KeymanOptionInfo: array[0..17] of TKeymanOptionInfo = ( // I3331 // I3620 // I4552
|
||||
// Global options
|
||||
|
||||
(opt: koKeyboardHotkeysAreToggle; RegistryName: SRegValue_KeyboardHotkeysAreToggle; OptionType: kotBool; BoolValue: False; GroupName: 'kogGeneral'),
|
||||
|
|
@ -129,7 +129,8 @@ const KeymanOptionInfo: array[0..16] of TKeymanOptionInfo = ( // I3331 // I36
|
|||
(opt: koAltGrCtrlAlt; RegistryName: SRegValue_AltGrCtrlAlt; OptionType: kotBool; BoolValue: False; GroupName: 'kogGeneral'),
|
||||
(opt: koRightModifierHK; RegistryName: SRegValue_AllowRightModifierHotKey; OptionType: kotBool; BoolValue: False; GroupName: 'kogGeneral'),
|
||||
(opt: koShowHints; RegistryName: SRegValue_EnableHints; OptionType: kotBool; BoolValue: True; GroupName: 'kogGeneral'),
|
||||
(opt: koBaseLayout; RegistryName: SRegValue_UnderlyingLayout; OptionType: kotLong; IntValue: 0; GroupName: 'kogGeneral'),
|
||||
(opt: koBaseLayout; RegistryName: SRegValue_UnderlyingLayout; OptionType: kotLong; IntValue: 0; GroupName: 'kogGeneral'),
|
||||
(opt: koAutomaticUpdate; RegistryName: SRegValue_AutomaticUpdates; OptionType: kotBool; BoolValue: True; GroupName: 'kogGeneral'),
|
||||
|
||||
(opt: koAutomaticallyReportErrors; RegistryName: SRegValue_AutomaticallyReportErrors; OptionType: kotBool; BoolValue: True; GroupName: 'kogGeneral'), // I4393
|
||||
(opt: koAutomaticallyReportUsage; RegistryName: SRegValue_AutomaticallyReportUsage; OptionType: kotBool; BoolValue: True; GroupName: 'kogGeneral'), // I4393
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ type
|
|||
koRightModifierHK,
|
||||
koReleaseShiftKeysAfterKeyPress,
|
||||
koShowHints, // I1256
|
||||
koAutomaticUpdate,
|
||||
// Startup options
|
||||
koTestKeymanFunctioning,
|
||||
koStartWithWindows,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue