diff --git a/HISTORY.md b/HISTORY.md
index 0c1646e28e..f3ba952cd4 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,5 +1,9 @@
# Keyman Version History
+## 16.0.50 alpha 2022-08-23
+
+* chore(core): Remove obsolete python keyboardprocessor (#7094)
+
## 16.0.49 alpha 2022-08-22
* fix: remove saving and restoring context kbd options (#7077)
diff --git a/VERSION.md b/VERSION.md
index 245e8fdca3..251a25b345 100644
--- a/VERSION.md
+++ b/VERSION.md
@@ -1 +1 @@
-16.0.50
\ No newline at end of file
+16.0.51
\ No newline at end of file
diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KMPBrowserActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KMPBrowserActivity.java
index 7cff5b5e80..fe217c57e4 100644
--- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KMPBrowserActivity.java
+++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KMPBrowserActivity.java
@@ -18,6 +18,7 @@ import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
+import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.tavultesoft.kmea.BaseActivity;
@@ -113,7 +114,11 @@ public class KMPBrowserActivity extends BaseActivity {
// All links that aren't internal Keyman keyboard links open in user's browser
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- startActivity(intent);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ } else {
+ Toast.makeText(context, getString(R.string.unable_to_open_browser), Toast.LENGTH_SHORT).show();
+ }
return true;
}
if (lowerURL.startsWith("keyman:")) {
diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeyboardSettingsActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeyboardSettingsActivity.java
index 8aee2a6acb..dc5519095a 100644
--- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeyboardSettingsActivity.java
+++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/KeyboardSettingsActivity.java
@@ -26,6 +26,7 @@ import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
+import android.widget.Toast;
import com.tavultesoft.kmea.ConfirmDialogFragment;
import com.tavultesoft.kmea.KMHelpFileActivity;
@@ -160,7 +161,11 @@ public final class KeyboardSettingsActivity extends AppCompatActivity {
Bundle args = kbd.buildDownloadBundle();
Intent i = new Intent(getApplicationContext(), KMKeyboardDownloaderActivity.class);
i.putExtras(args);
- startActivity(i);
+ if (i.resolveActivity(getPackageManager()) != null) {
+ startActivity(i);
+ } else {
+ Toast.makeText(getApplicationContext(), getString(R.string.unable_to_open_browser), Toast.LENGTH_SHORT).show();
+ }
finish();
// "Help" link clicked
diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java
index 6f3affe4fb..2a9626984a 100644
--- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java
+++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java
@@ -762,10 +762,24 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
// Launch PlayStore to update Chrome
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.android.chrome"));
- startActivity(intent);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ } else {
+ intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=com.android.chrome"));
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ } else {
+ Toast.makeText(getApplicationContext(), getString(R.string.unable_to_open_browser), Toast.LENGTH_SHORT).show();
+ }
+ }
} catch (android.content.ActivityNotFoundException e) {
// Link to Chrome if user is not signed in to Play Store
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=com.android.chrome")));
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=com.android.chrome"));
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ } else {
+ Toast.makeText(getApplicationContext(), getString(R.string.unable_to_open_browser), Toast.LENGTH_SHORT).show();
+ }
}
}
});
diff --git a/android/KMAPro/kMAPro/src/main/res/values/strings.xml b/android/KMAPro/kMAPro/src/main/res/values/strings.xml
index 09a91b5f60..ed4e5b85a1 100644
--- a/android/KMAPro/kMAPro/src/main/res/values/strings.xml
+++ b/android/KMAPro/kMAPro/src/main/res/values/strings.xml
@@ -247,4 +247,7 @@
Keyboard requires a newer version of Keyman
+
+
+ Unable to launch web browser
diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardInfoActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardInfoActivity.java
index d9b15f0ea8..4b818acf7c 100644
--- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardInfoActivity.java
+++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardInfoActivity.java
@@ -136,7 +136,11 @@ public final class KeyboardInfoActivity extends BaseActivity {
} else {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(customHelpLink));
- startActivity(i);
+ if (i.resolveActivity(getPackageManager()) != null) {
+ startActivity(i);
+ } else {
+ Toast.makeText(context, getString(R.string.unable_to_open_browser), Toast.LENGTH_SHORT).show();
+ }
}
}
}
diff --git a/android/KMEA/app/src/main/res/values/strings.xml b/android/KMEA/app/src/main/res/values/strings.xml
index 8f7d20150d..50f52c5ef3 100644
--- a/android/KMEA/app/src/main/res/values/strings.xml
+++ b/android/KMEA/app/src/main/res/values/strings.xml
@@ -3,10 +3,10 @@
AndroidMobile
-
+
KMEA
-
+
- Keyboard
@@ -267,4 +267,6 @@
Tap here to change keyboard
+
+ Unable to launch web browser
diff --git a/common/include/km_types.h b/common/include/km_types.h
index 113647d3a0..bf25b354b5 100644
--- a/common/include/km_types.h
+++ b/common/include/km_types.h
@@ -1,5 +1,7 @@
#pragma once
+#include
+
/*
#if defined(_WIN32) || defined(_WIN64)
#define snprintf _snprintf
diff --git a/core/include/ldml/keyboardprocessor_ldml.h b/core/include/ldml/keyboardprocessor_ldml.h
index a6e623debb..5d2cab3050 100644
--- a/core/include/ldml/keyboardprocessor_ldml.h
+++ b/core/include/ldml/keyboardprocessor_ldml.h
@@ -14,27 +14,28 @@
//
#pragma once
-#define LDML_KEYS_FLAGS_EXTEND 1
-#define LDML_LENGTH_HEADER 8
-#define LDML_LENGTH_KEYS 16
-#define LDML_LENGTH_LOCA 12
-#define LDML_LENGTH_META 36
-#define LDML_LENGTH_SECT 16
-#define LDML_LENGTH_STRS 16
-#define LDML_LENGTH_VKEY 12
-#define LDML_META_SETTINGS_FALLBACK_OMIT 1
-#define LDML_META_SETTINGS_TRANSFORMFAILURE_OMIT 2
-#define LDML_META_SETTINGS_TRANSFORMPARTIAL_HIDE 4
-// Section ID
-#define LDML_SECTION_KEYS ((uint32_t)'keys')
-// Section ID
-#define LDML_SECTION_LOCA ((uint32_t)'loca')
-// Section ID
-#define LDML_SECTION_META ((uint32_t)'meta')
-// Section ID
-#define LDML_SECTION_SECT ((uint32_t)'sect')
-// Section ID
-#define LDML_SECTION_STRS ((uint32_t)'strs')
-// Section ID
-#define LDML_SECTION_VKEY ((uint32_t)'vkey')
+
+#define LDML_KEYS_FLAGS_EXTEND 0x1
+#define LDML_LENGTH_HEADER 0x8
+#define LDML_LENGTH_KEYS 0x10
+#define LDML_LENGTH_LOCA 0xC
+#define LDML_LENGTH_META 0x24
+#define LDML_LENGTH_SECT 0x10
+#define LDML_LENGTH_STRS 0x10
+#define LDML_LENGTH_VKEY 0xC
+#define LDML_META_SETTINGS_FALLBACK_OMIT 0x1
+#define LDML_META_SETTINGS_TRANSFORMFAILURE_OMIT 0x2
+#define LDML_META_SETTINGS_TRANSFORMPARTIAL_HIDE 0x4
+#define LDML_SECTIONID_KEYS 0x7379656B /* "keys" */
+#define LDML_SECTIONNAME_KEYS "keys"
+#define LDML_SECTIONID_LOCA 0x61636F6C /* "loca" */
+#define LDML_SECTIONNAME_LOCA "loca"
+#define LDML_SECTIONID_META 0x6174656D /* "meta" */
+#define LDML_SECTIONNAME_META "meta"
+#define LDML_SECTIONID_SECT 0x74636573 /* "sect" */
+#define LDML_SECTIONNAME_SECT "sect"
+#define LDML_SECTIONID_STRS 0x73727473 /* "strs" */
+#define LDML_SECTIONNAME_STRS "strs"
+#define LDML_SECTIONID_VKEY 0x79656B76 /* "vkey" */
+#define LDML_SECTIONNAME_VKEY "vkey"
#define LDML_VERSION "1.0"
diff --git a/core/include/ldml/keyboardprocessor_ldml.ts b/core/include/ldml/keyboardprocessor_ldml.ts
index e4a5a78346..35a0e01731 100644
--- a/core/include/ldml/keyboardprocessor_ldml.ts
+++ b/core/include/ldml/keyboardprocessor_ldml.ts
@@ -19,7 +19,10 @@
// TODO-LDML: namespace com.keyman.core.ldml {
/**
* Constants for the KMXPlus data format
- * These are shared between the data access layer and the compiler
+ * These are shared between the data access layer and the compiler.
+ * Note that the section IDs (section_keys etc.) are 32 bit hex
+ * values that are designed to appear as text when written in little endian
+ * format, so 0x7379656b = 'keys'
*/
export const constants = {
/**
@@ -30,28 +33,16 @@ export const constants = {
* Length of a raw section header, in bytes
*/
length_header: 8,
- /**
- * Section ID for the keybag
- */
- section_keys: 'keys',
/**
* Minimum length of the 'keys' section
* not including variable parts
*/
length_keys: 16,
- /**
- * Section ID for the locale list
- */
- section_loca: 'loca',
/**
* Minimum length of the 'loca' section
* not including variable parts
*/
length_loca: 12,
- /**
- * Section ID for the metadata
- */
- section_meta: 'meta',
/**
* length of the 'meta' section
*/
@@ -68,18 +59,10 @@ export const constants = {
* bitwise or value for transformPartial=hide in meta.settings
*/
meta_settings_transformPartial_hide: 4,
- /**
- * Section ID for the section header
- */
- section_sect: 'sect',
/**
* Minimum length of the 'sect' section, not including entries
*/
length_sect: 16,
- /**
- * Section ID for the string table
- */
- section_strs: 'strs',
/**
* Minimum length of the 'strs' section
* not including variable parts
@@ -93,14 +76,39 @@ export const constants = {
* `extend = flags & keys_flags_extend`
*/
keys_flags_extend: 1,
- /**
- * Section ID for the vkeys map
- */
- section_vkey: 'vkey',
/**
* Minimum length of the 'vkey' section
* not including variable parts
*/
length_vkey: 12,
+
+ /**
+ * All section IDs.
+ */
+ section: {
+ keys: 'keys',
+ loca: 'loca',
+ meta: 'meta',
+ sect: 'sect',
+ strs: 'strs',
+ vkey: 'vkey',
+ },
+
+ /**
+ * Use to convert 4-char string into hex
+ * @param id section id such as 'sect'
+ * @returns hex ID such as 0x74636573
+ */
+ hex_section_id: function(id:string) {
+ if(!id || typeof id !== 'string' || !id.match(/[a-z][a-z][a-z][a-z]/)) {
+ throw Error(`hex_section_id(${id}) - need a 4-character string`);
+ }
+ let r = 0;
+ for (let i = 3; i>=0; i--) {
+ r = (r << 8 | id.charCodeAt(i));
+ }
+ return r;
+ },
+
};
// }
diff --git a/core/include/ldml/ldml-const-builder.ts b/core/include/ldml/ldml-const-builder.ts
index d8a398b72e..e028dc4b70 100644
--- a/core/include/ldml/ldml-const-builder.ts
+++ b/core/include/ldml/ldml-const-builder.ts
@@ -23,19 +23,29 @@ console.log(`
// based on core/include/ldml/keyboardprocessor_ldml.ts
//
-#pragma once`);
+#pragma once
+`);
for (const key of keys) {
const value = constants[key];
const upkey = key.toUpperCase();
const type = typeof value;
- if ((key.indexOf('section_') === 0) && type === 'string' && value.length === 4) {
- // the 4-char section ID strings get handled specially
- console.log('// Section ID');
- console.log(`#define LDML_${upkey} ((uint32_t)'${value}')`);
- } else if (type === 'number') {
- console.log(`#define LDML_${upkey} ${value}`);
+ if (type === 'number') {
+ console.log(`#define LDML_${upkey} 0x${value.toString(16).toUpperCase()}`);
} else if (type === 'string') {
console.log(`#define LDML_${upkey} "${value}"`);
+ } else if (key === 'section') {
+ // handle section table
+ const subkeys = Object.keys(value);
+ subkeys.sort();
+ for (const subkey of subkeys) {
+ const upsubkey = subkey.toUpperCase();
+ const subvalue = subkeys[subkey];
+ const asnum = constants.hex_section_id(subkey);
+ console.log(`#define LDML_${upkey}ID_${upsubkey} 0x${asnum.toString(16).toUpperCase()} /* "${subkey}" */`);
+ console.log(`#define LDML_${upkey}NAME_${upsubkey} "${subkey}"`);
+ }
+ } else if (type !== 'function') {
+ console.error(`Unrecognized key ${key}`);
}
}
diff --git a/core/src/kmx/kmx_plus.cpp b/core/src/kmx/kmx_plus.cpp
index 7949cb030f..fa47279364 100644
--- a/core/src/kmx/kmx_plus.cpp
+++ b/core/src/kmx/kmx_plus.cpp
@@ -4,12 +4,14 @@
Implementation for the KMX Plus utilities
*/
+#include
+#include
#include
/**
* @def KMXPLUS_DEBUG Set to 1 to enable debug output
*/
-#define KMXPLUS_DEBUG 1
+#define KMXPLUS_DEBUG 0
#if KMXPLUS_DEBUG
#include
@@ -32,8 +34,9 @@ dump_section_name(KMX_DWORD ident) {
static void
dump_kmxplus_header(const COMP_KMXPLUS_HEADER* hdr) {
- if (hdr == NULL) {
+ if (hdr == nullptr) {
printf("! dump_kmxplus_header: NULL header\n");
+ return;
}
dump_section_name(hdr->ident);
printf(": (%X) size 0x%X\n", hdr->ident, hdr->size);
@@ -41,7 +44,7 @@ dump_kmxplus_header(const COMP_KMXPLUS_HEADER* hdr) {
static void
dump_kmxplus_keys(const uint8_t* /*data*/, const COMP_KMXPLUS_KEYS* keys) {
- if(keys == NULL) {
+ if(keys == nullptr) {
printf("! could not load 'keys' section\n");
return;
}
@@ -63,7 +66,7 @@ dump_kmxplus_keys(const uint8_t* /*data*/, const COMP_KMXPLUS_KEYS* keys) {
static void
dump_kmxplus_loca(const uint8_t* /*data*/, const COMP_KMXPLUS_LOCA* loca) {
- if(loca == NULL) {
+ if(loca == nullptr) {
printf("! could not load 'loca' section\n");
return;
}
@@ -76,7 +79,7 @@ dump_kmxplus_loca(const uint8_t* /*data*/, const COMP_KMXPLUS_LOCA* loca) {
static void
dump_kmxplus_meta(const uint8_t* /*data*/, const COMP_KMXPLUS_META* meta) {
- if(meta == NULL) {
+ if(meta == nullptr) {
printf("! could not load 'meta' section\n");
return;
}
@@ -92,7 +95,7 @@ dump_kmxplus_meta(const uint8_t* /*data*/, const COMP_KMXPLUS_META* meta) {
static void
dump_kmxplus_vkey(const uint8_t* /*data*/, const COMP_KMXPLUS_VKEY* vkey) {
- if(vkey == NULL) {
+ if (vkey == nullptr) {
printf("! could not load 'vkey' section\n");
return;
}
@@ -102,6 +105,10 @@ dump_kmxplus_vkey(const uint8_t* /*data*/, const COMP_KMXPLUS_VKEY* vkey) {
static void
dump_kmxplus_strs(const uint8_t* /*data*/, const COMP_KMXPLUS_STRS* strs) {
+ if (strs == nullptr) {
+ printf("! could not load 'strs' section\n");
+ return;
+ }
dump_kmxplus_header((const COMP_KMXPLUS_HEADER*)strs);
printf("strs: count 0x%X\n", strs->count);
for (KMX_DWORD i=0; icount; i++) {
@@ -113,10 +120,10 @@ dump_kmxplus_strs(const uint8_t* /*data*/, const COMP_KMXPLUS_STRS* strs) {
continue;
}
for(int j=0; str[j] && j<0x30; j++) {
- if (str[j] < 0x7F && str[j] != 0x0020 && str[j] > 0x20) {
+ if (str[j] < 0x7F && str[j] > 0x20) {
putchar(str[j]);
} else {
- printf("U+%04X ", str[j]);
+ printf(" U+%04X ", str[j]);
}
}
printf("\n");
@@ -125,6 +132,9 @@ dump_kmxplus_strs(const uint8_t* /*data*/, const COMP_KMXPLUS_STRS* strs) {
static void
dump_kmxplus_sect(const uint8_t* data, const COMP_KMXPLUS_SECT* sect) {
+ if (sect == nullptr) {
+ printf("! could not load 'sect' section\n");
+ }
dump_kmxplus_header((const COMP_KMXPLUS_HEADER*)sect);
printf("sect: total 0x%X\n", sect->total);
printf("sect: count 0x%X\n", sect->count);
@@ -135,22 +145,22 @@ dump_kmxplus_sect(const uint8_t* data, const COMP_KMXPLUS_SECT* sect) {
printf(" sect#%d: %X @ %X\n", i, entry.sect, entry.offset);
const uint8_t* entrydata = (data+entry.offset);
switch(entry.sect) {
- case LDML_SECTION_KEYS:
+ case LDML_SECTIONID_KEYS:
dump_kmxplus_keys(data, as_kmxplus_keys(entrydata));
break;
- case LDML_SECTION_LOCA:
+ case LDML_SECTIONID_LOCA:
dump_kmxplus_loca(data, as_kmxplus_loca(entrydata));
break;
- case LDML_SECTION_META:
+ case LDML_SECTIONID_META:
dump_kmxplus_meta(data, as_kmxplus_meta(entrydata));
break;
- case LDML_SECTION_SECT:
- printf("! Cowardly refusing to dump nested 'sect' section.\n");
+ case LDML_SECTIONID_SECT:
+ printf("! Cowardly refusing to dump invalid nested 'sect' section.\n");
break;
- case LDML_SECTION_STRS:
+ case LDML_SECTIONID_STRS:
dump_kmxplus_strs(data, as_kmxplus_strs(entrydata));
break;
- case LDML_SECTION_VKEY:
+ case LDML_SECTIONID_VKEY:
dump_kmxplus_vkey(data, as_kmxplus_vkey(entrydata));
break;
default:
@@ -160,21 +170,31 @@ dump_kmxplus_sect(const uint8_t* data, const COMP_KMXPLUS_SECT* sect) {
}
#endif
+#if !KMXPLUS_DEBUG
+void
+dump_kmxplus_data(const uint8_t* ) {
+ // no op
+}
+
+void
+dump_kmxplus_data(kmx::PCOMP_KEYBOARD) {
+ // no op
+}
+
+#else
+
void
dump_kmxplus_data(const uint8_t* data) {
-#if KMXPLUS_DEBUG
const COMP_KMXPLUS_SECT* sect = as_kmxplus_sect(data);
- if (sect == NULL) {
- printf("Err: 'sect' null from %p\n", data);
+ if (sect == nullptr) {
+ printf("Err: 'sect' NULL from %p\n", data);
return;
}
dump_kmxplus_sect(data, sect);
-#endif
}
void
dump_kmxplus_data(kmx::PCOMP_KEYBOARD keyboard) {
-#if KMXPLUS_DEBUG
printf("dump_kmxplus_data(): Got a PCOMP_KEYBOARD at %p\n", keyboard);
if (!(keyboard->dwFlags & KF_KMXPLUS)) {
printf("Err: flags KF_KMXPLUS not set\n");
@@ -185,8 +205,8 @@ dump_kmxplus_data(kmx::PCOMP_KEYBOARD keyboard) {
printf("KMXPlus offset 0x%X, KMXPlus size 0x%X\n", ex->kmxplus.dpKMXPlus, ex->kmxplus.dwKMXPlusSize);
const uint8_t* rawdata = reinterpret_cast(keyboard);
dump_kmxplus_data(rawdata + ex->kmxplus.dpKMXPlus);
-#endif
}
+#endif
const COMP_KMXPLUS_KEYS_ENTRY *COMP_KMXPLUS_KEYS::find(KMX_DWORD vkey, KMX_DWORD mod) const {
// TODO-LDML: eventually, assume sorted order & binary search
@@ -195,7 +215,7 @@ const COMP_KMXPLUS_KEYS_ENTRY *COMP_KMXPLUS_KEYS::find(KMX_DWORD vkey, KMX_DWORD
return &entries[i];
}
}
- return NULL;
+ return nullptr;
}
KMX_DWORD COMP_KMXPLUS_SECT::find(KMX_DWORD ident) const {
@@ -211,7 +231,7 @@ PKMX_WCHAR
COMP_KMXPLUS_STRS::get(KMX_DWORD entry, PKMX_WCHAR buf, KMX_DWORD bufsiz) const {
assert(entry < count);
if (entry >= count) {
- return NULL;
+ return nullptr;
}
KMX_DWORD offset = entries[entry].offset;
KMX_DWORD length = entries[entry].length;
diff --git a/core/src/kmx/kmx_plus.h b/core/src/kmx/kmx_plus.h
index 89c3421d7f..98d091036b 100644
--- a/core/src/kmx/kmx_plus.h
+++ b/core/src/kmx/kmx_plus.h
@@ -7,13 +7,23 @@
#pragma once
#include
-#include
+#include
+#include
+#include
#include
namespace km {
namespace kbp {
namespace kmx {
+/**
+ * Using C99 flexible array initializers: entries[]
+ * https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-levels-2-and-4-c4200
+ */
+#if defined(_WIN32)
+#pragma warning ( disable : 4200 )
+#endif
+
struct COMP_KMXPLUS_HEADER {
KMX_DWORD ident; // 0000 Section name
KMX_DWORD size; // 0004 Section length
@@ -31,7 +41,7 @@ struct COMP_KMXPLUS_SECT {
COMP_KMXPLUS_HEADER header;
KMX_DWORD total; // 0008 KMXPlus entire length
KMX_DWORD count; // 000B number of section headers
- COMP_KMXPLUS_SECT_ENTRY entries[0]; // 0010 section entries
+ COMP_KMXPLUS_SECT_ENTRY entries[]; // 0010 section entries
/**
* @brief Get the offset of a section, or 0
*
@@ -53,7 +63,7 @@ struct COMP_KMXPLUS_STRS {
COMP_KMXPLUS_HEADER header;
KMX_DWORD count; // 0008 count of str entries
KMX_DWORD reserved; // 000C padding
- COMP_KMXPLUS_STRS_ENTRY entries[0]; // 0010+ entries
+ COMP_KMXPLUS_STRS_ENTRY entries[]; // 0010+ entries
/**
* @brief Get a string entry
@@ -61,7 +71,7 @@ struct COMP_KMXPLUS_STRS {
* @param entry entry number
* @param buf output buffer
* @param bufsiz buffer size in bytes
- * @return NULL or a pointer to the output buffer
+ * @return nullptr or a pointer to the output buffer
*/
PKMX_WCHAR get(KMX_DWORD entry, PKMX_WCHAR buf, KMX_DWORD bufsiz) const;
};
@@ -88,7 +98,7 @@ struct COMP_KMXPLUS_LOCA_ENTRY {
struct COMP_KMXPLUS_LOCA {
COMP_KMXPLUS_HEADER header;
KMX_DWORD count; // 0008 number of locales
- COMP_KMXPLUS_LOCA_ENTRY entries[0];
+ COMP_KMXPLUS_LOCA_ENTRY entries[];
};
static_assert(sizeof(struct COMP_KMXPLUS_LOCA) == LDML_LENGTH_LOCA, "mismatched size of section loca");
@@ -104,7 +114,7 @@ struct COMP_KMXPLUS_KEYS {
COMP_KMXPLUS_HEADER header;
KMX_DWORD count; // number of keys
KMX_DWORD reserved; // padding
- COMP_KMXPLUS_KEYS_ENTRY entries[0];
+ COMP_KMXPLUS_KEYS_ENTRY entries[];
const COMP_KMXPLUS_KEYS_ENTRY *find(KMX_DWORD vkey, KMX_DWORD mod) const;
};
@@ -118,11 +128,19 @@ struct COMP_KMXPLUS_VKEY_ENTRY {
struct COMP_KMXPLUS_VKEY {
COMP_KMXPLUS_HEADER header;
KMX_DWORD count;
- COMP_KMXPLUS_VKEY_ENTRY entries[0];
+ COMP_KMXPLUS_VKEY_ENTRY entries[];
};
static_assert(sizeof(struct COMP_KMXPLUS_VKEY) == LDML_LENGTH_VKEY, "mismatched size of section vkey");
+/**
+ * See above
+ */
+#if defined(_WIN32)
+#pragma warning ( default : 4200 )
+#endif
+
+
/**
* @brief Validate that this data is the named section.
*
@@ -133,14 +151,14 @@ static_assert(sizeof(struct COMP_KMXPLUS_VKEY) == LDML_LENGTH_VKEY, "mismatched
static inline const COMP_KMXPLUS_HEADER *
validate_as_section(const uint8_t *data, uint32_t ident) {
if (!data) {
- return NULL;
+ return nullptr;
}
const COMP_KMXPLUS_HEADER *all = reinterpret_cast(data);
// TODO-LDML these fail on 000null ..
assert(all->size >= LDML_LENGTH_HEADER);
assert(ident == all->ident);
if (ident != all->ident || (all->size < LDML_LENGTH_HEADER)) {
- return NULL; // invalid header or wrong section
+ return nullptr; // invalid header or wrong section
}
return all;
}
@@ -151,7 +169,7 @@ validate_as_section(const uint8_t *data, uint32_t ident) {
*/
static inline const COMP_KMXPLUS_SECT *
as_kmxplus_sect(const uint8_t *data) {
- const COMP_KMXPLUS_HEADER *all = validate_as_section(data, LDML_SECTION_SECT);
+ const COMP_KMXPLUS_HEADER *all = validate_as_section(data, LDML_SECTIONID_SECT);
return reinterpret_cast(all);
}
@@ -161,7 +179,7 @@ as_kmxplus_sect(const uint8_t *data) {
*/
static inline const COMP_KMXPLUS_STRS *
as_kmxplus_strs(const uint8_t *data) {
- const COMP_KMXPLUS_HEADER *all = validate_as_section(data, LDML_SECTION_STRS);
+ const COMP_KMXPLUS_HEADER *all = validate_as_section(data, LDML_SECTIONID_STRS);
return reinterpret_cast(all);
}
@@ -171,7 +189,7 @@ as_kmxplus_strs(const uint8_t *data) {
*/
static inline const COMP_KMXPLUS_KEYS *
as_kmxplus_keys(const uint8_t *data) {
- const COMP_KMXPLUS_HEADER *all = validate_as_section(data, LDML_SECTION_KEYS);
+ const COMP_KMXPLUS_HEADER *all = validate_as_section(data, LDML_SECTIONID_KEYS);
return reinterpret_cast(all);
}
/**
@@ -180,7 +198,7 @@ as_kmxplus_keys(const uint8_t *data) {
*/
static inline const COMP_KMXPLUS_LOCA *
as_kmxplus_loca(const uint8_t *data) {
- const COMP_KMXPLUS_HEADER *all = validate_as_section(data, LDML_SECTION_LOCA);
+ const COMP_KMXPLUS_HEADER *all = validate_as_section(data, LDML_SECTIONID_LOCA);
return reinterpret_cast(all);
}
/**
@@ -189,7 +207,7 @@ as_kmxplus_loca(const uint8_t *data) {
*/
static inline const COMP_KMXPLUS_META *
as_kmxplus_meta(const uint8_t *data) {
- const COMP_KMXPLUS_HEADER *all = validate_as_section(data, LDML_SECTION_META);
+ const COMP_KMXPLUS_HEADER *all = validate_as_section(data, LDML_SECTIONID_META);
return reinterpret_cast(all);
}
/**
@@ -198,7 +216,7 @@ as_kmxplus_meta(const uint8_t *data) {
*/
static inline const COMP_KMXPLUS_VKEY *
as_kmxplus_vkey(const uint8_t *data) {
- const COMP_KMXPLUS_HEADER *all = validate_as_section(data, LDML_SECTION_VKEY);
+ const COMP_KMXPLUS_HEADER *all = validate_as_section(data, LDML_SECTIONID_VKEY);
return reinterpret_cast(all);
}
diff --git a/core/src/ldml/ldml_processor.cpp b/core/src/ldml/ldml_processor.cpp
index d20caf44a3..595dc6abf6 100644
--- a/core/src/ldml/ldml_processor.cpp
+++ b/core/src/ldml/ldml_processor.cpp
@@ -8,8 +8,8 @@
#include
#include "ldml/ldml_processor.hpp"
#include "state.hpp"
-#include "../kmx/kmx_file.h"
-#include "../kmx/kmx_plus.h"
+#include "kmx_file.h"
+#include "kmx/kmx_plus.h"
#include "ldml/keyboardprocessor_ldml.h"
// extern "C" {
@@ -28,6 +28,10 @@ enum ConversionFlags {
typedef KMX_WCHAR UTF16;
typedef KMX_DWORD UTF32;
+/**
+ * This is a temporary patch for now.
+ * API surface somewhat modelled after ConvertUTF.h
+ */
ConversionResult ConvertUTF32toUTF16(
UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, const UTF16* targetEnd, const ConversionFlags /*flags*/) {
@@ -170,21 +174,21 @@ ldml_processor::process_event(
const uint8_t* kmxplusdata = rawdata.data() + ex->kmxplus.dpKMXPlus;
// Get out the SECT header
const kmx::COMP_KMXPLUS_SECT *sect = kmx::as_kmxplus_sect(kmxplusdata);
- assert(sect != NULL);
- assert(sect->header.ident == LDML_SECTION_SECT);
+ assert(sect != nullptr);
+ assert(sect->header.ident == LDML_SECTIONID_SECT);
KMX_DWORD offset;
// Fill out the other sections we need.
- offset = sect->find(LDML_SECTION_STRS);
+ offset = sect->find(LDML_SECTIONID_STRS);
assert(offset != 0); // or else section not found
const kmx::COMP_KMXPLUS_STRS *strs = kmx::as_kmxplus_strs(kmxplusdata+offset);
- assert(strs->header.ident == LDML_SECTION_STRS);
- offset = sect->find(LDML_SECTION_KEYS);
+ assert(strs->header.ident == LDML_SECTIONID_STRS);
+ offset = sect->find(LDML_SECTIONID_KEYS);
assert(offset != 0); // or else section not found
const kmx::COMP_KMXPLUS_KEYS *keys = kmx::as_kmxplus_keys(kmxplusdata+offset);
- assert(keys->header.ident == LDML_SECTION_KEYS);
+ assert(keys->header.ident == LDML_SECTIONID_KEYS);
// Look up the key
const kmx::COMP_KMXPLUS_KEYS_ENTRY *key = keys->find(vk, modifier_state);
- assert(key != NULL);
+ assert(key != nullptr);
if (!key) {
return KM_KBP_STATUS_KEY_ERROR;
}
@@ -193,7 +197,7 @@ ldml_processor::process_event(
KMX_WCHAR out[BUFSIZ];
if (key->flags && LDML_KEYS_FLAGS_EXTEND) {
// It's a string.
- assert(NULL != strs->get(key->to, out, BUFSIZ));
+ assert(nullptr != strs->get(key->to, out, BUFSIZ));
// u_strlen()
for(len=0; len=1 && len <= 2);
}
- assert(len>=0);
+ assert(len>0);
assert(len
#include
-#include
+#include "kmx/kmx_plus.h"
using namespace km::kbp::kmx;
diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS
index eff7811f5e..021a6fc8bc 100644
--- a/docs/CODEOWNERS
+++ b/docs/CODEOWNERS
@@ -3,32 +3,31 @@
#
# @darcywong00 @mcdurdin @ermshiperete @rc-swag @SabineSIL @sgschantz
-/android/ @darcywong00 @rc-swag
+/android/ @darcywong00 @mcdurdin
-/common/ @mcdurdin @jahorton
-/core/ @mcdurdin @jahorton
+/common/ @mcdurdin @rc-swag
+/core/ @mcdurdin @rc-swag
/common/lexical-model-types/ @jahorton @mcdurdin
/common/models/ @jahorton @mcdurdin
/common/predictive-text/ @jahorton @mcdurdin
/common/schemas/ @mcdurdin @jahorton
/common/test/ @mcdurdin @ermshiperete
-/common/web/ @jahorton @ermshiperete @mcdurdin
+/common/web/ @jahorton @sgschantz @mcdurdin
/developer/ @mcdurdin @darcywong00
/docs/ @mcdurdin @jahorton
-/ios/ @sgschantz @mcdurdin
+/ios/ @sgschantz @jahorton
/linux/ @ermshiperete @darcywong00
/mac/ @sgschantz @SabineSIL
-/oem/firstvoices/android/ @darcywong00 @rc-swag
-/oem/firstvoices/common/ @mcdurdin @jahorton
-/oem/firstvoices/ios/ @sgschantz @mcdurdin
-/oem/firstvoices/windows/ @rc-swag @sgschantz
+/oem/firstvoices/android/ @darcywong00 @mcdurdin
+/oem/firstvoices/common/ @mcdurdin @rc-swag
+/oem/firstvoices/ios/ @sgschantz @jahorton
+/oem/firstvoices/windows/ @rc-swag @ermshiperete
/resources/ @mcdurdin @jahorton
# Web is currently shared between Marc and Joshua:
-/web/ @jahorton @ermshiperete @mcdurdin
+/web/ @jahorton @sgschantz @mcdurdin
+
+/windows/ @rc-swag @ermshiperete
-/windows/ @rc-swag @sgschantz
-# Override for windows/src:
-/windows/src/developer/ @mcdurdin @darcywong00
diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVShared.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVShared.java
index 854175e4cc..d308049417 100644
--- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVShared.java
+++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVShared.java
@@ -6,6 +6,7 @@ import android.content.SharedPreferences;
import android.content.res.AssetManager;
import android.net.Uri;
import android.util.Log;
+import android.widget.Toast;
import com.tavultesoft.kmea.KMManager;
import com.tavultesoft.kmea.data.Keyboard;
import com.tavultesoft.kmea.packages.PackageProcessor;
@@ -252,7 +253,11 @@ final class FVShared {
String helpUrl = String.format("%s%s", FVKeyboardHelpLink, id);
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(helpUrl));
- localContext.startActivity(i);
+ if (i.resolveActivity(localContext.getPackageManager()) != null) {
+ localContext.startActivity(i);
+ } else {
+ Toast.makeText(localContext, localContext.getString(R.string.unable_to_open_browser), Toast.LENGTH_SHORT).show();
+ }
}
private void updateActiveKeyboardsList() {
diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java
index 5d3e5c5939..95309efe48 100644
--- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java
+++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/MainActivity.java
@@ -105,7 +105,11 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardDownloa
}
else {
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- startActivity(i);
+ if (i.resolveActivity(getPackageManager()) != null) {
+ startActivity(i);
+ } else {
+ Toast.makeText(context, getString(R.string.unable_to_open_browser), Toast.LENGTH_SHORT).show();
+ }
}
return true;
diff --git a/oem/firstvoices/android/app/src/main/res/values/strings.xml b/oem/firstvoices/android/app/src/main/res/values/strings.xml
index 83edf8f86b..e443e0f717 100644
--- a/oem/firstvoices/android/app/src/main/res/values/strings.xml
+++ b/oem/firstvoices/android/app/src/main/res/values/strings.xml
@@ -42,4 +42,6 @@
Invalid/Missing metadata in package
+
+ Unable to launch web browser
diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp
index 03a047cc63..7faac081c2 100644
--- a/windows/src/engine/keyman32/kmprocess.cpp
+++ b/windows/src/engine/keyman32/kmprocess.cpp
@@ -190,7 +190,7 @@ BOOL ProcessHook()
}
if (!_td->TIPFUpdateable) {
- ProcessActionsTestParse(&fOutputKeystroke);
+ ProcessActionsNonUpdatableParse(&fOutputKeystroke);
} else {
ProcessActions(&fOutputKeystroke);
}
diff --git a/windows/src/engine/keyman32/kmprocessactions.cpp b/windows/src/engine/keyman32/kmprocessactions.cpp
index f0aa36256d..6a5e03c123 100644
--- a/windows/src/engine/keyman32/kmprocessactions.cpp
+++ b/windows/src/engine/keyman32/kmprocessactions.cpp
@@ -167,7 +167,7 @@ BOOL ProcessActions(BOOL* emitKeyStroke)
}
BOOL
-ProcessActionsTestParse(BOOL* emitKeyStroke) {
+ProcessActionsNonUpdatableParse(BOOL* emitKeyStroke) {
PKEYMAN64THREADDATA _td = ThreadGlobals();
if (!_td) {
return FALSE;
@@ -184,13 +184,16 @@ ProcessActionsTestParse(BOOL* emitKeyStroke) {
switch (act->type) {
case KM_KBP_IT_EMIT_KEYSTROKE:
*emitKeyStroke = TRUE;
- SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessActionsTestParse EMIT_KEYSTROKE: act->type=%d", act->type);
+ SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessActionsNonUpdatableParse EMIT_KEYSTROKE: act->type=[%d]", act->type);
continueProcessingActions = TRUE;
_td->CoreProcessEventRun = FALSE; // If we emit the key stroke on this parse we don't need the second parse
break;
case KM_KBP_IT_CAPSLOCK:
continueProcessingActions = processCapsLock(act, !_td->state.isDown, _td->TIPFUpdateable);
break;
+ case KM_KBP_IT_INVALIDATE_CONTEXT:
+ continueProcessingActions = processInvalidateContext(_td->app, _td->lpActiveKeyboard->lpCoreKeyboardState);
+ break;
}
if (!continueProcessingActions) {
return FALSE;
diff --git a/windows/src/engine/keyman32/kmprocessactions.h b/windows/src/engine/keyman32/kmprocessactions.h
index e96f2226d1..80827ea623 100644
--- a/windows/src/engine/keyman32/kmprocessactions.h
+++ b/windows/src/engine/keyman32/kmprocessactions.h
@@ -18,12 +18,12 @@ BOOL ProcessActions(BOOL* emitKeyStroke);
/**
* This function process the actions queued in the core processor in
- * the non updateable parse of a keystroke.
- * Emit keystroke and capslock are required to be processed in this phase.
+ * the non-updateable parse of a keystroke.
+ * Emit keystroke, capslock and possibly invalidate key stroke are required to be processed in this parse.
*
* @param [in, out] emitKeyStroke is set to true if requested by the core action queue
* @return BOOL True if actions were successfully processed
*/
-BOOL ProcessActionsTestParse(BOOL* emitKeyStroke);
+BOOL ProcessActionsNonUpdatableParse(BOOL* emitKeyStroke);
#endif