mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-07 08:07:43 +00:00
chore: Merge branch 'feat/developer/ldml-compiler-kmx-builder' in
This commit is contained in:
commit
e84bd590b0
24 changed files with 247 additions and 134 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
16.0.50
|
||||
16.0.51
|
||||
|
|
@ -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:")) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -247,4 +247,7 @@
|
|||
<!-- Context: KMP Package strings -->
|
||||
<string name="minimum_keyboard_version_not_supported" comment="Notification when keyboard has functionality not supported by current Keyman">
|
||||
Keyboard requires a newer version of Keyman</string>
|
||||
|
||||
<!-- Context: anywhere -->
|
||||
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">Unable to launch web browser</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
<!-- Device type -->
|
||||
<string name="device_type" translatable="false">AndroidMobile</string>
|
||||
|
||||
|
||||
<!-- Application name (Keyman Engine for Android) -->
|
||||
<string name="app_name" translatable="false">KMEA</string>
|
||||
|
||||
|
||||
<!-- Context: Title for list -->
|
||||
<plurals name="title_keyboards">
|
||||
<item quantity="one">Keyboard</item>
|
||||
|
|
@ -267,4 +267,6 @@
|
|||
<!-- Context: Other strings -->
|
||||
<string name="help_bubble_text">Tap here to change keyboard</string>
|
||||
|
||||
<!-- Context: anywhere -->
|
||||
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">Unable to launch web browser</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define snprintf _snprintf
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
},
|
||||
|
||||
};
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -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}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,14 @@
|
|||
Implementation for the KMX Plus utilities
|
||||
*/
|
||||
|
||||
#include <km_types.h>
|
||||
#include <kmx_file.h>
|
||||
#include <kmx/kmx_plus.h>
|
||||
|
||||
/**
|
||||
* @def KMXPLUS_DEBUG Set to 1 to enable debug output
|
||||
*/
|
||||
#define KMXPLUS_DEBUG 1
|
||||
#define KMXPLUS_DEBUG 0
|
||||
|
||||
#if KMXPLUS_DEBUG
|
||||
#include <stdio.h>
|
||||
|
|
@ -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; i<strs->count; 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<const uint8_t*>(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;
|
||||
|
|
|
|||
|
|
@ -7,13 +7,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <kmx/kmx_file.h>
|
||||
#include <km_types.h>
|
||||
#include <kmx/kmx_base.h>
|
||||
#include <kmx_file.h>
|
||||
#include <ldml/keyboardprocessor_ldml.h>
|
||||
|
||||
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<const COMP_KMXPLUS_HEADER *>(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<const COMP_KMXPLUS_SECT *>(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<const COMP_KMXPLUS_STRS *>(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<const COMP_KMXPLUS_KEYS *>(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<const COMP_KMXPLUS_LOCA *>(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<const COMP_KMXPLUS_META *>(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<const COMP_KMXPLUS_VKEY *>(all);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
#include <fstream>
|
||||
#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<BUFSIZ && out[len]; len++);
|
||||
} else {
|
||||
|
|
@ -211,7 +215,7 @@ ldml_processor::process_event(
|
|||
// len = (targetStart - out);
|
||||
assert(len>=1 && len <= 2);
|
||||
}
|
||||
assert(len>=0);
|
||||
assert(len>0);
|
||||
assert(len<BUFSIZ);
|
||||
assert(out[len] == 0); // null termination
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,6 +1,6 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <kmx/kmx_plus.h>
|
||||
#include "kmx/kmx_plus.h"
|
||||
|
||||
using namespace km::kbp::kmx;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -42,4 +42,6 @@
|
|||
<!-- Context: KMP Package strings -->
|
||||
<string name="invalid_metadata" comment="kmp.json metadata file is invalid or missing in package">Invalid/Missing metadata in package</string>
|
||||
|
||||
<!-- Context: anywhere -->
|
||||
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">Unable to launch web browser</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ BOOL ProcessHook()
|
|||
}
|
||||
|
||||
if (!_td->TIPFUpdateable) {
|
||||
ProcessActionsTestParse(&fOutputKeystroke);
|
||||
ProcessActionsNonUpdatableParse(&fOutputKeystroke);
|
||||
} else {
|
||||
ProcessActions(&fOutputKeystroke);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue