chore(developer): Merge branch 'master' into test/developer/kmcmplib-compiler-unit-tests

This commit is contained in:
Dr Mark C. Sinclair 2024-05-13 10:24:13 +01:00
commit 810c9720d3
98 changed files with 740 additions and 440 deletions

View file

@ -1,5 +1,28 @@
# Keyman Version History
## 18.0.33 alpha 2024-05-10
* chore(common): Merge beta to master for Sprint A18S1 (part 2) (#11413)
## 18.0.32 alpha 2024-05-09
* chore(common): Add `minimum-versions.inc.sh` (#11380)
* chore(core): km_core_cp -> km_core_cu (#11341)
## 18.0.31 alpha 2024-05-08
* fix(windows): "Keyboard" should be lower case in UI string for font helper tool (#11392)
## 18.0.30 alpha 2024-05-07
* chore(web): Improve dependencies (#11377)
* test(developer) keyboard info compiler unit tests 3 (#11255)
## 18.0.29 alpha 2024-05-06
* chore(web): Improve web/test.sh script (#11355)
* chore(linux): Fix typo (#11356)
## 18.0.28 alpha 2024-05-04
* chore(common): maintenance on build scripts - cd (#11329)
@ -121,6 +144,32 @@
* chore(common): move to 18.0 alpha (#10713)
* chore: move to 18.0 alpha
## 17.0.322 beta 2024-05-10
* fix(web): fixes illegal KMW event state - can't focus a null element (#11385)
## 17.0.321 beta 2024-05-09
* fix(android/engine): Skip updating selection range if invalid (#11384)
* refactor(android/engine): Refactor updateSelection (#11389)
## 17.0.320 beta 2024-05-07
* fix(android): prevents mid-keystroke desynchronization when deleting selected text (#11367)
* fix(web): support SVG elements when checking className (#11365)
* fix(developer): define `lastSelLength` variable (#11366)
## 17.0.319 beta 2024-05-04
* fix(android): inverting a selection range would crash Keyman (#11345)
* fix(developer): handle missing Name element for File element in package compiler (#11352)
* fix(developer): handle missing Description element for File element in package compiler (#11354)
## 17.0.318 beta 2024-05-02
* fix(web): longpress shortcut activation should only consider northward part (#11306)
* chore(ios,mac): support build on Apple Silicon using Xcode 15.3 (#11302)
## 17.0.317 beta 2024-05-01
* (#11322)

View file

@ -1 +1 @@
18.0.29
18.0.34

View file

@ -57,6 +57,7 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
if (DependencyUtil.libraryExists(LibraryType.SENTRY) && !Sentry.isEnabled()) {
Log.d(TAG, "Initializing Sentry");
SentryAndroid.init(getApplicationContext(), options -> {
options.setEnableAutoSessionTracking(false);
options.setRelease(com.tavultesoft.kmapro.BuildConfig.VERSION_GIT_TAG);
options.setEnvironment(com.tavultesoft.kmapro.BuildConfig.VERSION_ENVIRONMENT);
});

View file

@ -141,6 +141,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
checkSendCrashReport();
if (KMManager.getMaySendCrashReport()) {
SentryAndroid.init(context, options -> {
options.setEnableAutoSessionTracking(false);
options.setRelease(com.tavultesoft.kmapro.BuildConfig.VERSION_GIT_TAG);
options.setEnvironment(com.tavultesoft.kmapro.BuildConfig.VERSION_ENVIRONMENT);
});

View file

@ -170,51 +170,63 @@ final class KMKeyboard extends WebView {
return result;
}
/**
* Updates the selection range of the current context.
* Returns boolean - true if the selection range was updated successfully
*/
protected boolean updateSelectionRange() {
boolean result = false;
InputConnection ic = KMManager.getInputConnection(this.keyboardType);
if (ic != null) {
ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0);
if (icText == null) {
return false;
}
String rawText = icText.text.toString();
updateText(rawText.toString());
int selStart = icText.selectionStart;
int selEnd = icText.selectionEnd;
int selMin = selStart, selMax = selEnd;
if (selStart > selEnd) {
// Selection is reversed so "swap"
selMin = selEnd;
selMax = selStart;
}
/*
The values of selStart & selEnd provided by the system are in code units,
not code-points. We need to account for surrogate pairs here.
Fortunately, it uses UCS-2 encoding... just like JS.
References:
- https://stackoverflow.com/a/23980211
- https://android.googlesource.com/platform/frameworks/base/+/152944f/core/java/android/view/inputmethod/InputConnection.java#326
*/
// Count the number of characters which are surrogate pairs.
int pairsAtStart = CharSequenceUtil.countSurrogatePairs(rawText.substring(0, selStart), rawText.length());
String selectedText = rawText.substring(selStart, selEnd);
int pairsSelected = CharSequenceUtil.countSurrogatePairs(selectedText, selectedText.length());
selStart -= pairsAtStart;
selEnd -= (pairsAtStart + pairsSelected);
this.loadJavascript(KMString.format("updateKMSelectionRange(%d,%d)", selStart, selEnd));
if (ic == null) {
// Unable to get connection to the text
return false;
}
result = true;
return result;
ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0);
if (icText == null) {
// Failed to get text becausee either input connection became invalid or client is taking too long to respond
// https://developer.android.com/reference/android/view/inputmethod/InputConnection#getExtractedText(android.view.inputmethod.ExtractedTextRequest,%20int)
return false;
}
String rawText = icText.text.toString();
updateText(rawText.toString());
int selMin = icText.selectionStart, selMax = icText.selectionEnd;
if (selMin < 0 || selMax < 0) {
// There is no selection or cursor
// Reference https://developer.android.com/reference/android/text/Selection#getSelectionEnd(java.lang.CharSequence)
return false;
}
if (selMin > selMax) {
// Selection is reversed so "swap"
selMin = icText.selectionEnd;
selMax = icText.selectionStart;
}
/*
The values of selStart & selEnd provided by the system are in code units,
not code-points. We need to account for surrogate pairs here.
Fortunately, it uses UCS-2 encoding... just like JS.
References:
- https://stackoverflow.com/a/23980211
- https://android.googlesource.com/platform/frameworks/base/+/152944f/core/java/android/view/inputmethod/InputConnection.java#326
*/
// Count the number of characters which are surrogate pairs.
int pairsAtStart = CharSequenceUtil.countSurrogatePairs(rawText.substring(0, selMin), rawText.length());
String selectedText = rawText.substring(selMin, selMax);
int pairsSelected = CharSequenceUtil.countSurrogatePairs(selectedText, selectedText.length());
selMin -= pairsAtStart;
selMax -= (pairsAtStart + pairsSelected);
this.loadJavascript(KMString.format("updateKMSelectionRange(%d,%d)", selMin, selMax));
return true;
}

View file

@ -135,13 +135,13 @@ public class KMKeyboardJSHandler {
end = temp;
}
if (end > start) {
k.setShouldIgnoreSelectionChange(true);
if (s.length() == 0) {
ic.setSelection(start, start);
ic.deleteSurroundingText(0, end - start);
ic.endBatchEdit();
return;
} else {
k.setShouldIgnoreSelectionChange(true);
ic.setSelection(start, start);
ic.deleteSurroundingText(0, end - start);
}

View file

@ -28,14 +28,14 @@ typedef uint8_t KMX_BYTE;
typedef uint16_t KMX_WORD;
#if defined(__cplusplus)
typedef char16_t km_core_cp;
typedef char16_t km_core_cu;
typedef char32_t km_core_usv;
#else
typedef uint16_t km_core_cp; // code point
typedef uint16_t km_core_cu; // code unit
typedef uint32_t km_core_usv; // Unicode Scalar Value
#endif
typedef km_core_cp KMX_WCHAR; // wc, 16-bit UNICODE character
typedef km_core_cu KMX_WCHAR; // wc, 16-bit UNICODE character
typedef KMX_WCHAR* PKMX_WCHAR;
typedef char KMX_CHAR;
@ -60,7 +60,7 @@ typedef KMX_DWORD* PKMX_DWORD;
#ifdef USE_CHAR16_T
#define lpuch(x) u ## x
typedef km_core_cp KMX_UCHAR;
typedef km_core_cu KMX_UCHAR;
#else
#define lpuch(x) L ## x
typedef wchar_t KMX_UCHAR;

View file

@ -8,6 +8,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
builder_describe "Build Keyman common file types module" \
"@/core/include/ldml" \
"@/common/web/keyman-version" \
"configure" \
"build" \

View file

@ -29,6 +29,7 @@
"url": "https://github.com/keymanapp/keyman/issues"
},
"dependencies": {
"@keymanapp/ldml-keyboard-constants": "*",
"@keymanapp/keyman-version": "*",
"restructure": "git+https://github.com/keymanapp/dependency-restructure.git#7a188a1e26f8f36a175d95b67ffece8702363dfc",
"semver": "^7.5.2",

View file

@ -1 +1 @@
1.0.0
2.0.0

View file

@ -205,7 +205,7 @@ interface.
Fundamental types for representing data passed across the API.
### km_core_cp type
### km_core_cu type
`uint16_t/char16_t`
@ -683,7 +683,7 @@ KMN_API
km_core_context_status
km_core_state_context_set_if_needed(
km_core_state *state,
km_core_cp const *application_context
km_core_cu const *application_context
);
/*
@ -800,8 +800,8 @@ Platform layer.
## Specification
```c */
struct km_core_option_item {
km_core_cp const * key;
km_core_cp const * value;
km_core_cu const * key;
km_core_cu const * value;
uint8_t scope;
};
@ -860,8 +860,8 @@ KMN_API
km_core_status
km_core_state_option_lookup(km_core_state const *state,
uint8_t scope,
km_core_cp const *key,
km_core_cp const **value);
km_core_cu const *key,
km_core_cu const **value);
/*
```
@ -1005,8 +1005,8 @@ Provides read-only information about a keyboard.
```c
*/
typedef struct {
km_core_cp const * version_string;
km_core_cp const * id;
km_core_cu const * version_string;
km_core_cu const * id;
km_core_path_name folder_path;
km_core_option_item const * default_options;
} km_core_keyboard_attrs;
@ -1070,8 +1070,8 @@ Describes a single Input Method eXtension library and entry point.
```c */
typedef struct {
km_core_cp const * library_name;
km_core_cp const * function_name;
km_core_cu const * library_name;
km_core_cu const * function_name;
uint32_t imx_id;
} km_core_keyboard_imx;
@ -1332,7 +1332,7 @@ void km_core_state_imx_register_callback(km_core_state *state, km_core_keyboard_
: pointer to a function that implements the IMX callback
`callback_object`
: An opaque pointer that can be used to pass context information to the callback function,
: An opaque pointer that can be used to pass context information to the callback function,
usually it is a user-defined data structure.
-------------------------------------------------------------------------------
@ -1523,7 +1523,7 @@ Returns a debug formatted string of the context from the state.
```c */
KMN_API
km_core_cp *
km_core_cu *
km_core_state_context_debug(km_core_state *state, km_core_debug_context_type context_type);
/*
@ -1538,16 +1538,16 @@ km_core_state_context_debug(km_core_state *state, km_core_debug_context_type con
## Returns
A pointer to a [km_core_cp] UTF-16 string. Must be disposed of by a call
to [km_core_cp_dispose].
A pointer to a [km_core_cu] UTF-16 string. Must be disposed of by a call
to [km_core_cu_dispose].
-------------------------------------------------------------------------------
# km_core_cp_dispose()
# km_core_cu_dispose()
## Description
Free the allocated memory belonging to a [km_core_cp] array previously
Free the allocated memory belonging to a [km_core_cu] array previously
returned by [km_core_state_context_debug]. May be `nullptr`.
## Specification
@ -1555,14 +1555,14 @@ returned by [km_core_state_context_debug]. May be `nullptr`.
```c */
KMN_API
void
km_core_cp_dispose(km_core_cp *cp);
km_core_cu_dispose(km_core_cu *cp);
/*
```
## Parameters
`cp`
: A pointer to the start of the [km_core_cp] array to be disposed of.
: A pointer to the start of the [km_core_cu] array to be disposed of.
-------------------------------------------------------------------------------

View file

@ -24,7 +24,7 @@ extern "C"
#endif
/**
* The maximum size of context in km_core_cp units for a single debug
* The maximum size of context in km_core_cu units for a single debug
* event. This is taken from MAXCONTEXT in keyman32 (Windows) and is purely
* a convenience value. We can increase it if there is a demonstrated need.
*/
@ -65,7 +65,7 @@ typedef struct {
*/
typedef struct {
void *store; // LPSTORE
km_core_cp value[DEBUG_MAX_CONTEXT]; // value to be saved into the store
km_core_cu value[DEBUG_MAX_CONTEXT]; // value to be saved into the store
} km_core_state_debug_kmx_option_info;
/**
@ -80,7 +80,7 @@ typedef struct {
*/
typedef struct {
km_core_cp context[DEBUG_MAX_CONTEXT]; // The context matched by the rule (? may not need this?) // TODO: rename to context_matched
km_core_cu context[DEBUG_MAX_CONTEXT]; // The context matched by the rule (? may not need this?) // TODO: rename to context_matched
void *group; // LPGROUP
void *rule; // LPKEY
uint16_t store_offsets[DEBUG_STORE_OFFSETS_SIZE]; // pairs--store, char position, terminated by 0xFFFF // TODO use a better structure here

View file

@ -45,8 +45,8 @@ void context::push_marker(uint32_t marker) {
// Context helper functions
km_core_cp* get_context_as_string(km_core_context *context);
km_core_status set_context_from_string(km_core_context *context, km_core_cp const *new_context);
km_core_cu* get_context_as_string(km_core_context *context);
km_core_status set_context_from_string(km_core_context *context, km_core_cu const *new_context);
} // namespace core
} // namespace km
@ -84,7 +84,7 @@ struct km_core_context : public km::core::context
* `km_core_context_items_dispose`.
*/
km_core_status
context_items_from_utf16(km_core_cp const *text,
context_items_from_utf16(km_core_cu const *text,
km_core_context_item **out_ptr);
/**
@ -113,7 +113,7 @@ context_items_from_utf16(km_core_cp const *text,
*/
km_core_status
context_items_to_utf16(km_core_context_item const *item,
km_core_cp *buf,
km_core_cu *buf,
size_t *buf_size);
/**

View file

@ -13,9 +13,9 @@
using namespace km::core;
/**
* Retrieves the context as a km_core_cp string, dropping markers
* Retrieves the context as a km_core_cu string, dropping markers
*/
km_core_cp* km::core::get_context_as_string(km_core_context *context) {
km_core_cu* km::core::get_context_as_string(km_core_context *context) {
assert(context != nullptr);
if(context == nullptr) {
return nullptr;
@ -33,7 +33,7 @@ km_core_cp* km::core::get_context_as_string(km_core_context *context) {
return nullptr;
}
km_core_cp *app_context_string = new km_core_cp[buf_size];
km_core_cu *app_context_string = new km_core_cu[buf_size];
km_core_status status = context_items_to_utf16(context_items, app_context_string, &buf_size);
km_core_context_items_dispose(context_items);
@ -46,9 +46,9 @@ km_core_cp* km::core::get_context_as_string(km_core_context *context) {
}
/**
* Updates the context from the new_context km_core_cp string
* Updates the context from the new_context km_core_cu string
*/
km_core_status km::core::set_context_from_string(km_core_context *context, km_core_cp const *new_context) {
km_core_status km::core::set_context_from_string(km_core_context *context, km_core_cu const *new_context) {
assert(context != nullptr);
assert(new_context != nullptr);
if(context == nullptr || new_context == nullptr) {

View file

@ -108,7 +108,7 @@ namespace {
}
km_core_status
context_items_from_utf16(km_core_cp const *text,
context_items_from_utf16(km_core_cu const *text,
km_core_context_item **out_ptr)
{
return _context_items_from<utf16>(reinterpret_cast<utf16::codeunit_t const *>(text), out_ptr);
@ -125,7 +125,7 @@ km_core_status context_items_to_utf8(km_core_context_item const *ci,
km_core_status context_items_to_utf16(km_core_context_item const *ci,
km_core_cp *buf, size_t * sz_ptr)
km_core_cu *buf, size_t * sz_ptr)
{
return _context_items_to<utf16>(ci,
reinterpret_cast<utf16::codeunit_t *>(buf),

View file

@ -36,8 +36,8 @@ km_core_options_list_size(km_core_option_item const *opts)
km_core_status
km_core_state_option_lookup(km_core_state const *state,
uint8_t scope, km_core_cp const *key,
km_core_cp const **value_out)
uint8_t scope, km_core_cu const *key,
km_core_cu const **value_out)
{
assert(state); assert(key); assert(value_out);
if (!state || !key || !value_out) return KM_CORE_STATUS_INVALID_ARGUMENT;

View file

@ -285,22 +285,22 @@ km_core_status km_core_state_context_clear(
return KM_CORE_STATUS_OK;
}
void km_core_cp_dispose(
km_core_cp *cp
void km_core_cu_dispose(
km_core_cu *cp
) {
if(cp != nullptr) {
delete [] cp;
}
}
km_core_cp * _new_error_string(std::u16string const str) {
km_core_cp* result = new km_core_cp[str.size()+1];
km_core_cu * _new_error_string(std::u16string const str) {
km_core_cu* result = new km_core_cu[str.size()+1];
str.copy(result, str.size());
result[str.size()] = 0;
return result;
}
km_core_cp * km_core_state_context_debug(
km_core_cu * km_core_state_context_debug(
km_core_state *state,
km_core_debug_context_type context_type
) {
@ -359,7 +359,7 @@ km_core_cp * km_core_state_context_debug(
std::u16string s = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(buffer.str());
km_core_cp* result = new km_core_cp[s.size() + 1];
km_core_cu* result = new km_core_cu[s.size() + 1];
s.copy(result, s.size());
result[s.size()] = 0;
@ -385,11 +385,11 @@ state_should_invalidate_context(km_core_state *state,
// if emit_keystroke is present, check if a context reset is needed
if (state_has_action_type(state, KM_CORE_IT_EMIT_KEYSTROKE)) {
if (
// when a backspace keystroke is emitted, it is because we are at the start of
// context, and we want to give the application the chance to process it, e.g.
// by moving to previous field. Note that context manipulation does not result
// in an emit_keystroke backspace action, as this is handled through the
// `code_points_to_delete` field. So we always invalidate context when a
// when a backspace keystroke is emitted, it is because we are at the start of
// context, and we want to give the application the chance to process it, e.g.
// by moving to previous field. Note that context manipulation does not result
// in an emit_keystroke backspace action, as this is handled through the
// `code_points_to_delete` field. So we always invalidate context when a
// processor emits a backspace.
vk == KM_CORE_VKEY_BKSP ||
// certain modifiers invalidate context

View file

@ -39,12 +39,12 @@ typedef struct {
// Forward declarations
bool replace_context(context_change_result context_change, km_core_context *context, km_core_cp const *new_context);
bool replace_context(context_change_result context_change, km_core_context *context, km_core_cu const *new_context);
bool should_normalize(km_core_state *state);
context_change_result get_context_change(km_core_cp const *new_context, km_core_context *context);
context_change_result get_context_change(km_core_cu const *new_context, km_core_context *context);
context_change_result get_context_items_change(km_core_context_item *new_context_items, km_core_context_item *context_items);
bool do_normalize_nfd(km_core_cp const * src, std::u16string &dst);
bool do_normalize_nfd(km_core_cu const * src, std::u16string &dst);
km_core_context_status do_fail(km_core_context *app_context, km_core_context *cached_context, const char* error);
// ---------------------------------------------------------------------------
@ -52,7 +52,7 @@ km_core_context_status do_fail(km_core_context *app_context, km_core_context *ca
km_core_context_status
km_core_state_context_set_if_needed(
km_core_state *state,
km_core_cp const *new_app_context
km_core_cu const *new_app_context
) {
assert(state != nullptr);
assert(new_app_context != nullptr);
@ -91,7 +91,7 @@ km_core_state_context_set_if_needed(
// Finally, we normalize and replace the cached context
std::u16string normalized_buffer;
km_core_cp const *new_cached_context = nullptr;
km_core_cu const *new_cached_context = nullptr;
if (should_normalize(state)) {
if (!do_normalize_nfd(new_app_context, normalized_buffer)) {
@ -128,7 +128,7 @@ bool
replace_context(
context_change_result context_change,
km_core_context *context,
km_core_cp const *new_context
km_core_cu const *new_context
) {
if (context_change.type == CONTEXT_DIFFERENT) {
if (set_context_from_string(context, new_context) != KM_CORE_STATUS_OK) {
@ -189,7 +189,7 @@ context_previous_char(
*/
context_change_result
get_context_change(
km_core_cp const *new_context_string,
km_core_cu const *new_context_string,
km_core_context *context
) {
context_change_result change_type({CONTEXT_DIFFERENT, 0});
@ -286,7 +286,7 @@ get_context_items_change(
/**
* Normalize the input string using ICU
*/
bool do_normalize_nfd(km_core_cp const * src, std::u16string &dst) {
bool do_normalize_nfd(km_core_cu const * src, std::u16string &dst) {
UErrorCode icu_status = U_ZERO_ERROR;
const icu::Normalizer2 *nfd = icu::Normalizer2::getNFDInstance(icu_status);
assert(U_SUCCESS(icu_status));

View file

@ -61,7 +61,7 @@ void KMX_DebugItems::fill_store_offsets(km_core_state_debug_kmx_info *info, PKMX
int i, n;
km_core_cp *p;
km_core_cu *p;
// TODO turn this into a struct rather than interwoven values
for(i = n = 0, p = static_cast<LPKEY>(info->rule)->dpContext; p && *p; p = incxstr(p), i++) {

View file

@ -11,7 +11,7 @@ using namespace km::core;
using namespace kmx;
namespace {
km_core_cp const
km_core_cu const
*DEFAULT_PLATFORM = u"windows hardware desktop native",
*DEFAULT_BASELAYOUT = u"kbdus.dll",
*DEFAULT_BASELAYOUTALT = u"en-US",

View file

@ -15,8 +15,8 @@ private:
std::u16string _platform;
void InitOption(
std::vector<option> & default_env,
km_core_cp const * key,
km_core_cp const * default_value);
km_core_cu const * key,
km_core_cu const * default_value);
public:
KMX_Environment();
void Set(std::u16string const & key, std::u16string const & value);

View file

@ -535,8 +535,8 @@ int KMX_ProcessEvent::PostString(PKMX_WCHAR str, LPKEYBOARD lpkb, PKMX_WCHAR end
KMX_BOOL KMX_ProcessEvent::IsMatchingBaseLayout(PKMX_WCHAR layoutName) // I3432
{
KMX_BOOL bEqual = u16icmp(layoutName, static_cast<const km_core_cp *>(m_environment.baseLayout().c_str())) == 0 || // I4583
u16icmp(layoutName, static_cast<const km_core_cp*>(m_environment.baseLayoutAlt().c_str())) == 0; // I4583
KMX_BOOL bEqual = u16icmp(layoutName, static_cast<const km_core_cu *>(m_environment.baseLayout().c_str())) == 0 || // I4583
u16icmp(layoutName, static_cast<const km_core_cu*>(m_environment.baseLayoutAlt().c_str())) == 0; // I4583
return bEqual;
}

View file

@ -12,7 +12,7 @@
using namespace km::core;
using namespace kmx;
const km_core_cp *km::core::kmx::u16chr(const km_core_cp *p, km_core_cp ch) {
const km_core_cu *km::core::kmx::u16chr(const km_core_cu *p, km_core_cu ch) {
while (*p) {
if (*p == ch) return p;
p++;
@ -20,8 +20,8 @@ const km_core_cp *km::core::kmx::u16chr(const km_core_cp *p, km_core_cp ch) {
return ch == 0 ? p : NULL;
}
const km_core_cp *km::core::kmx::u16cpy(km_core_cp *dst, const km_core_cp *src) {
km_core_cp *o = dst;
const km_core_cu *km::core::kmx::u16cpy(km_core_cu *dst, const km_core_cu *src) {
km_core_cu *o = dst;
while (*src) {
*dst++ = *src++;
}
@ -29,8 +29,8 @@ const km_core_cp *km::core::kmx::u16cpy(km_core_cp *dst, const km_core_cp *src)
return o;
}
const km_core_cp *km::core::kmx::u16ncpy(km_core_cp *dst, const km_core_cp *src, size_t max) {
km_core_cp *o = dst;
const km_core_cu *km::core::kmx::u16ncpy(km_core_cu *dst, const km_core_cu *src, size_t max) {
km_core_cu *o = dst;
while (*src && max > 0) {
*dst++ = *src++;
max--;
@ -42,7 +42,7 @@ const km_core_cp *km::core::kmx::u16ncpy(km_core_cp *dst, const km_core_cp *src,
return o;
}
size_t km::core::kmx::u16len(const km_core_cp *p) {
size_t km::core::kmx::u16len(const km_core_cu *p) {
int i = 0;
while (*p) {
p++;
@ -51,7 +51,7 @@ size_t km::core::kmx::u16len(const km_core_cp *p) {
return i;
}
int km::core::kmx::u16cmp(const km_core_cp *p, const km_core_cp *q) {
int km::core::kmx::u16cmp(const km_core_cu *p, const km_core_cu *q) {
while (*p && *q) {
if (*p != *q) return *p - *q;
p++;
@ -60,7 +60,7 @@ int km::core::kmx::u16cmp(const km_core_cp *p, const km_core_cp *q) {
return *p - *q;
}
int km::core::kmx::u16icmp(const km_core_cp *p, const km_core_cp *q) {
int km::core::kmx::u16icmp(const km_core_cu *p, const km_core_cu *q) {
while (*p && *q) {
if (toupper(*p) != toupper(*q)) return *p - *q;
p++;
@ -69,7 +69,7 @@ int km::core::kmx::u16icmp(const km_core_cp *p, const km_core_cp *q) {
return *p - *q;
}
int km::core::kmx::u16ncmp(const km_core_cp *p, const km_core_cp *q, size_t count) {
int km::core::kmx::u16ncmp(const km_core_cu *p, const km_core_cu *q, size_t count) {
while (*p && *q && count) {
if (*p != *q) return *p - *q;
p++;
@ -81,13 +81,13 @@ int km::core::kmx::u16ncmp(const km_core_cp *p, const km_core_cp *q, size_t coun
return 0;
}
km_core_cp *km::core::kmx::u16tok(km_core_cp *p, km_core_cp ch, km_core_cp **ctx) {
km_core_cu *km::core::kmx::u16tok(km_core_cu *p, km_core_cu ch, km_core_cu **ctx) {
if (!p) {
p = *ctx;
if (!p) return NULL;
}
km_core_cp *q = p;
km_core_cu *q = p;
while (*q && *q != ch) {
q++;
}
@ -103,9 +103,9 @@ km_core_cp *km::core::kmx::u16tok(km_core_cp *p, km_core_cp ch, km_core_cp **ctx
return p;
}
km_core_cp *km::core::kmx::u16dup(km_core_cp *src) {
km_core_cp *dup = new km_core_cp[u16len(src) + 1];
memcpy(dup, src, (u16len(src) + 1) * sizeof(km_core_cp));
km_core_cu *km::core::kmx::u16dup(km_core_cu *src) {
km_core_cu *dup = new km_core_cu[u16len(src) + 1];
memcpy(dup, src, (u16len(src) + 1) * sizeof(km_core_cu));
return dup;
}

View file

@ -107,15 +107,15 @@ int xchrcmp(PKMX_WCHAR ch1, PKMX_WCHAR ch2);
PKMX_CHAR wstrtostr(PKMX_WCHAR in);
PKMX_WCHAR strtowstr(PKMX_CHAR in);
const km_core_cp *u16chr(const km_core_cp *p, km_core_cp ch);
const km_core_cp *u16cpy(km_core_cp *dst, const km_core_cp *src); // TODO: deprecate all usages
const km_core_cp *u16ncpy(km_core_cp *dst, const km_core_cp *src, size_t max);
size_t u16len(const km_core_cp *p);
int u16cmp(const km_core_cp *p, const km_core_cp *q);
int u16icmp(const km_core_cp *p, const km_core_cp *q);
int u16ncmp(const km_core_cp *p, const km_core_cp *q, size_t count);
km_core_cp *u16tok(km_core_cp *p, km_core_cp ch, km_core_cp **ctx);
km_core_cp *u16dup(km_core_cp *src);
const km_core_cu *u16chr(const km_core_cu *p, km_core_cu ch);
const km_core_cu *u16cpy(km_core_cu *dst, const km_core_cu *src); // TODO: deprecate all usages
const km_core_cu *u16ncpy(km_core_cu *dst, const km_core_cu *src, size_t max);
size_t u16len(const km_core_cu *p);
int u16cmp(const km_core_cu *p, const km_core_cu *q);
int u16icmp(const km_core_cu *p, const km_core_cu *q);
int u16ncmp(const km_core_cu *p, const km_core_cu *q, size_t count);
km_core_cu *u16tok(km_core_cu *p, km_core_cu ch, km_core_cu **ctx);
km_core_cu *u16dup(km_core_cu *src);
//KMX_BOOL MapUSCharToVK(KMX_WORD ch, PKMX_WORD puKey, PKMX_DWORD puShiftFlags);

View file

@ -32,8 +32,8 @@ option::option(km_core_option_scope s, char16_t const *k, char16_t const *v)
{
auto n_k = std::char_traits<char16_t>::length(k)+1,
n_v = std::char_traits<char16_t>::length(v)+1;
auto _key = new km_core_cp[n_k],
_val = new km_core_cp[n_v];
auto _key = new km_core_cu[n_k],
_val = new km_core_cu[n_v];
std::copy_n(k, n_k, _key);
std::copy_n(v, n_v, _val);

View file

@ -62,10 +62,10 @@ KmxTestSource::parse_source_string(std::string const &s) {
assert(v >= 0x0001 && v <= 0x10FFFF);
p += n - 1;
if (v < 0x10000) {
t += km_core_cp(v);
t += km_core_cu(v);
} else {
t += km_core_cp(Uni_UTF32ToSurrogate1(v));
t += km_core_cp(Uni_UTF32ToSurrogate2(v));
t += km_core_cu(Uni_UTF32ToSurrogate1(v));
t += km_core_cu(Uni_UTF32ToSurrogate2(v));
}
} else if (*p == 'd') {
// Deadkey
@ -191,13 +191,13 @@ KmxTestSource::get_keyboard_options(kmx_options options) {
keyboard_opts[i].scope = KM_CORE_OPT_KEYBOARD;
}
km_core_cp *cp = new km_core_cp[key.length() + 1];
km_core_cu *cp = new km_core_cu[key.length() + 1];
key.copy(cp, key.length());
cp[key.length()] = 0;
keyboard_opts[i].key = cp;
cp = new km_core_cp[it->value.length() + 1];
cp = new km_core_cu[it->value.length() + 1];
it->value.copy(cp, it->value.length());
cp[it->value.length()] = 0;

View file

@ -53,7 +53,7 @@ void teardown() {
}
}
void setup(const char *keyboard, const km_core_cp* context) {
void setup(const char *keyboard, const km_core_cu* context) {
teardown();
km::core::path path = km::core::path::join(arg_path, keyboard);

View file

@ -52,14 +52,14 @@ int main(int, char * [])
// Check context_item to UTF16 conversion, roundtrip test.
char16_t ctxt_buffer[512] ={0,};
// First call measure space 2nd call do conversion.
size_t ctxt_size = sizeof ctxt_buffer/sizeof(km_core_cp);
size_t ctxt_size = sizeof ctxt_buffer/sizeof(km_core_cu);
try_status(context_items_to_utf16(ctxt1, nullptr, &ctxt_size));
if (ctxt_size > sizeof ctxt_buffer/sizeof(km_core_cp)) return __LINE__;
if (ctxt_size > sizeof ctxt_buffer/sizeof(km_core_cu)) return __LINE__;
try_status(context_items_to_utf16(ctxt1, ctxt_buffer, &ctxt_size));
if (initial_bmp_context != ctxt_buffer) return __LINE__;
// Test roundtripping SMP characters in surrogate pairs.
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cp);
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cu);
try_status(context_items_to_utf16(ctxt2, ctxt_buffer, &ctxt_size));
if (initial_smp_context != ctxt_buffer) return __LINE__;
// Test buffer overrun protection.
@ -85,14 +85,14 @@ int main(int, char * [])
// retrieve bmp context and check it's okay.
km_core_context_item *tmp_ctxt;
try_status(km_core_context_get(&mock_ctxt1, &tmp_ctxt));
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cp);
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cu);
try_status(context_items_to_utf16(tmp_ctxt, ctxt_buffer, &ctxt_size));
km_core_context_items_dispose(tmp_ctxt);
if (initial_bmp_context != ctxt_buffer) return __LINE__;
// retrieve smp context and check it's okay.
try_status(km_core_context_get(&mock_ctxt2, &tmp_ctxt));
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cp);
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cu);
try_status(context_items_to_utf16(tmp_ctxt, ctxt_buffer, &ctxt_size));
km_core_context_items_dispose(tmp_ctxt);
if (initial_smp_context != ctxt_buffer) return __LINE__;
@ -116,7 +116,7 @@ int main(int, char * [])
km_core_context_items_dispose(ctxt2);
// Check it matches. The marker will be elided during the conversion.
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cp);
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cu);
try_status(km_core_context_get(&mock_ctxt1, &tmp_ctxt));
try_status(context_items_to_utf16(tmp_ctxt, ctxt_buffer, &ctxt_size));
if (std::u16string(u"Hello World!") != ctxt_buffer) return __LINE__;
@ -128,7 +128,7 @@ int main(int, char * [])
// expected if you go by the test string above.
try_status(context_shrink(&mock_ctxt1, 8));
try_status(context_prepend(&mock_ctxt1, ctxt1, 8));
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cp);
ctxt_size=sizeof ctxt_buffer/sizeof(km_core_cu);
try_status(km_core_context_get(&mock_ctxt1, &tmp_ctxt));
try_status(context_items_to_utf16(tmp_ctxt, ctxt_buffer, &ctxt_size));
if (std::u16string(u"Bye, Hello") != ctxt_buffer) return __LINE__;

View file

@ -79,7 +79,7 @@ namespace
bool _assert_lookup_equals(std::u16string const key, std::u16string value, km_core_option_scope scope)
{
km_core_cp const * ret = nullptr;
km_core_cu const * ret = nullptr;
auto s = km_core_state_option_lookup(api_mock_options, scope,
key.c_str(),
&ret);
@ -129,7 +129,7 @@ int main(int, char * [])
return __LINE__;
#if 0
km_core_cp const *value;
km_core_cu const *value;
auto s = km_core_options_lookup(api_empty_options,
KM_CORE_OPT_ENVIRONMENT,
u"isdummy", &value);

View file

@ -37,7 +37,7 @@ teardown() {
}
void
setup(const char *keyboard, const km_core_cp *context, bool setup_app_context = true) {
setup(const char *keyboard, const km_core_cu *context, bool setup_app_context = true) {
teardown();
km::core::path path = km::core::path::join(arg_path, keyboard);
@ -51,11 +51,11 @@ setup(const char *keyboard, const km_core_cp *context, bool setup_app_context =
}
bool
is_identical_context(km_core_cp const *cached_context) {
is_identical_context(km_core_cu const *cached_context) {
size_t buf_size;
try_status(km_core_context_get(km_core_state_context(test_state), &citems));
try_status(context_items_to_utf16(citems, nullptr, &buf_size));
km_core_cp *new_cached_context = new km_core_cp[buf_size];
km_core_cu *new_cached_context = new km_core_cu[buf_size];
try_status(context_items_to_utf16(citems, new_cached_context, &buf_size));
bool result = std::u16string(cached_context) == new_cached_context;
delete[] new_cached_context;
@ -122,8 +122,8 @@ is_identical_context(km_core_cp const *cached_context) {
void
test_context_set_if_needed__identical_context() {
km_core_cp const *cached_context = u"This is a test";
km_core_cp const *new_app_context = u"This is a test";
km_core_cu const *cached_context = u"This is a test";
km_core_cu const *new_app_context = u"This is a test";
setup("k_000___null_keyboard.kmx", cached_context, false);
assert_equal_status(km_core_state_context_set_if_needed(test_state, new_app_context), KM_CORE_CONTEXT_STATUS_UNCHANGED);
assert(is_identical_context(cached_context));
@ -132,8 +132,8 @@ test_context_set_if_needed__identical_context() {
void
test_context_set_if_needed__different_context() {
km_core_cp const *cached_context = u"This isn't a test";
km_core_cp const *new_app_context = u"This is a test";
km_core_cu const *cached_context = u"This isn't a test";
km_core_cu const *new_app_context = u"This is a test";
setup("k_000___null_keyboard.kmx", cached_context);
assert_equal_status(km_core_state_context_set_if_needed(test_state, new_app_context), KM_CORE_CONTEXT_STATUS_UPDATED);
assert(!is_identical_context(cached_context));
@ -143,8 +143,8 @@ test_context_set_if_needed__different_context() {
void
test_context_set_if_needed__cached_context_cleared() {
km_core_cp const *cached_context = u"";
km_core_cp const *new_app_context = u"This is a test";
km_core_cu const *cached_context = u"";
km_core_cu const *new_app_context = u"This is a test";
setup("k_000___null_keyboard.kmx", cached_context);
km_core_state_context_clear(test_state);
assert_equal_status(km_core_state_context_set_if_needed(test_state, new_app_context), KM_CORE_CONTEXT_STATUS_UPDATED);
@ -155,8 +155,8 @@ test_context_set_if_needed__cached_context_cleared() {
void
test_context_set_if_needed__application_context_empty() {
km_core_cp const *cached_context = u"This is a test";
km_core_cp const *new_app_context = u"";
km_core_cu const *cached_context = u"This is a test";
km_core_cu const *new_app_context = u"";
setup("k_000___null_keyboard.kmx", cached_context);
assert_equal_status(km_core_state_context_set_if_needed(test_state, new_app_context), KM_CORE_CONTEXT_STATUS_UPDATED);
assert(!is_identical_context(cached_context));
@ -166,8 +166,8 @@ test_context_set_if_needed__application_context_empty() {
void
test_context_set_if_needed__app_context_is_longer() {
km_core_cp const *cached_context = u"This is a test";
km_core_cp const *new_app_context = u"Longer This is a test";
km_core_cu const *cached_context = u"This is a test";
km_core_cu const *new_app_context = u"Longer This is a test";
setup("k_000___null_keyboard.kmx", cached_context);
assert_equal_status(km_core_state_context_set_if_needed(test_state, new_app_context), KM_CORE_CONTEXT_STATUS_UPDATED);
assert(!is_identical_context(cached_context));
@ -177,8 +177,8 @@ test_context_set_if_needed__app_context_is_longer() {
void
test_context_set_if_needed__app_context_is_shorter() {
km_core_cp const *cached_context = u"This is a test";
km_core_cp const *new_app_context = u"is a test";
km_core_cu const *cached_context = u"This is a test";
km_core_cu const *new_app_context = u"is a test";
setup("k_000___null_keyboard.kmx", cached_context);
assert_equal_status(km_core_state_context_set_if_needed(test_state, new_app_context), KM_CORE_CONTEXT_STATUS_UPDATED);
assert(!is_identical_context(cached_context));
@ -188,8 +188,8 @@ test_context_set_if_needed__app_context_is_shorter() {
void
test_context_set_if_needed__identical_context_and_markers() {
km_core_cp const *cached_context = u"123";
km_core_cp const *new_app_context = u"123";
km_core_cu const *cached_context = u"123";
km_core_cu const *new_app_context = u"123";
setup("k_000___null_keyboard.kmx", cached_context);
km_core_context_item const citems[] = {
@ -209,8 +209,8 @@ test_context_set_if_needed__identical_context_and_markers() {
void
test_context_set_if_needed__cached_context_shorter_and_markers() {
km_core_cp const *cached_context = u"123";
km_core_cp const *new_app_context = u"0123";
km_core_cu const *cached_context = u"123";
km_core_cu const *new_app_context = u"0123";
setup("k_000___null_keyboard.kmx", cached_context);
km_core_context_item const citems[] = {
@ -235,8 +235,8 @@ test_context_set_if_needed__cached_context_shorter_and_markers() {
void
test_context_set_if_needed__cached_context_shorter_and_markers_nfu() {
km_core_cp const *cached_context = u"bce\u0323\u0302";
km_core_cp const *new_app_context = u"abcệ";
km_core_cu const *cached_context = u"bce\u0323\u0302";
km_core_cu const *new_app_context = u"abcệ";
setup("/a/dummy/keyboard.mock", cached_context);
km_core_context_item const citems[] = {
@ -268,8 +268,8 @@ test_context_set_if_needed__cached_context_shorter_and_markers_nfu() {
void
test_context_set_if_needed__cached_context_longer_and_markers() {
km_core_cp const *cached_context = u"0123";
km_core_cp const *new_app_context = u"123";
km_core_cu const *cached_context = u"0123";
km_core_cu const *new_app_context = u"123";
setup("k_000___null_keyboard.kmx", cached_context);
km_core_context_item const citems[] = {
@ -293,8 +293,8 @@ test_context_set_if_needed__cached_context_longer_and_markers() {
void
test_context_set_if_needed__cached_context_longer_and_markers_nfu() {
km_core_cp const *cached_context = u"abce\u0323\u0302";
km_core_cp const *new_app_context = u"bcệ";
km_core_cu const *cached_context = u"abce\u0323\u0302";
km_core_cu const *new_app_context = u"bcệ";
setup("/a/dummy/keyboard.mock", cached_context);
km_core_context_item const citems[] = {
@ -326,8 +326,8 @@ test_context_set_if_needed__cached_context_longer_and_markers_nfu() {
void
test_context_set_if_needed__surrogate_pairs_unchanged() {
km_core_cp const *cached_context = u"a\U00010100";
km_core_cp const *new_app_context = u"a\U00010100";
km_core_cu const *cached_context = u"a\U00010100";
km_core_cu const *new_app_context = u"a\U00010100";
setup("k_000___null_keyboard.kmx", cached_context);
assert_equal_status(km_core_state_context_set_if_needed(test_state, new_app_context), KM_CORE_CONTEXT_STATUS_UNCHANGED);
assert(is_identical_context(new_app_context));
@ -336,8 +336,8 @@ test_context_set_if_needed__surrogate_pairs_unchanged() {
void
test_context_set_if_needed__surrogate_pairs_app_context_longer() {
km_core_cp const *cached_context = u"a\U00010100";
km_core_cp const *new_app_context = u"xa\U00010100";
km_core_cu const *cached_context = u"a\U00010100";
km_core_cu const *new_app_context = u"xa\U00010100";
setup("k_000___null_keyboard.kmx", cached_context);
assert_equal_status(km_core_state_context_set_if_needed(test_state, new_app_context), KM_CORE_CONTEXT_STATUS_UPDATED);
assert(is_identical_context(new_app_context));
@ -346,8 +346,8 @@ test_context_set_if_needed__surrogate_pairs_app_context_longer() {
void
test_context_set_if_needed__surrogate_pairs_cached_context_longer() {
km_core_cp const *cached_context = u"xa\U00010100";
km_core_cp const *new_app_context = u"a\U00010100";
km_core_cu const *cached_context = u"xa\U00010100";
km_core_cu const *new_app_context = u"a\U00010100";
setup("k_000___null_keyboard.kmx", cached_context);
assert_equal_status(km_core_state_context_set_if_needed(test_state, new_app_context), KM_CORE_CONTEXT_STATUS_UPDATED);
assert(is_identical_context(new_app_context));
@ -356,8 +356,8 @@ test_context_set_if_needed__surrogate_pairs_cached_context_longer() {
void
test_context_set_if_needed__surrogate_pairs_unchanged_and_markers() {
km_core_cp const *cached_context = u"a\U00010100";
km_core_cp const *new_app_context = u"a\U00010100";
km_core_cu const *cached_context = u"a\U00010100";
km_core_cu const *new_app_context = u"a\U00010100";
setup("k_000___null_keyboard.kmx", cached_context);
km_core_context_item const citems[] = {
@ -376,8 +376,8 @@ test_context_set_if_needed__surrogate_pairs_unchanged_and_markers() {
void
test_context_set_if_needed__surrogate_pairs_app_context_longer_and_markers() {
km_core_cp const *cached_context = u"a\U00010100";
km_core_cp const *new_app_context = u"\U00010200a\U00010100";
km_core_cu const *cached_context = u"a\U00010100";
km_core_cu const *new_app_context = u"\U00010200a\U00010100";
setup("k_000___null_keyboard.kmx", cached_context);
km_core_context_item const citems[] = {
@ -403,8 +403,8 @@ test_context_set_if_needed__surrogate_pairs_app_context_longer_and_markers() {
void
test_context_set_if_needed__surrogate_pairs_cached_context_longer_and_markers() {
km_core_cp const *cached_context = u"\U00010200a\U00010100";
km_core_cp const *new_app_context = u"a\U00010100";
km_core_cu const *cached_context = u"\U00010200a\U00010100";
km_core_cu const *new_app_context = u"a\U00010100";
setup("k_000___null_keyboard.kmx", cached_context);
km_core_context_item const citems[] = {
@ -464,7 +464,7 @@ test_context_set_if_needed() {
void
test_context_clear() {
km_core_cp const *cached_context = u"This is a test";
km_core_cu const *cached_context = u"This is a test";
setup("k_000___null_keyboard.kmx", cached_context);
try_status(km_core_state_context_clear(test_state));
assert(!is_identical_context(cached_context));
@ -475,16 +475,16 @@ test_context_clear() {
//-------------------------------------------------------------------------------------
void test_context_debug_empty() {
km_core_cp const *cached_context = u"";
km_core_cu const *cached_context = u"";
setup("k_000___null_keyboard.kmx", cached_context);
auto str = km_core_state_context_debug(test_state, KM_CORE_DEBUG_CONTEXT_CACHED);
// std::cout << str << std::endl;
assert(std::u16string(str) == u"|| (len: 0) [ ]");
km_core_cp_dispose(str);
km_core_cu_dispose(str);
}
void test_context_debug_various() {
km_core_cp const *cached_context = u"123\U0001F923";
km_core_cu const *cached_context = u"123\U0001F923";
setup("k_000___null_keyboard.kmx", cached_context);
km_core_context_item const citems[] = {
@ -505,7 +505,7 @@ void test_context_debug_various() {
auto str = km_core_state_context_debug(test_state, KM_CORE_DEBUG_CONTEXT_CACHED);
// std::cout << str << std::endl;
assert(std::u16string(str) == u"|123🤣| (len: 9) [ M(5) U+0031 M(1) U+0032 M(2) U+0033 M(3) M(4) U+1f923 ]");
km_core_cp_dispose(str);
km_core_cu_dispose(str);
}
void test_context_debug() {

View file

@ -44,7 +44,7 @@ void teardown() {
void setup(const km_core_cp *app_context, const km_core_cp *cached_context, int actions_code_points_to_delete, const std::u32string actions_output) {
void setup(const km_core_cu *app_context, const km_core_cu *cached_context, int actions_code_points_to_delete, const std::u32string actions_output) {
teardown();
km::core::path path = km::core::path::join(arg_path, "..", "ldml", "keyboards", "k_001_tiny.kmx");
@ -107,14 +107,14 @@ void setup(const km_core_cp *app_context, const km_core_cp *cached_context, int
*/
void test(
const char *name,
const km_core_cp *initial_app_context,
const km_core_cp *final_cached_context,
const km_core_cu *initial_app_context,
const km_core_cu *final_cached_context,
int actions_code_points_to_delete,
const std::u32string actions_output,
const unsigned int expected_delete,
const std::u32string expected_output,
const km_core_cp *expected_final_app_context,
const km_core_cu *expected_final_app_context,
const std::u32string expected_deleted_context
) {
std::cout << "test: " << name << std::endl;

View file

@ -16,7 +16,7 @@
#include <test_assert.h>
#include "../emscripten_filesystem.h"
void compare_context(km_core_context *app_context, const km_core_cp* expected_final_app_context);
void compare_context(km_core_context *app_context, const km_core_cu* expected_final_app_context);
km_core_option_item test_env_opts[] =
{
@ -42,7 +42,7 @@ void teardown() {
void setup(const km_core_cp *app_context, const km_core_cp *cached_context_string, const km_core_context_item *cached_context_items, int actions_code_points_to_delete, const std::u32string actions_output) {
void setup(const km_core_cu *app_context, const km_core_cu *cached_context_string, const km_core_context_item *cached_context_items, int actions_code_points_to_delete, const std::u32string actions_output) {
teardown();
km::core::path path = km::core::path::join(arg_path, "..", "ldml", "keyboards", "k_001_tiny.kmx");
@ -105,15 +105,15 @@ void setup(const km_core_cp *app_context, const km_core_cp *cached_context_strin
*/
void test_actions_normalize(
const char *name,
const km_core_cp *initial_app_context,
const km_core_cp *final_cached_context_string,
const km_core_cu *initial_app_context,
const km_core_cu *final_cached_context_string,
const km_core_context_item *final_cached_context_items,
int actions_code_points_to_delete,
const std::u32string actions_output,
const unsigned int expected_delete,
const std::u32string expected_output,
const km_core_cp *expected_final_app_context
const km_core_cu *expected_final_app_context
) {
std::cout << "test_actions_normalize: " << name << std::endl;
@ -133,7 +133,7 @@ void test_actions_normalize(
auto debug = km_core_state_context_debug(test_state, KM_CORE_DEBUG_CONTEXT_APP);
std::cout << " final app context: " << debug << std::endl;
km_core_cp_dispose(debug);
km_core_cu_dispose(debug);
compare_context(km_core_state_app_context(test_state), expected_final_app_context);
teardown();
@ -179,15 +179,15 @@ void test_actions_normalize(
*/
void test_actions_update_app_context_nfu(
const char *name,
const km_core_cp *initial_app_context,
const km_core_cp *final_cached_context_string,
const km_core_cu *initial_app_context,
const km_core_cu *final_cached_context_string,
const km_core_context_item *final_cached_context_items,
int actions_code_points_to_delete,
const std::u32string actions_output,
const unsigned int expected_delete,
const std::u32string expected_output,
const km_core_cp *expected_final_app_context
const km_core_cu *expected_final_app_context
) {
std::cout << "test_actions_update_app_context_nfu: " << name << std::endl;
@ -207,7 +207,7 @@ void test_actions_update_app_context_nfu(
auto debug = km_core_state_context_debug(test_state, KM_CORE_DEBUG_CONTEXT_APP);
std::cout << " final app context: " << debug << std::endl;
km_core_cp_dispose(debug);
km_core_cu_dispose(debug);
compare_context(km_core_state_app_context(test_state), expected_final_app_context);
teardown();
@ -618,7 +618,7 @@ int main(int argc, char *argv []) {
}
void compare_context(km_core_context *app_context, const km_core_cp* expected_final_app_context) {
void compare_context(km_core_context *app_context, const km_core_cu* expected_final_app_context) {
// Compare context items -- to ensure no markers have leaked into app context
km_core_context_item *actual_final_app_context_items = nullptr, *expected_final_app_context_items = nullptr;
try_status(km_core_context_get(app_context, &actual_final_app_context_items));

View file

@ -246,7 +246,7 @@ run_test(const km::core::path &source, const km::core::path &compiled) {
size_t n = 0;
try_status(km_core_context_get(km_core_state_context(test_state), &citems));
try_status(context_items_to_utf16(citems, nullptr, &n));
km_core_cp *core_context_str = new km_core_cp[n];
km_core_cu *core_context_str = new km_core_cu[n];
try_status(context_items_to_utf16(citems, core_context_str, &n));
// Verify that both our local test_context and the core's test_state.context have
@ -273,7 +273,7 @@ run_test(const km::core::path &source, const km::core::path &compiled) {
size_t n = 0;
try_status(km_core_context_get(km_core_state_context(test_state), &citems));
try_status(context_items_to_utf16(citems, nullptr, &n));
km_core_cp *core_context_str = new km_core_cp[n];
km_core_cu *core_context_str = new km_core_cu[n];
try_status(context_items_to_utf16(citems, core_context_str, &n));
// Verify that both our local test_context and the core's test_state.context have
@ -301,7 +301,7 @@ run_test(const km::core::path &source, const km::core::path &compiled) {
for (auto it = options.begin(); it != options.end(); it++) {
if (it->type == km::tests::KOT_OUTPUT) {
std::cout << "output option-key: " << it->key << " expected: " << it->value;
km_core_cp const *value;
km_core_cu const *value;
try_status(km_core_state_option_lookup(test_state, KM_CORE_OPT_KEYBOARD, it->key.c_str(), &value));
std::cout << " actual: " << value << std::endl;
if (it->value.compare(value) != 0) return __LINE__;

View file

@ -78,7 +78,7 @@ uint8_t test_imx_callback(km_core_state *state, uint32_t imx_id, void *callback_
size_t n = 0;
try_status(context_items_to_utf16(entry_context, nullptr, &n))
km_core_cp *buf = new km_core_cp[n];
km_core_cu *buf = new km_core_cu[n];
try_status(context_items_to_utf16(entry_context, buf, &n));
std::cout << "imx entry context : " << " [" << buf << "]" << std::endl;
@ -146,7 +146,7 @@ uint8_t test_imx_callback(km_core_state *state, uint32_t imx_id, void *callback_
n = 0;
try_status(context_items_to_utf16(exit_context, nullptr, &n))
km_core_cp *tmp_buf = new km_core_cp[n];
km_core_cu *tmp_buf = new km_core_cu[n];
try_status(context_items_to_utf16(exit_context, tmp_buf, &n));
std::cout << "imx exit context : " << " [" << tmp_buf << "]" << std::endl;

View file

@ -206,7 +206,7 @@ verify_context(std::u16string &text_store, km_core_state *&test_state, std::vect
km_core_context_item *citems = nullptr;
try_status(km_core_context_get(km_core_state_context(test_state), &citems));
try_status(context_items_to_utf16(citems, nullptr, &n));
km_core_cp *buf = new km_core_cp[n];
km_core_cu *buf = new km_core_cu[n];
try_status(context_items_to_utf16(citems, buf, &n));
std::cout << "context (raw): "; // output including markers (which aren't in 'buf' here)
for (auto ci = citems; ci->type != KM_CORE_CT_END; ci++) {

View file

@ -174,10 +174,10 @@ LdmlTestSource::parse_source_string(std::string const &s) {
assert(v >= 0x0001 && v <= 0x10FFFF);
p += n - 1;
if (v < 0x10000) {
t += km_core_cp(v);
t += km_core_cu(v);
} else {
t += km_core_cp(Uni_UTF32ToSurrogate1(v));
t += km_core_cp(Uni_UTF32ToSurrogate2(v));
t += km_core_cu(Uni_UTF32ToSurrogate1(v));
t += km_core_cu(Uni_UTF32ToSurrogate2(v));
}
if (had_open_curly) {
p++;
@ -225,10 +225,10 @@ LdmlTestSource::parse_u8_source_string(std::string const &u8s) {
assert(v >= 0x0001 && v <= 0x10FFFF);
p += n - 1;
if (v < 0x10000) {
t += km_core_cp(v);
t += km_core_cu(v);
} else {
t += km_core_cp(Uni_UTF32ToSurrogate1(v));
t += km_core_cp(Uni_UTF32ToSurrogate2(v));
t += km_core_cu(Uni_UTF32ToSurrogate1(v));
t += km_core_cu(Uni_UTF32ToSurrogate2(v));
}
if (had_open_curly) {
p++;

View file

@ -53,10 +53,10 @@ void debug_context(km_core_debug_context_type context_type) {
} else {
std::cout << "cached context: " << context << std::endl;
}
km_core_cp_dispose(context);
km_core_cu_dispose(context);
}
bool is_identical_context(km_core_cp const *cached_context, km_core_debug_context_type context_type) {
bool is_identical_context(km_core_cu const *cached_context, km_core_debug_context_type context_type) {
size_t buf_size;
km_core_context_item * citems = nullptr;
@ -68,7 +68,7 @@ bool is_identical_context(km_core_cp const *cached_context, km_core_debug_contex
try_status(km_core_context_get(km_core_state_context(test_state), &citems));
}
try_status(context_items_to_utf16(citems, nullptr, &buf_size));
km_core_cp* new_cached_context = new km_core_cp[buf_size];
km_core_cu* new_cached_context = new km_core_cu[buf_size];
try_status(context_items_to_utf16(citems, new_cached_context, &buf_size));
km_core_context_items_dispose(citems);
@ -79,7 +79,7 @@ bool is_identical_context(km_core_cp const *cached_context, km_core_debug_contex
}
void test_context_normalization_already_nfd() {
km_core_cp const *app_context_nfd = u"A\u0300";
km_core_cu const *app_context_nfd = u"A\u0300";
setup("k_001_tiny.kmx");
assert(km_core_state_context_set_if_needed(test_state, app_context_nfd) == KM_CORE_CONTEXT_STATUS_UPDATED);
assert(is_identical_context(app_context_nfd, KM_CORE_DEBUG_CONTEXT_APP));
@ -88,8 +88,8 @@ void test_context_normalization_already_nfd() {
}
void test_context_normalization_basic() {
km_core_cp const *application_context = u"This is a test À";
km_core_cp const *cached_context = u"This is a test A\u0300";
km_core_cu const *application_context = u"This is a test À";
km_core_cu const *cached_context = u"This is a test A\u0300";
setup("k_001_tiny.kmx");
assert(km_core_state_context_set_if_needed(test_state, application_context) == KM_CORE_CONTEXT_STATUS_UPDATED);
assert(is_identical_context(application_context, KM_CORE_DEBUG_CONTEXT_APP));
@ -99,8 +99,8 @@ void test_context_normalization_basic() {
void test_context_normalization_hefty() {
// Latin Latin "ṩ" "Å" Tirhuta U+114bc -> U+114B9 U+114B0
km_core_cp const *application_context = u"À" u"é̖" u"\u1e69" u"\u212b" u"\U000114BC";
km_core_cp const *cached_context = u"A\u0300" u"e\u0316\u0301" u"\u0073\u0323\u0307" u"\u0041\u030a" u"\U000114B9\U000114B0";
km_core_cu const *application_context = u"À" u"é̖" u"\u1e69" u"\u212b" u"\U000114BC";
km_core_cu const *cached_context = u"A\u0300" u"e\u0316\u0301" u"\u0073\u0323\u0307" u"\u0041\u030a" u"\U000114B9\U000114B0";
setup("k_001_tiny.kmx");
assert(km_core_state_context_set_if_needed(test_state, application_context) == KM_CORE_CONTEXT_STATUS_UPDATED);
assert(is_identical_context(application_context, KM_CORE_DEBUG_CONTEXT_APP));
@ -110,8 +110,8 @@ void test_context_normalization_hefty() {
void test_context_normalization_invalid_unicode() {
// unpaired surrogate illegal
km_core_cp const application_context[] = { 0xDC01, 0x0020, 0x0020, 0xFFFF, 0x0000 };
km_core_cp const cached_context[] = { 0xDC01, 0x0020, 0x0020, 0xFFFF, 0x0000 };
km_core_cu const application_context[] = { 0xDC01, 0x0020, 0x0020, 0xFFFF, 0x0000 };
km_core_cu const cached_context[] = { 0xDC01, 0x0020, 0x0020, 0xFFFF, 0x0000 };
setup("k_001_tiny.kmx");
assert(km_core_state_context_set_if_needed(test_state, application_context) == KM_CORE_CONTEXT_STATUS_UPDATED);
assert(is_identical_context(application_context, KM_CORE_DEBUG_CONTEXT_APP));
@ -121,8 +121,8 @@ void test_context_normalization_invalid_unicode() {
void test_context_normalization_lone_trailing_surrogate() {
// unpaired trail surrogate
km_core_cp const application_context[] = { 0xDC01, 0x0020, 0x0020, 0x0000 };
km_core_cp const cached_context[] = /* skipped*/ { 0x0020, 0x0020, 0x0000 };
km_core_cu const application_context[] = { 0xDC01, 0x0020, 0x0020, 0x0000 };
km_core_cu const cached_context[] = /* skipped*/ { 0x0020, 0x0020, 0x0000 };
setup("k_001_tiny.kmx");
assert(km_core_state_context_set_if_needed(test_state, application_context) == KM_CORE_CONTEXT_STATUS_UPDATED);
assert(is_identical_context(application_context+1, KM_CORE_DEBUG_CONTEXT_APP)); // first code unit is skipped

View file

@ -18,3 +18,5 @@ DEVELOPER_DCC32DPK=cmd /c "$(DCC32PATH)\dcc32.exe" $(DEVELOPER_DELPHIDPKPARAMS)
# Temporary import of windows/src/Defines.mak
# TODO: include COMMON_ROOT's defines.mak instead
!include $(WINDOWS_ROOT)\src\Defines.mak
KEYMANCORE=keymancore-2

View file

@ -167,7 +167,7 @@
</Component>
<Component>
<File Name="keymancore-1.dll" KeyPath="yes" />
<File Name="keymancore-2.dll" KeyPath="yes" />
</Component>
<Component>

View file

@ -372,6 +372,7 @@ export class KeyboardInfoCompiler implements KeymanCompiler {
const jsonOutput = JSON.stringify(keyboard_info, null, 2);
/* c8 ignore next 8 */
if(!SchemaValidators.default.keyboard_info(keyboard_info)) {
// This is an internal fatal error; we should not be capable of producing
// invalid output, so it is best to throw and die

View file

@ -109,7 +109,7 @@ describe('keyboard-info-compiler', function () {
assert.deepEqual(actual, expected);
});
it('check preinit creates langtagsByTag correctly', async function() {
it('check preinit creates langtagsByTag correctly', function() {
const compiler = new KeyboardInfoCompiler(); // indirectly call preinit()
assert.isNotNull(compiler);
const en_langtag = langtags.find(({ tag }) => tag === 'en');
@ -146,7 +146,6 @@ describe('keyboard-info-compiler', function () {
});
it('check run returns null if KmpCompiler.transformKpsToKmpObject fails', async function() {
const kpjFilename = KHMER_ANGKOR_KPJ;
const sources = KHMER_ANGKOR_SOURCES;
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
@ -154,7 +153,7 @@ describe('keyboard-info-compiler', function () {
let result: KeyboardInfoCompilerResult;
try {
KmpCompiler.prototype.transformKpsToKmpObject = (_kpsFilename: string): KmpJsonFile.KmpJsonFile => null;
result = await compiler.run(kpjFilename, null);
result = await compiler.run(KHMER_ANGKOR_KPJ, null);
} catch(e) {
assert.fail(e);
} finally {
@ -164,40 +163,36 @@ describe('keyboard-info-compiler', function () {
});
it('check run returns null if loadJsFile fails', async function() {
const kpjFilename = KHMER_ANGKOR_KPJ;
const sources = KHMER_ANGKOR_SOURCES
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
compiler['loadJsFile'] = (_filename: string): string => null;
const result = await compiler.run(kpjFilename, null);
const result = await compiler.run(KHMER_ANGKOR_KPJ, null);
assert.isNull(result);
});
it('check run returns null if license is not MIT', async function() {
const kpjFilename = KHMER_ANGKOR_KPJ;
const sources = KHMER_ANGKOR_SOURCES;
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
compiler['isLicenseMIT'] = (_filename: string): boolean => false;
const result = await compiler.run(kpjFilename, null);
const result = await compiler.run(KHMER_ANGKOR_KPJ, null);
assert.isNull(result);
});
it('check run leaves keyboard_info.isRTL undefined if not set in jsFile', async function() {
const kpjFilename = KHMER_ANGKOR_KPJ;
const sources = KHMER_ANGKOR_SOURCES;
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
const jsFile = compiler['loadJsFile'](sources.jsFilename);
assert.isNull(jsFile.match(/this\.KRTL=1/));
const result = await compiler.run(kpjFilename, null);
const result = await compiler.run(KHMER_ANGKOR_KPJ, null);
assert.isNotNull(result);
const keyboard_info = JSON.parse(new TextDecoder().decode(result.artifacts.keyboard_info.data));
assert.isUndefined(keyboard_info.isRTL);
});
it('check run sets keyboard_info.isRTL if set in jsFile', async function() {
const kpjFilename = KHMER_ANGKOR_KPJ;
const sources = KHMER_ANGKOR_SOURCES;
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
@ -205,7 +200,7 @@ describe('keyboard-info-compiler', function () {
jsFile = jsFile.replace('this\.KN="Khmer Angkor";', '$&\n this\.KRTL=1;'); // insert this.KRTL=1
const origCompilerLoadJsFile = compiler['loadJsFile'];
compiler['loadJsFile'] = (_filename: string) => jsFile;
const result = await compiler.run(kpjFilename, null);
const result = await compiler.run(KHMER_ANGKOR_KPJ, null);
compiler['loadJsFile'] = origCompilerLoadJsFile;
assert.isNotNull(result);
const keyboard_info = JSON.parse(new TextDecoder().decode(result.artifacts.keyboard_info.data));
@ -213,7 +208,6 @@ describe('keyboard-info-compiler', function () {
});
it('check run sets author.url correctly if mailto provided', async function() {
const kpjFilename = KHMER_ANGKOR_KPJ;
const sources = KHMER_ANGKOR_SOURCES;
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
@ -221,14 +215,13 @@ describe('keyboard-info-compiler', function () {
await kmpCompiler.init(callbacks, {});
const kmpJsonData = kmpCompiler.transformKpsToKmpObject(sources.kpsFilename);
assert.isNotNull(kmpJsonData.info.author.url.match(/^mailto\:/));
const result = await compiler.run(kpjFilename, null);
const result = await compiler.run(KHMER_ANGKOR_KPJ, null);
assert.isNotNull(result);
const keyboard_info = JSON.parse(new TextDecoder().decode(result.artifacts.keyboard_info.data));
assert.deepEqual(keyboard_info.authorEmail, 'makara_sok@sil.org');
});
it('check run sets author.url correctly if just email provided', async function() {
const kpjFilename = KHMER_ANGKOR_KPJ;
const sources = KHMER_ANGKOR_SOURCES;
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
@ -240,7 +233,7 @@ describe('keyboard-info-compiler', function () {
let result: KeyboardInfoCompilerResult;
try {
KmpCompiler.prototype.transformKpsToKmpObject = (_kpsFilename: string): KmpJsonFile.KmpJsonFile => kmpJsonData;
result = await compiler.run(kpjFilename, null);
result = await compiler.run(KHMER_ANGKOR_KPJ, null);
} catch(e) {
assert.fail(e);
} finally {
@ -252,12 +245,11 @@ describe('keyboard-info-compiler', function () {
});
it('check run returns null if fillLanguages fails', async function() {
const kpjFilename = KHMER_ANGKOR_KPJ;
const sources = KHMER_ANGKOR_SOURCES;
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
compiler['fillLanguages'] = async (_kpsFilename: string, _keyboard_info: KeyboardInfoFile, _kmpJsonData: KmpJsonFile.KmpJsonFile): Promise<boolean> => false;
const result = await compiler.run(kpjFilename, null);
const result = await compiler.run(KHMER_ANGKOR_KPJ, null);
assert.isNull(result);
});
@ -283,7 +275,6 @@ describe('keyboard-info-compiler', function () {
];
packageIncludesTestCases.forEach((testCase, idx) => it(`check run sets packageIncludes correctly (test case #${idx})`, async function() {
const kpjFilename = KHMER_ANGKOR_KPJ;
const sources = KHMER_ANGKOR_SOURCES;
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
@ -291,17 +282,16 @@ describe('keyboard-info-compiler', function () {
compiler['fontSourceToKeyboardInfoFont'] = async (_kpsFilename: string, _kmpJsonData: KmpJsonFile.KmpJsonFile, _source: string[]) => {
return (_source[0] == KHMER_ANGKOR_DISPLAY_FONT) ? KHMER_ANGKOR_DISPLAY_FONT_INFO : KHMER_ANGKOR_OSK_FONT_INFO;
}
const kpsFilename = KHMER_ANGKOR_KPS;
const kmpCompiler = new KmpCompiler();
assert.isTrue(await kmpCompiler.init(callbacks, {}));
const kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsFilename);
const kmpJsonData = kmpCompiler.transformKpsToKmpObject(KHMER_ANGKOR_KPS);
assert.isNotNull(kmpJsonData);
const origKmpCompilerTransformKpsToKmpObject = KmpCompiler.prototype.transformKpsToKmpObject;
kmpJsonData.files = testCase.files;
let result: KeyboardInfoCompilerResult;
try {
KmpCompiler.prototype.transformKpsToKmpObject = (_kpsFilename: string): KmpJsonFile.KmpJsonFile => kmpJsonData;
result = await compiler.run(kpjFilename, null);
result = await compiler.run(KHMER_ANGKOR_KPJ, null);
} catch(e) {
assert.fail(e);
} finally {
@ -321,7 +311,6 @@ describe('keyboard-info-compiler', function () {
];
minKeymanVersionTestCases.forEach((testCase, idx) => it(`check run sets minKeymanVersion correctly (test case #${idx})`, async function() {
const kpjFilename = KHMER_ANGKOR_KPJ;
const sources = KHMER_ANGKOR_SOURCES;
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
@ -332,7 +321,7 @@ describe('keyboard-info-compiler', function () {
jsFile = jsFile.replace('this.KMINVER="10.0";', insert);
compiler['loadJsFile'] = (_filename: string) => jsFile;
compiler['kmxFileVersionToString'] = (_version: number) => testCase.kmx;
const result = await compiler.run(kpjFilename, null);
const result = await compiler.run(KHMER_ANGKOR_KPJ, null);
compiler['loadJsFile'] = origCompilerLoadJsFile;
compiler['kmxFileVersionToString'] = origKmxFileVersionToString;
assert.isNotNull(result);
@ -341,35 +330,33 @@ describe('keyboard-info-compiler', function () {
}));
const platformsTestCases = [
{ hasJsFile: true, targets: 'any', expected: { windows: "full",macos: "full",linux: "full",desktopWeb: "full",ios: "full",android: "full",mobileWeb: "full" } },
{ hasJsFile: false, targets: '', expected: { desktopWeb: "full",mobileWeb: "full" } },
{ hasJsFile: true, targets: '', expected: { desktopWeb: "full",ios: "full",android: "full",mobileWeb: "full" } },
{ hasJsFile: true, targets: 'androidphone', expected: { android: "full",mobileWeb: "full" } },
{ hasJsFile: true, targets: 'iphone', expected: { ios: "full",mobileWeb: "full" } },
{ hasJsFile: true, targets: 'linux', expected: { linux: "full",desktopWeb: "full" } },
{ hasJsFile: true, targets: 'macosx', expected: { macos: "full",desktopWeb: "full" } },
{ hasJsFile: true, targets: 'windows', expected: { windows: "full",desktopWeb: "full" } },
{ hasJsFile: true, targets: 'androidphone iphone', expected: { android: "full",ios: "full",mobileWeb: "full" } },
{ hasJsFileInKps: true, targets: 'any', expected: { windows: "full",macos: "full",linux: "full",desktopWeb: "full",ios: "full",android: "full",mobileWeb: "full" } },
{ hasJsFileInKps: false, targets: '', expected: { desktopWeb: "full",mobileWeb: "full" } },
{ hasJsFileInKps: true, targets: '', expected: { desktopWeb: "full",ios: "full",android: "full",mobileWeb: "full" } },
{ hasJsFileInKps: true, targets: 'androidphone', expected: { android: "full",mobileWeb: "full" } },
{ hasJsFileInKps: true, targets: 'iphone', expected: { ios: "full",mobileWeb: "full" } },
{ hasJsFileInKps: true, targets: 'linux', expected: { linux: "full",desktopWeb: "full" } },
{ hasJsFileInKps: true, targets: 'macosx', expected: { macos: "full",desktopWeb: "full" } },
{ hasJsFileInKps: true, targets: 'windows', expected: { windows: "full",desktopWeb: "full" } },
{ hasJsFileInKps: true, targets: 'androidphone iphone', expected: { android: "full",ios: "full",mobileWeb: "full" } },
];
platformsTestCases.forEach((testCase, idx) => it(`check run sets platforms correctly (test case #${idx})`, async function() {
const kpjFilename = KHMER_ANGKOR_KPJ;
const sources = KHMER_ANGKOR_SOURCES;
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
const kpsFilename = KHMER_ANGKOR_KPS;
const kmpCompiler = new KmpCompiler();
assert.isTrue(await kmpCompiler.init(callbacks, {}));
const kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsFilename);
const kmpJsonData = kmpCompiler.transformKpsToKmpObject(KHMER_ANGKOR_KPS);
assert.isNotNull(kmpJsonData);
if (!testCase.hasJsFile) {
if (!testCase.hasJsFileInKps) {
// remove .js file
kmpJsonData.files = kmpJsonData.files.filter(file => !KeymanFileTypes.filenameIs(file.name, KeymanFileTypes.Binary.WebKeyboard));
}
const kmxFiles: {
filename: string,
data: KMX.KEYBOARD
}[] = compiler['loadKmxFiles'](kpsFilename, kmpJsonData);
}[] = compiler['loadKmxFiles'](KHMER_ANGKOR_KPS, kmpJsonData);
// set targets
kmxFiles[0].data.targets = testCase.targets;
const origLoadKmxFiles = compiler['loadKmxFiles'];
@ -378,7 +365,7 @@ describe('keyboard-info-compiler', function () {
try {
KmpCompiler.prototype.transformKpsToKmpObject = (_kpsFilename: string): KmpJsonFile.KmpJsonFile => kmpJsonData;
compiler['loadKmxFiles'] = (_kpsFilename: string, _kmpJsonData: KmpJsonFile.KmpJsonFile) => kmxFiles;
result = await compiler.run(kpjFilename, null);
result = await compiler.run(KHMER_ANGKOR_KPJ, null);
} catch(e) {
assert.fail(e);
} finally {
@ -390,15 +377,43 @@ describe('keyboard-info-compiler', function () {
assert.deepEqual(keyboard_info.platformSupport, testCase.expected);
}));
it('check run sets related packages correctly', async function() {
const sources = KHMER_ANGKOR_SOURCES;
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
const kmpCompiler = new KmpCompiler();
await kmpCompiler.init(callbacks, {});
const kmpJsonData = kmpCompiler.transformKpsToKmpObject(sources.kpsFilename);
kmpJsonData.relatedPackages = [
{ id: "dep1", relationship: "deprecates" },
{ id: "dep2", relationship: "deprecates" },
{ id: "rel1", relationship: "related" },
];
const origKmpCompilerTransformKpsToKmpObject = KmpCompiler.prototype.transformKpsToKmpObject;
let result: KeyboardInfoCompilerResult;
try {
KmpCompiler.prototype.transformKpsToKmpObject = (_kpsFilename: string): KmpJsonFile.KmpJsonFile => kmpJsonData;
result = await compiler.run(KHMER_ANGKOR_KPJ, null);
} catch(e) {
assert.fail(e);
} finally {
KmpCompiler.prototype.transformKpsToKmpObject = origKmpCompilerTransformKpsToKmpObject;
}
assert.isNotNull(result);
const keyboard_info = JSON.parse(new TextDecoder().decode(result.artifacts.keyboard_info.data));
assert.deepEqual(keyboard_info.related['dep1'], {deprecates: true});
assert.deepEqual(keyboard_info.related['dep2'], {deprecates: true});
assert.deepEqual(keyboard_info.related['rel1'], {deprecates: false});
});
it('should write artifacts to disk', async function() {
const kpjFilename = KHMER_ANGKOR_KPJ;
const actualFilename = makePathToFixture('khmer_angkor', 'build', 'actual.keyboard_info');
const expectedFilename = makePathToFixture('khmer_angkor', 'build', 'khmer_angkor.keyboard_info');
const sources = KHMER_ANGKOR_SOURCES;
const compiler = new KeyboardInfoCompiler();
assert.isTrue(await compiler.init(callbacks, {sources}));
const result = await compiler.run(kpjFilename, null);
const result = await compiler.run(KHMER_ANGKOR_KPJ, null);
assert.isNotNull(result);
if(fs.existsSync(actualFilename)) {
@ -459,32 +474,30 @@ describe('keyboard-info-compiler', function () {
});
it('check loadKmxFiles returns empty array if .kmx file is missing from .kmp', async function() {
const kpsFilename = KHMER_ANGKOR_KPS;
const compiler = new KeyboardInfoCompiler();
const kmpCompiler = new KmpCompiler();
assert.isTrue(await kmpCompiler.init(callbacks, {}));
const kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsFilename);
const kmpJsonData = kmpCompiler.transformKpsToKmpObject(KHMER_ANGKOR_KPS);
assert.isNotNull(kmpJsonData);
// remove .kmx file
kmpJsonData.files = kmpJsonData.files.filter(file => !KeymanFileTypes.filenameIs(file.name, KeymanFileTypes.Binary.Keyboard));
const kmxFiles: {
filename: string,
data: KMX.KEYBOARD
}[] = compiler['loadKmxFiles'](kpsFilename, kmpJsonData);
}[] = compiler['loadKmxFiles'](KHMER_ANGKOR_KPS, kmpJsonData);
assert.deepEqual(kmxFiles, []);
});
it('check loadKmxFiles throws error if .kmx file is missing from disk', async function() {
const kpsFilename = KHMER_ANGKOR_KPS;
const compiler = new KeyboardInfoCompiler();
const kmpCompiler = new KmpCompiler();
assert.isTrue(await kmpCompiler.init(callbacks, {}));
const kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsFilename);
const kmpJsonData = kmpCompiler.transformKpsToKmpObject(KHMER_ANGKOR_KPS);
assert.isNotNull(kmpJsonData);
// rename .kmx file in files list so it cannot be loaded from disk
const kmpIndex = kmpJsonData.files.findIndex(file => KeymanFileTypes.filenameIs(file.name, KeymanFileTypes.Binary.Keyboard));
kmpJsonData.files[kmpIndex].name = '../build/throw_error.kmx';
assert.throws(() => compiler['loadKmxFiles'](kpsFilename, kmpJsonData));
assert.throws(() => compiler['loadKmxFiles'](KHMER_ANGKOR_KPS, kmpJsonData));
});
it('check loadKmxFiles can handle two .kmx files', async function() {

View file

@ -269,11 +269,21 @@ export class KmpCompiler implements KeymanCompiler {
kmp.files = this.arrayWrap(kps.Files.File).map((file: KpsFile.KpsFileContentFile) => {
return {
name: this.normalizePath(file.Name),
description: file.Description.trim(),
description: (file.Description ?? '').trim(),
copyLocation: parseInt(file.CopyLocation, 10) || undefined
// note: we don't emit fileType as that is not permitted in kmp.json
};
});
if(!kmp.files.reduce((result: boolean, file) => {
if(!file.name) {
// as the filename field is missing or blank, we'll try with the description instead
this.callbacks.reportMessage(CompilerMessages.Error_FileRecordIsMissingName({description: file.description ?? '(no description)'}));
return false;
}
return result;
}, true)) {
return null;
}
}
kmp.files = kmp.files ?? [];

View file

@ -130,5 +130,9 @@ export class CompilerMessages {
static ERROR_InvalidPackageFile = SevError | 0x001E;
static Error_InvalidPackageFile = (o:{e:any}) => m(this.ERROR_InvalidPackageFile,
`Package source file is invalid: ${(o.e ?? 'unknown error').toString()}`);
static ERROR_FileRecordIsMissingName = SevError | 0x001F;
static Error_FileRecordIsMissingName = (o:{description:string}) => m(this.ERROR_FileRecordIsMissingName,
`File record in the package with description '${o.description}' is missing a filename.`);
}

View file

@ -36,7 +36,7 @@ export class PackageKeyboardTargetValidator {
// package also includes the .js
const targets = KeymanTargets.keymanTargetsFromString(targetsText, {expandTargets: true});
if(targets.some(target => KeymanTargets.TouchKeymanTargets.includes(target))) {
if(!kmp.files.find(file => this.callbacks.path.basename(file.name, '.js') == keyboard.id)) {
if(!kmp.files.find(file => this.callbacks.path.basename(file.name ?? '', '.js') == keyboard.id)) {
// .js version of the keyboard is not found, warn
this.callbacks.reportMessage(CompilerMessages.Warn_JsKeyboardFileIsMissing({id: keyboard.id}));
return false;

View file

@ -40,16 +40,21 @@ export class PackageMetadataCollector {
): KeyboardMetadata {
let isJavascript = false;
let file = kmp.files.find(file => this.callbacks.path.basename(file.name, KeymanFileTypes.Binary.Keyboard) == keyboard.id);
let file = kmp.files.find(file => this.callbacks.path.basename(file.name ?? '', KeymanFileTypes.Binary.Keyboard) == keyboard.id);
if(!file) {
isJavascript = true;
file = kmp.files.find(file => this.callbacks.path.basename(file.name, KeymanFileTypes.Binary.WebKeyboard) == keyboard.id);
file = kmp.files.find(file => this.callbacks.path.basename(file.name ?? '', KeymanFileTypes.Binary.WebKeyboard) == keyboard.id);
if(!file) {
this.callbacks.reportMessage(CompilerMessages.Error_KeyboardContentFileNotFound({id:keyboard.id}));
return null;
}
}
if(!file.name) {
this.callbacks.reportMessage(CompilerMessages.Error_FileRecordIsMissingName({description: file.description ?? '(no description)'}));
return null;
}
const filename = this.callbacks.resolveFilename(kpsFilename, file.name);
if(!this.callbacks.fs.existsSync(filename)) {
this.callbacks.reportMessage(CompilerMessages.Error_KeyboardFileNotFound({filename}));

View file

@ -1060,7 +1060,7 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE
u16ncpy(q, pp2, u16len(pp2) + 1);
// Change compiled reference file extension to .kvk
pp2 = ( km_core_cp *) u16chr(q, 0) - 5;
pp2 = ( km_core_cu *) u16chr(q, 0) - 5;
if (pp2 > q && u16icmp(pp2, u".kvks") == 0) {
pp2[4] = 0;
}

View file

@ -57,7 +57,7 @@
lastContent = ta1.value;
}
var lastSelStart = -1;
var lastSelStart = -1, lastSelLength = -1;
function calculateLengthByCodepoint(text, base, x) {
var stop = base + x;

View file

@ -14,10 +14,10 @@ build: version.res manifest.res icons dirs xml xsd pull-core
$(COPY) kmlmc.cmd $(DEVELOPER_PROGRAM)
$(COPY) kmlmp.cmd $(DEVELOPER_PROGRAM)
$(COPY) kmc.cmd $(DEVELOPER_PROGRAM)
$(COPY) $(KEYMAN_ROOT)\core\build\x86\$(TARGET_PATH)\src\keymancore-1.dll $(DEVELOPER_PROGRAM)
$(COPY) $(KEYMAN_ROOT)\core\build\x86\$(TARGET_PATH)\src\$(KEYMANCORE).dll $(DEVELOPER_PROGRAM)
if exist $(WIN32_TARGET_PATH)\tike.dbg $(COPY) $(WIN32_TARGET_PATH)\tike.dbg $(DEVELOPER_DEBUGPATH)
$(COPY) $(KEYMAN_ROOT)\core\build\x86\$(TARGET_PATH)\src\keymancore-1.dll $(WIN32_TARGET_PATH)
$(COPY) $(KEYMAN_ROOT)\core\build\x86\$(TARGET_PATH)\src\keymancore-1.pdb $(WIN32_TARGET_PATH)
$(COPY) $(KEYMAN_ROOT)\core\build\x86\$(TARGET_PATH)\src\$(KEYMANCORE).dll $(WIN32_TARGET_PATH)
$(COPY) $(KEYMAN_ROOT)\core\build\x86\$(TARGET_PATH)\src\$(KEYMANCORE).pdb $(WIN32_TARGET_PATH)
xsd:
$(COPY) $(KEYMAN_ROOT)\common\schemas\kps\kps.xsd $(DEVELOPER_PROGRAM)
@ -69,7 +69,7 @@ clean: def-clean
signcode:
$(SIGNCODE) /d "Keyman Developer" $(DEVELOPER_PROGRAM)\tike.exe
$(SIGNCODE) /d "Keyman Core" $(DEVELOPER_PROGRAM)\keymancore-1.dll
$(SIGNCODE) /d "Keyman Core" $(DEVELOPER_PROGRAM)\$(KEYMANCORE).dll
# Sign the Sentry executables and libraries here
$(SIGNCODE) /d "Keyman Developer" $(DEVELOPER_PROGRAM)\sentry.dll
$(SIGNCODE) /d "Keyman Developer" $(DEVELOPER_PROGRAM)\sentry.x64.dll
@ -81,7 +81,7 @@ wrap-symbols:
install:
$(COPY) $(DEVELOPER_PROGRAM)\tike.exe "$(INSTALLPATH_KEYMANDEVELOPER)\tike.exe"
$(COPY) $(DEVELOPER_PROGRAM)\keymancore-1.dll "$(INSTALLPATH_KEYMANDEVELOPER)\keymancore-1.dll"
$(COPY) $(DEVELOPER_PROGRAM)\$(KEYMANCORE).dll "$(INSTALLPATH_KEYMANDEVELOPER)\$(KEYMANCORE).dll"
test-manifest:
# test that linked manifest exists and correct

View file

@ -98,13 +98,13 @@ end;
function TDebugCore.GetKMXPlatform: string;
var
p: pkm_core_cp;
p: pkm_core_cu;
status: km_core_status;
begin
status := km_core_state_option_lookup(
FState,
KM_CORE_OPT_ENVIRONMENT,
pkm_core_cp(PWideChar(KM_CORE_KMX_ENV_PLATFORM)),
pkm_core_cu(PWideChar(KM_CORE_KMX_ENV_PLATFORM)),
p
);
if status <> KM_CORE_STATUS_OK then
@ -117,8 +117,8 @@ var
options: array[0..1] of km_core_option_item;
status: km_core_status;
begin
options[0].key := pkm_core_cp(PWideChar(KM_CORE_KMX_ENV_PLATFORM));
options[0].value := pkm_core_cp(PWideChar(Value));
options[0].key := pkm_core_cu(PWideChar(KM_CORE_KMX_ENV_PLATFORM));
options[0].value := pkm_core_cu(PWideChar(Value));
options[0].scope := KM_CORE_OPT_ENVIRONMENT;
options[1] := KM_CORE_OPTIONS_END;
status := km_core_state_options_update(FState, @options[0]);
@ -128,13 +128,13 @@ end;
function TDebugCore.GetOption(const name: string): string;
var
p: pkm_core_cp;
p: pkm_core_cu;
status: km_core_status;
begin
status := km_core_state_option_lookup(
FState,
KM_CORE_OPT_KEYBOARD,
pkm_core_cp(PWideChar(name)),
pkm_core_cu(PWideChar(name)),
p
);
if status <> KM_CORE_STATUS_OK then
@ -147,8 +147,8 @@ var
options: array[0..1] of km_core_option_item;
status: km_core_status;
begin
options[0].key := pkm_core_cp(PWideChar(Name));
options[0].value := pkm_core_cp(PWideChar(Value));
options[0].key := pkm_core_cu(PWideChar(Name));
options[0].value := pkm_core_cu(PWideChar(Value));
options[0].scope := KM_CORE_OPT_KEYBOARD;
options[1] := KM_CORE_OPTIONS_END;
status := km_core_state_options_update(FState, @options[0]);

View file

@ -21,8 +21,8 @@ type
km_core_usv = uint32_t; // UTF-32
pkm_core_usv = ^km_core_usv;
km_core_cp = WideChar;
pkm_core_cp = ^km_core_cp;
km_core_cu = WideChar;
pkm_core_cu = ^km_core_cu;
km_core_context = record end;
pkm_core_context = ^km_core_context;
@ -81,7 +81,7 @@ const
);
const
keymancore = 'keymancore-1.dll';
keymancore = 'keymancore-2.dll';
procedure km_core_context_items_dispose(
context_items: pkm_core_context_item
@ -114,8 +114,8 @@ type
);
km_core_option_item = record
key: pkm_core_cp;
value: pkm_core_cp;
key: pkm_core_cu;
value: pkm_core_cu;
scope: km_core_option_scope;
end;
@ -220,8 +220,8 @@ function km_core_options_list_size(
function km_core_state_option_lookup(
state: pkm_core_state;
scope: km_core_option_scope;
key: pkm_core_cp;
var value: pkm_core_cp
key: pkm_core_cu;
var value: pkm_core_cu
): km_core_status; cdecl; external keymancore delayed;
function km_core_state_options_update(
@ -237,8 +237,8 @@ function km_core_state_options_to_json(
type
km_core_keyboard_attrs = record
version_string: pkm_core_cp;
id: pkm_core_cp;
version_string: pkm_core_cu;
id: pkm_core_cu;
folder_path: km_core_path_name;
default_optons: pkm_core_option_item
end;

View file

@ -14,7 +14,7 @@ uses
{$ALIGN 8}
///
/// The maximum size of context in km_core_cp units for a single debug
/// The maximum size of context in km_core_cu units for a single debug
/// event. This is taken from MAXCONTEXT in keyman32 (Windows) and is purely
/// a convenience value. We can increase it if there is a demonstrated need.
///
@ -54,7 +54,7 @@ pkm_core_state_debug_key_info = ^km_core_state_debug_key_info;
km_core_state_debug_kmx_option_info = record
store: Pointer; // LPSTORE
value: array[0..DEBUG_MAX_CONTEXT-1] of km_core_cp; // value to be saved into the store
value: array[0..DEBUG_MAX_CONTEXT-1] of km_core_cu; // value to be saved into the store
end;
pkm_core_state_debug_kmx_option_info = ^km_core_state_debug_kmx_option_info;
@ -71,7 +71,7 @@ pkm_core_state_debug_kmx_option_info = ^km_core_state_debug_kmx_option_info;
///
km_core_state_debug_kmx_info = record
context: array [0..DEBUG_MAX_CONTEXT-1] of km_core_cp; // The context matched by the rule (? may not need this?) // TODO: rename to context_matched
context: array [0..DEBUG_MAX_CONTEXT-1] of km_core_cu; // The context matched by the rule (? may not need this?) // TODO: rename to context_matched
group: Pointer; // LPGROUP
rule: Pointer; // LPKEY
store_offsets: array [0..DEBUG_STORE_OFFSETS_SIZE-1] of uint16_t; // pairs--store, char position, terminated by 0xFFFF // TODO use a better structure here

View file

@ -49,7 +49,7 @@ work particularly well with C++, so it might flag some C++ symbols even though
they aren't part of the API. This happens particularly with C++ template
instantiations.
To work around this, we list the C++ symbols as `optional` that get flaged:
To work around this, we list the C++ symbols as `optional` that get flagged:
```
(c++|optional)"typeinfo name for std::codecvt_utf8_utf16<char16_t, 1114111ul, (std::codecvt_mode)0>@Base" 17.0.244

View file

@ -116,7 +116,7 @@ Architecture: amd64 arm64 armel armhf i386 loong64 mipsel mips64el ppc64el riscv
Section: libdevel
Depends:
libicu-dev,
libkeymancore1 (= ${binary:Version}),
libkeymancore2 (= ${binary:Version}),
${misc:Depends},
Conflicts: libkmnkbp-dev
Replaces: libkmnkbp-dev
@ -138,7 +138,7 @@ Description: Development files for Keyman keyboard processing library
.
This package contains development headers and libraries.
Package: libkeymancore1
Package: libkeymancore2
Architecture: amd64 arm64 armel armhf i386 loong64 mipsel mips64el ppc64el riscv64
Section: libs
Pre-Depends:
@ -148,8 +148,8 @@ Depends:
${shlibs:Depends},
Suggests:
keyman,
Conflicts: libkmnkbp0-0, libkeymancore
Replaces: libkmnkbp0-0, libkeymancore
Conflicts: libkmnkbp0-0, libkeymancore, libkeymancore1
Replaces: libkmnkbp0-0, libkeymancore, libkeymancore1
Multi-Arch: same
Description: Keyman keyboard processing library
Originally created in 1993 to type Lao on Windows, Keyman is now a free and
@ -170,7 +170,7 @@ Package: ibus-keyman
Architecture: amd64 arm64 armel armhf i386 loong64 mipsel mips64el ppc64el riscv64
Depends:
ibus (>= 1.3.7),
libkeymancore1 (= ${binary:Version}),
libkeymancore2 (= ${binary:Version}),
keyman-system-service (= ${binary:Version}),
${misc:Depends},
${shlibs:Depends},

View file

@ -1,4 +1,4 @@
libkeymancore.so.1 libkeymancore1 #MINVER#
libkeymancore.so.2 libkeymancore2 #MINVER#
* Build-Depends-Package: libkeymancore-dev
(c++|optional)"typeinfo name for std::codecvt_utf8_utf16<char16_t, 1114111ul, (std::codecvt_mode)0>@Base" 17.0.244
@ -8,7 +8,7 @@ libkeymancore.so.1 libkeymancore1 #MINVER#
km_core_context_items_dispose@Base 17.0.195
km_core_context_length@Base 17.0.195
km_core_context_set@Base 17.0.195
km_core_cp_dispose@Base 17.0.263
km_core_cu_dispose@Base 18.0.31
km_core_event@Base 17.0.195
km_core_get_engine_attrs@Base 17.0.195
km_core_keyboard_dispose@Base 17.0.195

View file

@ -219,9 +219,9 @@ static gchar *
get_context_debug(IBusEngine *engine) {
IBusKeymanEngine *keyman = (IBusKeymanEngine *)engine;
km_core_cp *buf = km_core_state_context_debug(keyman->state, KM_CORE_DEBUG_CONTEXT_CACHED);
km_core_cu *buf = km_core_state_context_debug(keyman->state, KM_CORE_DEBUG_CONTEXT_CACHED);
gchar *result = g_utf16_to_utf8((gunichar2 *)buf, -1, NULL, NULL, NULL);
km_core_cp_dispose(buf);
km_core_cu_dispose(buf);
if(result) {
return result;
}
@ -292,7 +292,7 @@ set_context_if_needed(IBusEngine *engine) {
g_message("%s: new application context: |%s| (len:%u) cursor:%d anchor:%d", __FUNCTION__,
application_context_utf8, context_end - context_start, cursor_pos, anchor_pos);
km_core_cp *application_context_utf16 = g_utf8_to_utf16(application_context_utf8, -1, NULL, NULL, NULL);
km_core_cu *application_context_utf16 = g_utf8_to_utf16(application_context_utf8, -1, NULL, NULL, NULL);
km_core_context_status result;
result = km_core_state_context_set_if_needed(keyman->state, application_context_utf16);
g_free(application_context_utf16);
@ -326,7 +326,7 @@ ibus_keyman_engine_init(IBusKeymanEngine *keyman) {
keyman->state = NULL;
}
static km_core_cp* get_base_layout()
static km_core_cu* get_base_layout()
{
return u"en-US";
@ -354,7 +354,7 @@ static km_core_cp* get_base_layout()
lang = strdup("en-US");
}
g_message("lang is %s", lang);
km_core_cp *cp = g_utf8_to_utf16(lang, -1, NULL, NULL, NULL);
km_core_cu *cp = g_utf8_to_utf16(lang, -1, NULL, NULL, NULL);
return cp;
// g_free(lang);
#endif
@ -395,8 +395,8 @@ free_km_core_option_item(gpointer data) {
return;
km_core_option_item *opt = (km_core_option_item *)data;
g_free((km_core_cp *)opt->key);
g_free((km_core_cp *)opt->value);
g_free((km_core_cu *)opt->key);
g_free((km_core_cu *)opt->value);
g_free(opt);
}

View file

@ -487,7 +487,7 @@ keyman_get_options_queue_fromdconf(gchar *package_id,
g_message("Keyboard Option [%d], %s=%s", index, option_tokens[0], option_tokens[1]);
km_core_option_item *opt = g_new0(km_core_option_item, 1);
opt[0].scope = KM_CORE_OPT_KEYBOARD;
km_core_cp *ocp = g_utf8_to_utf16(option_tokens[0], -1, NULL, NULL, NULL);
km_core_cu *ocp = g_utf8_to_utf16(option_tokens[0], -1, NULL, NULL, NULL);
opt[0].key = ocp;
ocp = g_utf8_to_utf16 (option_tokens[1], -1, NULL, NULL, NULL);
opt[0].value = ocp;

View file

@ -8,6 +8,7 @@
#import "AppDelegate.h"
#import <KeymanEngine4Mac/KeymanEngine4Mac.h>
#import <os/log.h>
static BOOL debugMode = YES;
@ -67,7 +68,9 @@ NSString *const kKMXFileKey = @"KMXFile";
}
- (void)windowDidResize:(NSNotification *)notification {
[self.oskView resizeOSKLayout];
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "AppDelegate windowDidResize");
[self.oskView resizeOSKLayout];
}
- (BOOL)createEventTap {
@ -205,7 +208,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef
[alert addButtonWithTitle:@"OK"];
[alert setMessageText:@"Invalid KMX file"];
[alert setInformativeText:@"This KMX file contains some invalid code!"];
[alert setAlertStyle:NSWarningAlertStyle];
[alert setAlertStyle:NSAlertStyleWarning];
[alert runModal];
}

View file

@ -11,7 +11,7 @@
@implementation KMBarView
- (void)drawRect:(NSRect)rect {
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext];
NSRect rect1 = NSMakeRect(0, 0, rect.size.width*0.56, rect.size.height);
NSRect rect2 = NSMakeRect(rect1.size.width, 0, rect.size.width*0.23, rect.size.height);

View file

@ -30,9 +30,9 @@
// NSLog(@"topFill origin x %f y %f size h %f w %f after raising to imgHeight %ld", topFill.origin.x, topFill.origin.y, topFill.size.height, topFill.size.width, imgOriginHeightDelta);
// NSLog(@"botFill origin x %f y %f size h %f w %f after reducing by imgHeight %ld", botFill.origin.x, botFill.origin.y, botFill.size.height, botFill.size.width, imgOriginHeightDelta);
[[NSColor whiteColor] setFill];
NSRectFillUsingOperation(topFill, NSCompositeSourceOver);
NSRectFillUsingOperation(topFill, NSCompositingOperationSourceOver);
[[NSColor windowBackgroundColor] setFill];
NSRectFillUsingOperation(botFill, NSCompositeSourceOver);
NSRectFillUsingOperation(botFill, NSCompositingOperationSourceOver);
}
- (BOOL)mouseDownCanMoveWindow {

View file

@ -11,7 +11,7 @@
@implementation KMBarView
- (void)drawRect:(NSRect)rect {
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext];
NSRect rect1 = NSMakeRect(0, 0, rect.size.width*0.56, rect.size.height);
NSRect rect2 = NSMakeRect(rect1.size.width, 0, rect.size.width*0.23, rect.size.height);

View file

@ -216,7 +216,7 @@
[textField setEditable:NO];
[textField setBordered:NO];
[textField setBackgroundColor:[NSColor clearColor]];
[textField setAlignment:NSLeftTextAlignment];
[textField setAlignment:NSTextAlignmentLeft];
[textField setFont:[NSFont systemFontOfSize:tableView.rowHeight*0.5]];
[textField setTextColor:[NSColor colorWithSRGBRed:0.0 green:0.0 blue:0.1 alpha:1.0]];
[textField setStringValue:[info objectForKey:@"HeaderTitle"]];
@ -471,7 +471,7 @@
[failure setMessageText:[NSString localizedStringWithFormat:errorString, kmpFile.lastPathComponent]];
[failure setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]];
[failure setAlertStyle:NSWarningAlertStyle];
[failure setAlertStyle:NSAlertStyleWarning];
[failure beginSheetModalForWindow:self.window
modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
@ -534,7 +534,7 @@
[_deleteAlertView setInformativeText:NSLocalizedString(@"info-cannot-undo-delete-keyboard", nil)];
[_deleteAlertView addButtonWithTitle:NSLocalizedString(@"button-delete-keyboard", nil)];
[_deleteAlertView addButtonWithTitle:NSLocalizedString(@"button-cancel-delete-keyboard", nil)];
[_deleteAlertView setAlertStyle:NSWarningAlertStyle];
[_deleteAlertView setAlertStyle:NSAlertStyleWarning];
[_deleteAlertView setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]];
}
@ -547,7 +547,7 @@
[_confirmKmpInstallAlertView addButtonWithTitle:NSLocalizedString(@"button-install-keyboard", nil)];
[_confirmKmpInstallAlertView addButtonWithTitle:NSLocalizedString(@"button-cancel-install-keyboard", nil)];
[_confirmKmpInstallAlertView setMessageText:NSLocalizedString(@"message-confirm-install-keyboard", nil)];
[_confirmKmpInstallAlertView setAlertStyle:NSInformationalAlertStyle];
[_confirmKmpInstallAlertView setAlertStyle:NSAlertStyleInformational];
[_confirmKmpInstallAlertView setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]];
}

View file

@ -224,12 +224,7 @@ NSString* _keymanDataPath = nil;
_downloadFilename = [NSString stringWithString:[value substringFromIndex:index+9]];
else if ((index = [value rangeOfString:@"url="].location) != NSNotFound) {
NSString *urlString = [NSString stringWithString:[value substringFromIndex:index+4]];
if ([urlString respondsToSelector:@selector(stringByRemovingPercentEncoding)])
urlString = [urlString stringByRemovingPercentEncoding];
else if ([urlString respondsToSelector:@selector(stringByReplacingPercentEscapesUsingEncoding:)]) {
// OS version prior to 10.9 - use this (now deprecated) method instead:
urlString = [urlString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
urlString = [urlString stringByRemovingPercentEncoding];
downloadUrl = [NSURL URLWithString:urlString];
}
}
@ -1161,7 +1156,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef
[_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-downloading", nil)];
[_downloadInfoView setInformativeText:@""];
[_downloadInfoView addButtonWithTitle:NSLocalizedString(@"button-cancel-downloading", nil)];
[_downloadInfoView setAlertStyle:NSInformationalAlertStyle];
[_downloadInfoView setAlertStyle:NSAlertStyleInformational];
[_downloadInfoView setAccessoryView:self.progressIndicator];
}

View file

@ -119,7 +119,7 @@ NSString* const kEasterEggKmxName = @"EnglishSpanish.kmx";
- (CoreKeyOutput*) processEventWithKeymanEngine:(NSEvent *)event in:(id) sender {
CoreKeyOutput* coreKeyOutput = nil;
if (self.appDelegate.lowLevelEventTap != nil) {
NSEvent *eventWithOriginalModifierFlags = [NSEvent keyEventWithType:event.type location:event.locationInWindow modifierFlags:self.appDelegate.currentModifierFlags timestamp:event.timestamp windowNumber:event.windowNumber context:event.context characters:event.characters charactersIgnoringModifiers:event.charactersIgnoringModifiers isARepeat:event.isARepeat keyCode:event.keyCode];
NSEvent *eventWithOriginalModifierFlags = [NSEvent keyEventWithType:event.type location:event.locationInWindow modifierFlags:self.appDelegate.currentModifierFlags timestamp:event.timestamp windowNumber:event.windowNumber context:[NSGraphicsContext currentContext] characters:event.characters charactersIgnoringModifiers:event.charactersIgnoringModifiers isARepeat:event.isARepeat keyCode:event.keyCode];
coreKeyOutput = [self.kme processEvent:eventWithOriginalModifierFlags];
[self.appDelegate logDebugMessage:@"processEventWithKeymanEngine, using AppDelegate.currentModifierFlags %lu, instead of event.modifiers = %lu", (unsigned long)self.appDelegate.currentModifierFlags, (unsigned long)event.modifierFlags];
}
@ -223,7 +223,7 @@ NSString* const kEasterEggKmxName = @"EnglishSpanish.kmx";
// mouse movement requires that the context be invalidated
[self handleContextChangedByLowLevelEvent];
if (event.type == NSKeyDown) {
if (event.type == NSEventTypeKeyDown) {
// indicates that our generated backspace event(s) are consumed
// and we can insert text that followed the backspace(s)
if (event.keyCode == kKeymanEventKeyCode) {
@ -253,7 +253,7 @@ NSString* const kEasterEggKmxName = @"EnglishSpanish.kmx";
return NO; // let the client app handle all Command-key events.
}
if (event.type == NSKeyDown) {
if (event.type == NSEventTypeKeyDown) {
[self reportContext:event forClient:sender];
handled = [self handleEventWithKeymanEngine:event in: sender];
}

View file

@ -69,14 +69,13 @@ const CGKeyCode kKeymanEventKeyCode = 0xFF;
NSRunningApplication *app = NSWorkspace.sharedWorkspace.frontmostApplication;
pid_t processId = app.processIdentifier;
NSString *bundleId = app.bundleIdentifier;
GetProcessForPID(processId, &psn);
[self.appDelegate logDebugMessage:@"sendKeymanKeyCodeForEvent keyCode %lu to app %@ with pid %d", (unsigned long)kKeymanEventKeyCode, bundleId, processId];
// use nil as source, as this generated event is not directly tied to the originating event
CGEventRef keyDownEvent = CGEventCreateKeyboardEvent(nil, kKeymanEventKeyCode, true);
CGEventPostToPSN(&psn, keyDownEvent);
CGEventPostToPid(processId, keyDownEvent);
CFRelease(keyDownEvent);
// this is not a real keycode, so we do not need a key up event

View file

@ -8,6 +8,7 @@
#import "OSKWindowController.h"
#import "KMInputMethodAppDelegate.h"
#import <os/log.h>
@interface OSKWindowController ()
@property (nonatomic, strong) NSButton *helpButton;
@ -29,6 +30,8 @@
}
- (void)awakeFromNib {
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKWC awakeFromNib");
// Keep the aspect ratio constant at its current value
[self.window setAspectRatio:self.window.frame.size];
NSSize size = self.window.frame.size;
@ -43,7 +46,7 @@
_helpButton = helpBtn;
[_helpButton setTitle:@""];
[_helpButton setBezelStyle:NSHelpButtonBezelStyle];
[_helpButton setControlSize:NSMiniControlSize];
[_helpButton setControlSize:NSControlSizeMini];
[_helpButton setAction:@selector(helpAction:)];
[_helpButton setEnabled:[self hasHelpDocumentation]];
[self.window addViewToTitleBar:_helpButton positionX:NSWidth(self.window.frame) - NSWidth(_helpButton.frame) -10];
@ -51,6 +54,8 @@
}
- (void)windowDidLoad {
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKWC windowDidLoad");
[super windowDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:self.window];
[self.oskView setKvk:[self.AppDelegate kvk]];
@ -59,6 +64,8 @@
}
- (void)windowDidResize:(NSNotification *)notification {
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKWC windowDidResize");
[self.oskView resizeOSKLayout];
}
@ -80,6 +87,8 @@
}
- (void)resetOSK {
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKWC windowDidLoad");
[self.oskView setKvk:[self.AppDelegate kvk]];
[self.oskView resetOSK];
if (_helpButton) {

View file

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9059" systemVersion="14F27" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9059"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22689"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="OSKWindowController">
@ -13,16 +14,16 @@
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Keyman" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" animationBehavior="default" id="F0z-JX-Cv5">
<window title="Keyman" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" animationBehavior="default" id="F0z-JX-Cv5">
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="614" height="212"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1057"/>
<view key="contentView" id="se5-gp-TjO">
<rect key="frame" x="0.0" y="1" width="614" height="212"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1055"/>
<view key="contentView" clipsToBounds="YES" id="se5-gp-TjO">
<rect key="frame" x="0.0" y="0.0" width="614" height="212"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="UaK-0H-MfR" customClass="OSKView">
<customView clipsToBounds="YES" translatesAutoresizingMaskIntoConstraints="NO" id="UaK-0H-MfR" customClass="OSKView">
<rect key="frame" x="5" y="5" width="604" height="202"/>
</customView>
</subviews>

View file

@ -8,16 +8,23 @@
#import <Cocoa/Cocoa.h>
#import <InputMethodKit/InputMethodKit.h>
#import <os/log.h>
const NSString *kConnectionName = @"Keyman_Input_Connection";
IMKServer *server;
int main(int argc, const char * argv[]) {
NSString *identifier;
os_log_t configLog = os_log_create("org.sil.keyman", "startup");
@autoreleasepool {
identifier = [[NSBundle mainBundle] bundleIdentifier];
server = [[IMKServer alloc] initWithName:(NSString *)kConnectionName bundleIdentifier:identifier];
[NSBundle loadNibNamed:@"MainMenu" owner:[NSApplication sharedApplication]];
BOOL didLoadNib = [[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:[NSApplication sharedApplication] topLevelObjects: nil];
os_log_with_type(configLog, OS_LOG_TYPE_DEBUG, "main Did load MainMenu nib: %@", didLoadNib?@"YES":@"NO");
[[NSApplication sharedApplication] run];
}
return 0;

View file

@ -32,7 +32,6 @@
-(NSString *)description
{
NSString* str = @"teststring";
NSData* data = [self.textToInsert dataUsingEncoding:NSUTF16LittleEndianStringEncoding];
return [[NSString alloc] initWithFormat: @"codePointsToDeleteBeforeInsert: %li, textToInsert: '%@', optionsToPersist: %@, alert: %d, emitKeystroke: %d, capsLockState: %d ", self.codePointsToDeleteBeforeInsert, data, self.optionsToPersist, self.alert, self.emitKeystroke, self.capsLockState];

View file

@ -184,7 +184,7 @@ const int CORE_ENVIRONMENT_ARRAY_LENGTH = 6;
NSString* deletedText = [self.coreHelper utf32CStringToString:actions->deleted_context];
CoreKeyOutput* coreKeyOutput = [[CoreKeyOutput alloc] init: actions->code_points_to_delete textToDelete:deletedText textToInsert:text optionsToPersist:options alert:actions->do_alert emitKeystroke:actions->emit_keystroke capsLockState:capsLock];
return coreKeyOutput;
}
@ -235,9 +235,9 @@ const int CORE_ENVIRONMENT_ARRAY_LENGTH = 6;
}
-(NSString*)contextDebug {
km_core_cp * context = km_core_state_context_debug(self.coreState, KM_CORE_DEBUG_CONTEXT_CACHED);
km_core_cu * context = km_core_state_context_debug(self.coreState, KM_CORE_DEBUG_CONTEXT_CACHED);
NSString *debugString = [self.coreHelper createNSStringFromUnicharString:context];
km_core_cp_dispose(context);
km_core_cu_dispose(context);
[self.coreHelper logDebugMessage:@"CoreWrapper contextDebug = %@", debugString];
return debugString;
@ -285,8 +285,8 @@ const int CORE_ENVIRONMENT_ARRAY_LENGTH = 6;
return (result==KM_CORE_STATUS_OK);
}
-(void)readCoreOptions: (km_core_cp const *) key {
km_core_cp const * valueFromCore = nil;
-(void)readCoreOptions: (km_core_cu const *) key {
km_core_cu const * valueFromCore = nil;
km_core_status result =
km_core_state_option_lookup(self.coreState,
KM_CORE_OPT_KEYBOARD,

View file

@ -10,6 +10,7 @@
#import "KeyLabel.h"
#import "MacVKCodes.h"
#import "TimerTarget.h"
#import <os/log.h>
CGFloat lw = 1.0;
CGFloat r = 7.0;
@ -27,20 +28,22 @@ static CGFloat const kRelativeModifierLabelHeight = 0.30f;
@property (nonatomic, assign) BOOL isCharacterKey;
@property (nonatomic, strong) KeyLabel *label;
@property (nonatomic, strong) NSTextField *caption;
@property (nonatomic, strong) NSImageView *bitmapView;
@property (nonatomic, strong) NSColor *bgColor1;
@property (nonatomic, strong) NSColor *bgColor2;
@property (nonatomic, strong) NSColor *bgColorRegularKey;
@property (nonatomic, strong) NSColor *bgColorSpecialKey;
@property (nonatomic, strong) NSTimer *keyEventTimer;
@property (readwrite) NSInteger tag;
@end
@implementation KeyView
@synthesize tag;
@synthesize bgColor1, bgColor2;
@synthesize bgColorRegularKey, bgColorSpecialKey;
- (id)initWithFrame:(NSRect)frame {
os_log_t oskKeyLog = os_log_create("org.sil.keyman", "osk-key");
self = [super initWithFrame:frame];
if (self) {
os_log_with_type(oskKeyLog, OS_LOG_TYPE_DEBUG, "KeyView initWithFrame: %{public}@, bounds: %{public}@, default clipsToBounds %{public}@", NSStringFromRect(frame), NSStringFromRect(self.bounds), self.clipsToBounds?@"YES":@"NO");
self.clipsToBounds = true;
CGSize size = frame.size;
CGFloat x = size.width*0.05;
NSRect labelFrame = NSMakeRect(x, 0, size.width -lw -2*x, size.height);
@ -48,7 +51,7 @@ static CGFloat const kRelativeModifierLabelHeight = 0.30f;
[_label setEditable:NO];
[_label setBordered:NO];
[_label setDrawsBackground:NO];
[_label setAlignment:NSCenterTextAlignment];
[_label setAlignment:NSTextAlignmentCenter];
if ([_caption respondsToSelector:@selector(setLineBreakMode:)]) {
[_label setLineBreakMode:NSLineBreakByClipping];
} // There might be some problem not calling this, but it seems to be okay as far as I can tell
@ -60,22 +63,26 @@ static CGFloat const kRelativeModifierLabelHeight = 0.30f;
[_label setLineBreakMode:NSLineBreakByClipping];
[self addSubview:_label];
bgColor1 = [self getOpaqueColorWithRed:209 green:211 blue:212];
bgColor2 = [self getOpaqueColorWithRed:166 green:169 blue:172];
bgColorRegularKey = [self getOpaqueColorWithRed:209 green:211 blue:212];
bgColorSpecialKey = [self getOpaqueColorWithRed:166 green:169 blue:172];
}
return self;
}
- (void)drawRect:(NSRect)rect {
os_log_t oskKeyLog = os_log_create("org.sil.keyman", "osk-key");
os_log_with_type(oskKeyLog, OS_LOG_TYPE_DEBUG, "KeyView drawRect: %{public}@, bounds: %{public}@, keyCode: 0x%lx, caption: %{public}@, label: %{public}@", NSStringFromRect(rect), NSStringFromRect(self.bounds), self.keyCode, self.caption.stringValue, self.label.stringValue);
[[self getOpaqueColorWithRed:241 green:242 blue:242] setFill];
NSRectFillUsingOperation(rect, NSCompositeSourceOver);
NSRectFillUsingOperation(rect, NSCompositingOperationSourceOver);
// Drawing code here.
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext];
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineWidth(context, lw);
CGContextSetStrokeColorWithColor(context, bgColor1.CGColor);
CGContextSetStrokeColorWithColor(context, bgColorRegularKey.CGColor);
CGFloat x = rect.origin.x + lw;
CGFloat y = rect.origin.y + lw;
@ -100,10 +107,10 @@ static CGFloat const kRelativeModifierLabelHeight = 0.30f;
CGContextClosePath(context);
CGContextClip(context);
NSColor *bgColor = bgColor1;
NSColor *bgColor = bgColorRegularKey;
if ([self isSpecialKey])
bgColor = bgColor2;
bgColor = bgColorSpecialKey;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat gradientLocations[] = {0, 1};
@ -238,7 +245,7 @@ static CGFloat const kRelativeModifierLabelHeight = 0.30f;
[_caption setBordered:NO];
[_caption setDrawsBackground:NO];
//[_caption setBackgroundColor:[NSColor yellowColor]];
[_caption setAlignment:NSLeftTextAlignment];
[_caption setAlignment:NSTextAlignmentLeft];
if ([_caption respondsToSelector:@selector(setLineBreakMode:)]) {
[_caption setLineBreakMode:NSLineBreakByClipping];
} // There might be some problem not calling this, but it seems to be okay as far as I can tell
@ -325,26 +332,18 @@ static CGFloat const kRelativeModifierLabelHeight = 0.30f;
- (void)setKeyPressed:(BOOL)keyPressed {
_keyPressed = keyPressed;
if (keyPressed) {
bgColor1 = [self getOpaqueColorWithRed:109 green:111 blue:112];
bgColor2 = [self getOpaqueColorWithRed:236 green:239 blue:242];
bgColorRegularKey = [self getOpaqueColorWithRed:109 green:111 blue:112];
bgColorSpecialKey = [self getOpaqueColorWithRed:236 green:239 blue:242];
[self setNeedsDisplay:YES];
}
else {
bgColor1 = [self getOpaqueColorWithRed:209 green:211 blue:212];
bgColor2 = [self getOpaqueColorWithRed:166 green:169 blue:172];
bgColorRegularKey = [self getOpaqueColorWithRed:209 green:211 blue:212];
bgColorSpecialKey = [self getOpaqueColorWithRed:166 green:169 blue:172];
[self setNeedsDisplay:YES];
}
}
- (NSColor *)getOpaqueColorWithRed:(NSUInteger) red green: (NSUInteger) green blue: (NSUInteger) blue {
// RGB is what was in the code originally I can't tell any difference between that and SRGB for the
// colors we're using in the OSK, but at the risk of causing an unintended change, I'm leaving it as
// it was for versions of macOS that support colorWithRed:green:blue:
if ([NSColor respondsToSelector:@selector(colorWithRed:green:blue:alpha:)]) {
return [NSColor colorWithRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:1.0];
}
else {
return [NSColor colorWithSRGBRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:1.0];
}
}
@end

View file

@ -7,12 +7,15 @@
//
#import "OSKKey.h"
#import <os/log.h>
@implementation OSKKey
- (id)initWithKeyCode:(NSUInteger)keyCode caption:(NSString *)caption scale:(CGFloat)scale {
self = [super init];
if (self) {
os_log_t oskKeyLog = os_log_create("org.sil.keyman", "osk-key");
os_log_with_type(oskKeyLog, OS_LOG_TYPE_DEBUG, "OSKKey initWithKeyCode: 0x%lx, caption: %{public}@, scale: %f", keyCode, caption, scale);
_keyCode = keyCode;
if (caption == nil)

View file

@ -16,6 +16,7 @@
#import "CoreHelper.h"
#include <Carbon/Carbon.h>
#import <os/log.h>
@interface OSKView()
@property (nonatomic, strong) NSArray *oskLayout;
@ -32,6 +33,8 @@
@synthesize tag;
- (id)initWithFrame:(NSRect)frame {
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView initWithFrame: %{public}@", NSStringFromRect(frame));
self = [super initWithFrame:frame];
if (self) {
// Custom initialization
@ -42,7 +45,10 @@
}
- (void)drawRect:(NSRect)rect {
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView drawRect: %{public}@", NSStringFromRect(rect));
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext];
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineWidth(context, 1.0);
CGColorRef cgClearColor = CGColorGetConstantColor(kCGColorClear);
@ -57,9 +63,10 @@
CGContextAddRect(context, CGRectMake(1.0, 1.0, rect.size.width-1.0, rect.size.height-1.0));
CGContextClip(context);
//TODO: gradient from clear to clear -- what does this do?
NSColor *bgColor = [NSColor clearColor]; //[NSColor colorWithWhite:0.7 alpha:1.0];
NSColor *bgColor2 = [NSColor clearColor]; //[NSColor colorWithWhite:0.5 alpha:1.0];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSArray *gradientColors = [NSArray arrayWithObjects:(id)bgColor.CGColor, bgColor2.CGColor, nil];
CGFloat gradientLocations[] = {0, 1};
@ -97,6 +104,8 @@
}
- (void)setKvk:(KVKFile *)kvk {
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView setKvk, forces keyboard to re-layout");
_kvk = kvk;
// Force the keyboard to re-layout
@ -107,6 +116,8 @@
}
- (void)initOSKKeys {
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView initOSKKeys");
CGFloat viewWidth = self.frame.size.width;
CGFloat viewHeight = self.frame.size.height;
CGFloat margin = 2.0;
@ -141,6 +152,8 @@
- (NSArray *)oskLayout {
if (_oskLayout == nil) {
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "oskLayout -> creating new arrays of OSKKey objects");
NSArray *row1 = [NSArray arrayWithObjects:
[[OSKKey alloc] initWithKeyCode:MVK_GRAVE caption:@"`" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_1 caption:@"1" scale:1.0],
@ -225,6 +238,8 @@
- (NSArray *)oskDefaultNKeys {
if (_oskDefaultNKeys == nil) {
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "oskDefaultNKeys -> creating new arrays of default number OSKKey objects");
NSMutableArray *defNKeys = [[NSMutableArray alloc] initWithCapacity:0];
// row 1
@ -395,6 +410,8 @@
}
- (void)resizeOSKLayout {
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView resizeOSKLayout, removing all superviews");
[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
[self initOSKKeys];
}
@ -402,9 +419,11 @@
- (void)keyAction:(id)sender {
KeyView *keyView = (KeyView *)sender;
NSUInteger keyCode = [keyView.key keyCode];
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView keyAction keyCode: 0x%lx", keyCode);
if (keyCode < 0x100) {
ProcessSerialNumber psn;
GetFrontProcess(&psn);
NSRunningApplication *app = NSWorkspace.sharedWorkspace.frontmostApplication;
pid_t processId = app.processIdentifier;
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStatePrivate);
CGEventRef keyDownEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, true);
CGEventRef keyUpEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, false);
@ -420,8 +439,8 @@
CGEventSetFlags(keyDownEvent, CGEventGetFlags(keyDownEvent) | kCGEventFlagMaskControl);
CGEventSetFlags(keyUpEvent, CGEventGetFlags(keyUpEvent) | kCGEventFlagMaskControl);
}
CGEventPostToPSN(&psn, keyDownEvent);
CGEventPostToPSN(&psn, keyUpEvent);
CGEventPostToPid(processId, keyDownEvent);
CGEventPostToPid(processId, keyUpEvent);
CFRelease(source);
CFRelease(keyDownEvent);
CFRelease(keyUpEvent);
@ -440,12 +459,14 @@
}
- (void)handleKeyEvent:(NSEvent *)event {
os_log_t oskLog = os_log_create("org.sil.keyman", "osk");
os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView handleKeyEvent event.type: %lu", event.type);
NSView *view = [self viewWithTag:event.keyCode|0x1000];
if (view == nil || ![view isKindOfClass:[KeyView class]])
return;
KeyView *keyView = (KeyView *)view;
if (event.type == NSKeyDown)
if (event.type == NSEventTypeKeyDown)
[keyView setKeyPressed:YES];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(setKeyPressedOff:) object:keyView];
[self performSelector:@selector(setKeyPressedOff:) withObject:keyView afterDelay:0.1];
@ -624,7 +645,7 @@
}
- (void)setOskCtrlState:(BOOL)oskCtrlState {
if (_oskCtrlState != oskCtrlState && !self.ctrlState) {
if (_oskCtrlState != oskCtrlState && !self.ctrlState) {
_oskCtrlState = oskCtrlState;
KeyView *ctrlKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_CTRL|0x1000];
KeyView *ctrlKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_CTRL|0x1000];

View file

@ -40,6 +40,7 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardDownloa
context = this;
SentryAndroid.init(context, options -> {
options.setEnableAutoSessionTracking(false);
options.setRelease(com.firstvoices.keyboards.BuildConfig.VERSION_GIT_TAG);
options.setEnvironment(com.firstvoices.keyboards.BuildConfig.VERSION_ENVIRONMENT);
});

View file

@ -49,6 +49,7 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
if (DependencyUtil.libraryExists(LibraryType.SENTRY) && !Sentry.isEnabled()) {
Log.d(TAG, "Initializing Sentry");
SentryAndroid.init(getApplicationContext(), options -> {
options.setEnableAutoSessionTracking(false);
options.setRelease(com.firstvoices.keyboards.BuildConfig.VERSION_GIT_TAG);
options.setEnvironment(com.firstvoices.keyboards.BuildConfig.VERSION_ENVIRONMENT);
});

View file

@ -13,11 +13,11 @@ fv,fv_diitiidatx,Diidiitidq,BC Coast,fv_diitiidatx_kmw-9.0.js,9.1.3,nuk-Latn,Nuu
fv,fv_gitsenimx,Gitsenimx̱,BC Coast,fv_gitsenimx_kmw-9.0.js,10.0.1,git,Gitxsan (Latin)
fv,fv_hailzaqvla,Haiɫzaqvla,BC Coast,fv_hailzaqvla_kmw-9.0.js,9.5.1,hei,Heiltsuk (Latin)
fv,fv_haisla,Haisla,BC Coast,fv_haisla.js,2.0.1,has-Latn,Haisla (Latin)
fv,fv_halqemeylem,Halq'eméylem,BC Coast,fv_halqemeylem_kmw-9.0.js,9.1.3,hur-Latn,Halkomelem (Latin)
fv,fv_halqemeylem,Halq'eméylem,BC Coast,fv_halqemeylem_kmw-9.0.js,9.2,hur-Latn,Halkomelem (Latin)
fv,fv_henqeminem,Hǝn̓q̓ǝmin̓ǝm,BC Coast,fv_henqeminem_kmw-9.0.js,10.0.1,hur-Latn,Halkomelem (Latin)
fv,fv_klahoose,Homalco-Klahoose-Sliammon,BC Coast,fv_klahoose_kmw-9.0.js,10.1,coo,Comox
fv,fv_hulquminum,Hulquminum,BC Coast,fv_hulquminum_kmw-9.0.js,9.1,hur-Latn,Halkomelem (Latin)
fv,fv_hulquminum_combine,Hul̓q̓umin̓um̓,BC Coast,fv_hulquminum_combine_kmw-9.0.js,1.0,hur-Latn,Halkomelem (Latin)
fv,fv_hulquminum_combine,Hul̓q̓umin̓um̓,BC Coast,fv_hulquminum_combine_kmw-9.0.js,1.1,hur-Latn,Halkomelem (Latin)
fv,fv_kwakwala_liqwala,Kʷak̓ʷala,BC Coast,fv_kwakwala_liqwala_kmw-9.0.js,9.2.5,kwk-Latn,Kwakiutl (Latin)
fv,fv_kwakwala,Kwak̕wala,BC Coast,fv_kwakwala_kmw-9.0.js,9.1.2,kwk-Latn,Kwakiutl (Latin)
fv,fv_nexwslayemucen,Nəxʷsƛ̓ay̓əmúcən,BC Coast,fv_nexwslayemucen_kmw-9.0.js,9.2.1,clm-Latn,Clallam (Latin)
@ -36,7 +36,8 @@ fv,fv_ktunaxa,Ktunaxa,BC Interior,fv_ktunaxa_kmw-9.0.js,9.1.3,kut-Latn,Kutenai (
fv,fv_kwadacha_tsekene,Kwadacha Tsekene,BC Interior,fv_kwadacha_tsekene_kmw-9.0.js,1.0,sek-Latn,Sekani
fv,fv_natwits,Neduten-Witsuwit'en,BC Interior,fv_natwits_kmw-9.0.js,9.1.3,caf-Latn,Southern Carrier (Latin)
fv,fv_nlekepmxcin,Nłeʔkepmxcin,BC Interior,fv_nlekepmxcin_kmw-9.0.js,9.2.3,thp-Latn,Thompson (Latin)
fv,fv_nlha7kapmxtsin,Nlha7kapmxtsin,BC Interior,fv_nlha7kapmxtsin_kmw-9.0.js,9.1.1,thp-Latn,Thompson (Latin)
fv,fv_nlha7kapmxtsin,Nlha7kapmxtsin,BC Interior,fv_nlha7kapmxtsin_kmw-9.0.js,10.0,thp-Latn,Thompson (Latin)
fv,fv_nlakapamuxcheen,Nlakapamuxcheen,BC Interior,fv_nlakapamuxcheen_kmw-9.0.js,1.0,thp,Thompson
fv,fv_nsilxcen,Nsilxcən,BC Interior,fv_nsilxcen_kmw-9.0.js,9.3,oka,Okanagan
fv,fv_secwepemctsin,Secwepemctsín,BC Interior,fv_secwepemctsin_kmw-9.0.js,9.2,shs-Latn,Shuswap (Latin)
fv,fv_stlatlimxec,Sƛ̓aƛ̓imxəc,BC Interior,fv_stlatlimxec_kmw-9.0.js,9.2.3,lil-Latn,Lillooet (Latin)
@ -44,7 +45,7 @@ fv,fv_statimcets,St̓át̓imcets,BC Interior,fv_statimcets_kmw-9.0.js,9.1.4,lil
fv,fv_taltan,Tāłtān,BC Interior,fv_taltan_kmw-9.0.js,9.1.5,tht-Latn,Tahltan (Latin)
fv,fv_tsekehne,Tsek'ehne,BC Interior,fv_tsekehne_kmw-9.0.js,9.1.2,sek-Latn,Sekani (Latin)
fv,fv_tsilhqotin,Tŝilhqot'in,BC Interior,fv_tsilhqotin_kmw-9.0.js,9.1.3,clc-Latn,Chilcotin (Latin)
fv,fv_southern_carrier,ᑐᑊᘁᗕᑋᗸ (Southern Carrier),BC Interior,fv_southern_carrier_kmw-9.0.js,10.0,caf-Cans,Southern Carrier (Unified Canadian Aboriginal Syllabics)
fv,fv_southern_carrier,ᑐᑊᘁᗕᑋᗸ (Southern Carrier),BC Interior,fv_southern_carrier_kmw-9.0.js,10.0.1,caf-Cans,Southern Carrier (Unified Canadian Aboriginal Syllabics)
fv,fv_anicinapemi8in,Anicinapemi8in/Anishinàbemiwin,Eastern Subarctic,fv_anicinapemi8in_kmw-9.0.js,9.1.1,alq-Latn,Algonquin (Latin)
fv,fv_atikamekw,Atikamekw,Eastern Subarctic,fv_atikamekw_kmw-9.0.js,9.1.1,atj-Latn,Atikamekw (Latin)
fv,fv_ilnu_innu_aimun,Ilnu-Innu Aimun,Eastern Subarctic,fv_ilnu_innu_aimun_kmw-9.0.js,9.1.1,moe-Latn,Montagnais (Latin)
@ -54,7 +55,7 @@ fv,fv_northern_east_cree,ᐄᔨᔫ-ᐄᓅ ᐊᔨᒨᓐ (Northern East Cree),East
fv,fv_severn_ojibwa,ᐊᓂᔑᓂᓂᒧᐎᐣ (Severn Ojibwa),Eastern Subarctic,fv_severn_ojibwa_kmw-9.0.js,9.3.1,ojs-Cans,Severn Ojibwa (Unified Canadian Aboriginal Syllabics)
fv,fv_ojibwa,ᐊᓂᔑᓇᐯᒧᐎᓐ (Ojibwa),Eastern Subarctic,fv_ojibwa_kmw-9.0.js,9.3.1,ojb-Cans,Northwestern Ojibwa (Unified Canadian Aboriginal Syllabics)
fv,fv_naskapi,ᓇᔅᑲᐱ (Naskapi),Eastern Subarctic,fv_naskapi_kmw-9.0.js,9.3.1,nsk-Cans,Naskapi (Unified Canadian Aboriginal Syllabics)
sil,sil_euro_latin,English,European,european2-1.6.js,3.0.1,en,English
sil,sil_euro_latin,English,European,european2-1.6.js,3.0.2,en,English
basic,basic_kbdcan,Français,European,canadian_french-1.0.js,1.1.1,fr-CA,French (Canada)
fv,fv_anishinaabemowin,Anishinaabemowin,Great Lakes - St. Lawrence,fv_anishinaabemowin_kmw-9.0.js,10.0.1,oj,Ojibwa
fv,fv_bodewadminwen,Bodéwadminwen-Nishnabémwen,Great Lakes - St. Lawrence,fv_bodewadminwen_kmw-9.0.js,9.1.1,pot-Latn,Potawatomi (Latin)

1 Shortname ID Name Region 9.0 Web Keyboard Version Language ID Language Name
13 fv fv_gitsenimx Gitsenimx̱ BC Coast fv_gitsenimx_kmw-9.0.js 10.0.1 git Gitxsan (Latin)
14 fv fv_hailzaqvla Haiɫzaqvla BC Coast fv_hailzaqvla_kmw-9.0.js 9.5.1 hei Heiltsuk (Latin)
15 fv fv_haisla Haisla BC Coast fv_haisla.js 2.0.1 has-Latn Haisla (Latin)
16 fv fv_halqemeylem Halq'eméylem BC Coast fv_halqemeylem_kmw-9.0.js 9.1.3 9.2 hur-Latn Halkomelem (Latin)
17 fv fv_henqeminem Hǝn̓q̓ǝmin̓ǝm BC Coast fv_henqeminem_kmw-9.0.js 10.0.1 hur-Latn Halkomelem (Latin)
18 fv fv_klahoose Homalco-Klahoose-Sliammon BC Coast fv_klahoose_kmw-9.0.js 10.1 coo Comox
19 fv fv_hulquminum Hul’q’umi’num’ BC Coast fv_hulquminum_kmw-9.0.js 9.1 hur-Latn Halkomelem (Latin)
20 fv fv_hulquminum_combine Hul̓q̓umin̓um̓ BC Coast fv_hulquminum_combine_kmw-9.0.js 1.0 1.1 hur-Latn Halkomelem (Latin)
21 fv fv_kwakwala_liqwala Kʷak̓ʷala BC Coast fv_kwakwala_liqwala_kmw-9.0.js 9.2.5 kwk-Latn Kwakiutl (Latin)
22 fv fv_kwakwala Kwak̕wala BC Coast fv_kwakwala_kmw-9.0.js 9.1.2 kwk-Latn Kwakiutl (Latin)
23 fv fv_nexwslayemucen Nəxʷsƛ̓ay̓əmúcən BC Coast fv_nexwslayemucen_kmw-9.0.js 9.2.1 clm-Latn Clallam (Latin)
36 fv fv_kwadacha_tsekene Kwadacha Tsek’ene BC Interior fv_kwadacha_tsekene_kmw-9.0.js 1.0 sek-Latn Sekani
37 fv fv_natwits Nedut’en-Witsuwit'en BC Interior fv_natwits_kmw-9.0.js 9.1.3 caf-Latn Southern Carrier (Latin)
38 fv fv_nlekepmxcin Nłeʔkepmxcin BC Interior fv_nlekepmxcin_kmw-9.0.js 9.2.3 thp-Latn Thompson (Latin)
39 fv fv_nlha7kapmxtsin Nlha7kapmxtsin BC Interior fv_nlha7kapmxtsin_kmw-9.0.js 9.1.1 10.0 thp-Latn Thompson (Latin)
40 fv fv_nlakapamuxcheen Nlakapamuxcheen BC Interior fv_nlakapamuxcheen_kmw-9.0.js 1.0 thp Thompson
41 fv fv_nsilxcen Nsilxcən BC Interior fv_nsilxcen_kmw-9.0.js 9.3 oka Okanagan
42 fv fv_secwepemctsin Secwepemctsín BC Interior fv_secwepemctsin_kmw-9.0.js 9.2 shs-Latn Shuswap (Latin)
43 fv fv_stlatlimxec Sƛ̓aƛ̓imxəc BC Interior fv_stlatlimxec_kmw-9.0.js 9.2.3 lil-Latn Lillooet (Latin)
45 fv fv_taltan Tāłtān BC Interior fv_taltan_kmw-9.0.js 9.1.5 tht-Latn Tahltan (Latin)
46 fv fv_tsekehne Tsek'ehne BC Interior fv_tsekehne_kmw-9.0.js 9.1.2 sek-Latn Sekani (Latin)
47 fv fv_tsilhqotin Tŝilhqot'in BC Interior fv_tsilhqotin_kmw-9.0.js 9.1.3 clc-Latn Chilcotin (Latin)
48 fv fv_southern_carrier ᑐᑊᘁᗕᑋᗸ (Southern Carrier) BC Interior fv_southern_carrier_kmw-9.0.js 10.0 10.0.1 caf-Cans Southern Carrier (Unified Canadian Aboriginal Syllabics)
49 fv fv_anicinapemi8in Anicinapemi8in/Anishinàbemiwin Eastern Subarctic fv_anicinapemi8in_kmw-9.0.js 9.1.1 alq-Latn Algonquin (Latin)
50 fv fv_atikamekw Atikamekw Eastern Subarctic fv_atikamekw_kmw-9.0.js 9.1.1 atj-Latn Atikamekw (Latin)
51 fv fv_ilnu_innu_aimun Ilnu-Innu Aimun Eastern Subarctic fv_ilnu_innu_aimun_kmw-9.0.js 9.1.1 moe-Latn Montagnais (Latin)
55 fv fv_severn_ojibwa ᐊᓂᔑᓂᓂᒧᐎᐣ (Severn Ojibwa) Eastern Subarctic fv_severn_ojibwa_kmw-9.0.js 9.3.1 ojs-Cans Severn Ojibwa (Unified Canadian Aboriginal Syllabics)
56 fv fv_ojibwa ᐊᓂᔑᓇᐯᒧᐎᓐ (Ojibwa) Eastern Subarctic fv_ojibwa_kmw-9.0.js 9.3.1 ojb-Cans Northwestern Ojibwa (Unified Canadian Aboriginal Syllabics)
57 fv fv_naskapi ᓇᔅᑲᐱ (Naskapi) Eastern Subarctic fv_naskapi_kmw-9.0.js 9.3.1 nsk-Cans Naskapi (Unified Canadian Aboriginal Syllabics)
58 sil sil_euro_latin English European european2-1.6.js 3.0.1 3.0.2 en English
59 basic basic_kbdcan Français European canadian_french-1.0.js 1.1.1 fr-CA French (Canada)
60 fv fv_anishinaabemowin Anishinaabemowin Great Lakes - St. Lawrence fv_anishinaabemowin_kmw-9.0.js 10.0.1 oj Ojibwa
61 fv fv_bodewadminwen Bodéwadminwen-Nishnabémwen Great Lakes - St. Lawrence fv_bodewadminwen_kmw-9.0.js 9.1.1 pot-Latn Potawatomi (Latin)

View file

@ -138,7 +138,8 @@ but makes the script easy to scan!
# Defining build script parameters
The build script should use the `builder` functions and variables to process its
command line and control its run.
command line and control its run. See [`builder_describe`] for full details on
how these parameters are defined.
Build scripts can define **targets**, **actions**, **options**, and
**dependencies**, which are parameters passed in to the script when it is run by
@ -179,6 +180,9 @@ a user or called by another script:
Options can be used to provide additional data, by including `=<varname>` in
their definition. Otherwise, they are treated as a boolean.
An option will be inherited by child scripts if you append a `+` to the option
name.
* **dependencies**: these are other builder scripts which must be configured and
built before the actions in this script can continue. Only `configure` and
`build` actions are ever passed to dependency scripts; these actions will
@ -424,6 +428,10 @@ a definition:
builder_describe "Testing script" clean test+
```
If an action is passed to a child script, but the child script does not support
it, it will be ignored, although a builder debug message will be issued for
safety.
**Options** are defined by including a `--` prefix.
Specification of options: `"--option[,-o][+][=var] [One line description]"`
@ -440,10 +448,11 @@ may not be combined when invoking the script -- each must be passed separately.
Ensure that you do not include a space after the comma.
If a `+` is appended (after the optional shorthand form, but before the
default), then the option will be passed to child scripts. All child scripts
_must_ accept this option, or they will fail. It is acceptable for the child
script to declare the option but ignore it. However, the option will _not_ be
passed to dependencies.
variable), then the option will be passed to child scripts. Child scripts do not
need to declare the option if they do not use it, but this will be noted as a
builder debug message for safety; it is also acceptable for the child script to
declare the option but ignore it. However, the option will _not_ be passed to
dependencies.
By default, an option will be treated as a boolean. It can be tested with
[`builder_has_option`]. If you need to pass additional data, then the

View file

@ -0,0 +1,29 @@
# Required minimum versions (also used as default version)
# Minimum versions as of Keyman 18
# (https://docs.google.com/document/d/1Uy3U2YXeA4rCEbUbT7O6QzUGJDZBeViFecL8fjUOLkE/edit?usp=sharing)
# shellcheck shell=bash disable=SC2034 # SC2034: X appears unused.
# Target operating system and platform versions
KEYMAN_MIN_TARGET_VERSION_ANDROID=5 # Lollipop
KEYMAN_MIN_TARGET_VERSION_IOS=12.2 # iOS 12.2
KEYMAN_MIN_TARGET_VERSION_WINDOWS=10 # Windows 10
KEYMAN_MIN_TARGET_VERSION_MAC=10.13 # MacOS 10.13 (High Sierra)
KEYMAN_MIN_TARGET_VERSION_UBUNTU=20.04 # Ubuntu 20.04 Focal
KEYMAN_MIN_TARGET_VERSION_CHROME=95.0 # Final version that runs on Android 5.0
# Dependency versions
KEYMAN_MIN_VERSION_NODE_MAJOR=18
KEYMAN_MIN_VERSION_NPM=10.5.1 # 10.5.0 has bug, discussed in #10350
KEYMAN_MIN_VERSION_EMSCRIPTEN=3.1.44 # Warning: 3.1.45 is bad (#9529); newer versions work
KEYMAN_MAX_VERSION_EMSCRIPTEN=3.1.58 # See #9529
KEYMAN_MIN_VERSION_VISUAL_STUDIO=2019
KEYMAN_MIN_VERSION_MESON=1.0.0
# Language and runtime versions
KEYMAN_VERSION_JAVA=11 # We're using Java/OpenJDK 11
KEYMAN_MIN_VERSION_CPP=17 # C++17
KEYMAN_MIN_VERSION_ANDROID_SDK=21
# Default version used in Docker containers
KEYMAN_DEFAULT_VERSION_UBUNTU_CONTAINER=noble # Ubuntu 24.04 Noble

View file

@ -7,6 +7,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
builder_describe \
"Tests dependency builds debug flag" \
:child \
configure build
function do_build() {
@ -25,3 +26,5 @@ builder_is_dep_build || builder_die "FAIL: dep: builder_is_dep_build should be t
! builder_is_child_build || builder_die "FAIL: dep: builder_is_child_build should be false"
builder_run_action build do_build
builder_run_child_actions configure build

View file

@ -0,0 +1,27 @@
#!/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
builder_describe \
"Tests dependency/child builds debug flag" \
configure build
function do_build() {
# Test the debug flag
builder_is_debug_build || builder_die "FAIL: child/dep: expecting builder_is_debug_build to be true"
echo "PASS: child/dep: builder_is_debug_build is true"
builder_has_option --debug || builder_die "FAIL: child/dep: expecting builder_has_option --debug to be true"
echo "PASS: child/dep: builder_has_option --debug is true"
}
builder_parse "$@"
# Sanity Check: verify that we are running as a dep AND as a child build
builder_is_dep_build || builder_die "FAIL: dep/child: builder_is_dep_build should be true"
builder_is_child_build || builder_die "FAIL: dep/child: builder_is_child_build should be false"
builder_run_action build do_build

View file

@ -0,0 +1,21 @@
#!/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
# Test builder_describe_outputs and dependencies
builder_describe "parent test module" \
:child \
test1 test2 \
"--option1+ inheritable option" \
"--option2+ second inheritable option"
builder_parse "$@"
builder_run_child_actions test1 test2
echo Done

View file

@ -0,0 +1,19 @@
#!/usr/bin/env bash
echo "Params: $@"
## 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
# Test missing actions and options
project=child1
builder_describe "$project test module" test1 --option1
builder_parse "$@"
builder_run_action test1 echo "test1 action ran"

View file

@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -eu
## START STANDARD BUILD SCRIPT INCLUDE
# adjust relative paths as necessary
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
. "${THIS_SCRIPT%/*}/../../../../resources/build/build-utils.sh"
# END STANDARD BUILD SCRIPT INCLUDE
cd "$THIS_SCRIPT_PATH"
echo "--- Build a child script which has ignored options and flags ---"
./build.sh test1 test2 --option1 --option2

View file

@ -175,6 +175,7 @@ echo -e "${COLOR_BLUE}## Running dependency tests${COLOR_RESET}"
"$THIS_SCRIPT_PATH/dependencies/test.sh"
"$THIS_SCRIPT_PATH/trees/test.sh"
"$THIS_SCRIPT_PATH/debug-deps/test.sh"
"$THIS_SCRIPT_PATH/ignored-flags/test.sh"
echo -e "${COLOR_BLUE}## Test builder.inc.sh 'builder-style' script${COLOR_RESET}"
./builder-invalid-script.test.sh || builder_die "FAIL: builder-invalid-script.test.sh returned failure code $?"
@ -187,7 +188,7 @@ echo
# builder_parse calls `exit 0` on a --help run, so running in a subshell
echo -e "${COLOR_BLUE}## Testing --help${COLOR_RESET}"
builder_parse --no-color --help
) || builder_die "FAIL: builder-parse returned failure code $? unexpectedly"
) || builder_die "FAIL: builder-parse unexpectedly returned failure code $?"
echo -e "${COLOR_GREEN}======================================================${COLOR_RESET}"
echo -e "${COLOR_GREEN}All tests passed successfully${COLOR_RESET}"

View file

@ -400,9 +400,19 @@ _builder_execute_child() {
fi
done
"$script" $action \
# If the current build is a dependency build, pass the dependency state on to
# the child build, so that we don't unnecessarily rebuild children (#11394)
local dep_flag= dep_module=
if builder_is_dep_build; then
dep_flag=--builder-dep-parent
dep_module="$builder_dep_parent"
fi
"$script" \
--builder-child \
$_builder_build_deps \
$dep_flag "$dep_module" \
$action \
${child_options[@]} \
$builder_verbose \
$builder_debug \
@ -1205,7 +1215,6 @@ builder_parse() {
if [[ $# -eq 0 ]]; then
_builder_parameter_error "$0" parameter "$key"
fi
exp+=("$1")
fi
else
@ -1369,9 +1378,12 @@ _builder_parse_expanded_parameters() {
# internal use parameter for dependency builds - identifier of parent script
shift
builder_dep_parent="$1"
builder_echo setmark "dependency build, started by $builder_dep_parent"
builder_echo grey "build.sh parameters: <${_params[@]}>"
;;
--builder-child)
_builder_is_child=0
builder_echo setmark "child build, parameters: <${_params[@]}>"
;;
--builder-report-dependencies)
# internal reporting function, ignores all other parameters
@ -1379,7 +1391,13 @@ _builder_parse_expanded_parameters() {
;;
*)
# script does not recognize anything of action or target form at this point.
_builder_parameter_error "$0" parameter "$key"
if builder_is_child_build; then
# For child builds, don't fail the build when pass inheritable
# parameters (#11408)
builder_echo_debug "Parameter '$key' is not supported, ignoring"
else
_builder_parameter_error "$0" parameter "$key"
fi
esac
fi
shift # past the processed argument
@ -1409,13 +1427,10 @@ _builder_parse_expanded_parameters() {
fi
if builder_is_dep_build; then
builder_echo setmark "dependency build, started by $builder_dep_parent"
builder_echo grey "build.sh parameters: <${_params[@]}>"
if [[ -z ${_builder_deps_built+x} ]]; then
builder_die "FATAL ERROR: Expected '_builder_deps_built' variable to be set"
fi
elif builder_is_child_build; then
builder_echo setmark "child build, parameters: <${_params[@]}>"
if [[ -z ${_builder_deps_built+x} ]]; then
builder_die "FATAL ERROR: Expected '_builder_deps_built' variable to be set"
fi

View file

@ -35,6 +35,7 @@
"@keymanapp/web-utils": ["./common/web/utils"],
"@keymanapp/lm-message-types": ["./common/web/lm-message-types"],
"@keymanapp/keyman-version": ["./common/web/keyman-version"],
"@keymanapp/ldml-keyboard-constants": [ "./core/include/ldml" ],
}
}
}
}

View file

@ -122,10 +122,10 @@ export class PageIntegrationHandlers {
// The following tests are needed to prevent the OSK from being hidden during normal input!
let p=(e.target as HTMLElement).parentElement;
if(typeof(p) != 'undefined' && p != null) {
if(p.className.indexOf('kmw-key-') >= 0) return false;
if(p.getAttribute('class')?.indexOf('kmw-key-') >= 0) return false;
if(typeof(p.parentElement) != 'undefined' && p.parentElement != null) {
p=p.parentElement;
if(p.className.indexOf('kmw-key-') >= 0) return false;
if(p.getAttribute('class')?.indexOf('kmw-key-') >= 0) return false;
}
}

View file

@ -287,24 +287,43 @@ export default class ContextManager extends ContextManagerBase<BrowserConfigurat
};
// Set element directionality (but only if element is empty)
let Ltarg = target?.getElement();
let focusedElement = target?.getElement();
if(target instanceof DesignIFrame) {
Ltarg = target.docRoot;
focusedElement = target.docRoot;
}
if(Ltarg && Ltarg.ownerDocument && Ltarg instanceof Ltarg.ownerDocument.defaultView.HTMLElement) {
_SetTargDir(Ltarg, this.activeKeyboard?.keyboard);
if(focusedElement && focusedElement.ownerDocument && focusedElement instanceof focusedElement.ownerDocument.defaultView.HTMLElement) {
_SetTargDir(focusedElement, this.activeKeyboard?.keyboard);
}
if(target != originalTarget) {
this.emit('targetchange', target);
}
//Execute external (UI) code needed on focus if required
if(sendEvents) {
// //Execute external (UI) code needed on focus if required
this.apiEvents.callEvent('controlfocused', {
target: target?.getElement() || null,
activeControl: previousTarget?.getElement()
});
let blurredElement = previousTarget?.getElement();
if(previousTarget instanceof DesignIFrame) {
blurredElement = previousTarget.docRoot;
}
if(!focusedElement) {
if(blurredElement) {
this.apiEvents.callEvent('controlblurred', {
target: blurredElement,
event: null,
isActivating: this.focusAssistant.maintainingFocus
});
}
} else {
// Note: indicates the previous control being blurred (as
// `activeControl`). 'controlfocused' and 'controlblurred' are
// treated as mutually exclusive, with the latter only happening
// when nothing KMW-related is focused.
this.apiEvents.callEvent('controlfocused', {
target: focusedElement,
activeControl: blurredElement
});
}
}
}

View file

@ -275,7 +275,7 @@ export default class HardwareEventKeyboard extends HardKeyboard {
// Prevent mapping element is readonly or tagged as kmw-disabled
const el = target.getElement();
if(el?.className?.indexOf('kmw-disabled') >= 0) {
if(el?.getAttribute('class')?.indexOf('kmw-disabled') >= 0) {
return true;
}

View file

@ -67,7 +67,6 @@
<Component>
<File Name="kmshell.exe" KeyPath="yes">
<Shortcut Id="desktopKeyman" Advertise="yes" Directory="DesktopFolder" Name="Keyman" WorkingDirectory='INSTALLDIR' Icon="appicon.ico" IconIndex="0" />
<Shortcut Id="startmenuKeyman" Advertise="yes" Directory="ProgramMenuDir" Name="Keyman" WorkingDirectory='INSTALLDIR' Icon="appicon.ico" IconIndex="0" />
<Shortcut Id="startmenuKeymanConfiguration" Advertise="yes" Directory="ProgramMenuDir" Arguments="-c" Name="Keyman Configuration" WorkingDirectory='INSTALLDIR' Icon="KMSHELL.ico" IconIndex="0" />
</File>

View file

@ -904,6 +904,10 @@
<!-- String Type: FormatString -->
<!-- Introduced: 8.0.294.0 -->
<string name="S_OSK_FontHelper_ChooseKeyboard" comment="OSK Font helper choose keyboard">សូម​ជ្រើសរើស​ក្ដារចុច Keyman មួយ​ដើម្បី​រក​ពុម្ព​អក្សរ​ដែល​ពាក់ព័ន្ធ</string>
<!-- Context: OSK Font Helper -->
<!-- String Type: FormatString -->
<!-- Introduced: 17.0.312.0 -->
<string name="S_OSK_FontHelper_NoFonts" comment="OSK Font helper no fonts found for keyboard">មិនឃើញមានពុម្ពអក្សរណាជាសំណូមពរសម្រាប់ក្តារចុច %1$s.</string>
<!-- Context: Text Editor -->
<!-- String Type: FormatString -->
<!-- Introduced: 10.0.836.0 -->

View file

@ -1189,7 +1189,7 @@ keyboard that you use in Windows. Keyman keyboards will adapt automatically to
<!-- Context: OSK Font Helper -->
<!-- String Type: FormatString -->
<!-- Introduced: 17.0.312.0 -->
<string name="S_OSK_FontHelper_NoFonts" comment="OSK Font helper no fonts found for keyboard">No fonts have been found as suggestions for Keyboard %1$s.</string>
<string name="S_OSK_FontHelper_NoFonts" comment="OSK Font helper no fonts found for keyboard">No fonts have been found as suggestions for keyboard %1$s.</string>
<!-- Context: Text Editor -->
<!-- String Type: FormatString -->

View file

@ -7,11 +7,11 @@ BOOL SetupCoreEnvironment(km_core_option_item **core_environment) {
items[0].scope = KM_CORE_OPT_ENVIRONMENT;
items[0].key = KM_CORE_KMX_ENV_BASELAYOUT;
items[0].value = reinterpret_cast<km_core_cp*>(Globals::get_BaseKeyboardName());
items[0].value = reinterpret_cast<km_core_cu*>(Globals::get_BaseKeyboardName());
items[1].scope = KM_CORE_OPT_ENVIRONMENT;
items[1].key = KM_CORE_KMX_ENV_BASELAYOUTALT;
items[1].value = reinterpret_cast<km_core_cp*>(Globals::get_BaseKeyboardNameAlt());
items[1].value = reinterpret_cast<km_core_cu*>(Globals::get_BaseKeyboardNameAlt());
items[2].scope = KM_CORE_OPT_ENVIRONMENT;
items[2].key = KM_CORE_KMX_ENV_SIMULATEALTGR;

View file

@ -136,7 +136,7 @@ ContextItemToAppContext(km_core_context_item *contextItems, PWSTR outBuf, DWORD
buf[idx++] = static_cast<WCHAR> Uni_UTF32ToSurrogate1(km_core_context_it->character);
buf[idx++] = static_cast<WCHAR> Uni_UTF32ToSurrogate2(km_core_context_it->character);
} else {
buf[idx++] = (km_core_cp)km_core_context_it->character;
buf[idx++] = (km_core_cu)km_core_context_it->character;
}
break;
case KM_CORE_CT_MARKER:

View file

@ -155,7 +155,7 @@ LogContext(km_core_state *lpCoreKeyboardState, uint8_t context_type) {
return FALSE;
}
km_core_cp* buffer = km_core_state_context_debug(
km_core_cu* buffer = km_core_state_context_debug(
lpCoreKeyboardState,
context_type == CONTEXT_CORE ? KM_CORE_DEBUG_CONTEXT_CACHED : KM_CORE_DEBUG_CONTEXT_INTERMEDIATE
);
@ -163,7 +163,7 @@ LogContext(km_core_state *lpCoreKeyboardState, uint8_t context_type) {
SendDebugMessageFormat(0, sdmKeyboard, 0, "%s: %ls", log_str_title, buffer);
km_core_cp_dispose(buffer);
km_core_cu_dispose(buffer);
return TRUE;
}

View file

@ -22,15 +22,15 @@
BOOL IntLoadKeyboardOptionsRegistrytoCore(LPCSTR key, LPINTKEYBOARDINFO kp, km_core_state* const state);
void IntSaveKeyboardOptionCoretoRegistry(LPCSTR REGKey, LPINTKEYBOARDINFO kp, LPCWSTR key, LPCWSTR value);
static km_core_cp* CloneKeymanCoreCP(const km_core_cp* cp) {
static km_core_cu* CloneKeymanCoreCP(const km_core_cu* cp) {
LPCWSTR buf = reinterpret_cast<LPCWSTR>(cp);
km_core_cp* clone = new km_core_cp[wcslen(buf) + 1];
km_core_cu* clone = new km_core_cu[wcslen(buf) + 1];
wcscpy_s(reinterpret_cast<LPWSTR>(clone), wcslen(buf) + 1, buf);
return clone;
}
static km_core_cp* CloneKeymanCoreCPFromWSTR(LPWSTR buf) {
km_core_cp* clone = new km_core_cp[wcslen(buf) + 1];
static km_core_cu* CloneKeymanCoreCPFromWSTR(LPWSTR buf) {
km_core_cu* clone = new km_core_cu[wcslen(buf) + 1];
wcscpy_s(reinterpret_cast<LPWSTR>(clone), wcslen(buf) + 1, buf);
return clone;
}

View file

@ -82,7 +82,7 @@ Process_Event_Core(PKEYMAN64THREADDATA _td) {
WCHAR application_context[MAXCONTEXT];
if (_td->app->ReadContext(application_context)) {
km_core_context_status result;
result = km_core_state_context_set_if_needed(_td->lpActiveKeyboard->lpCoreKeyboardState, reinterpret_cast<const km_core_cp *>(application_context));
result = km_core_state_context_set_if_needed(_td->lpActiveKeyboard->lpCoreKeyboardState, reinterpret_cast<const km_core_cu *>(application_context));
if (result == KM_CORE_CONTEXT_STATUS_ERROR || result == KM_CORE_CONTEXT_STATUS_INVALID_ARGUMENT) {
SendDebugMessageFormat(0, sdmGlobal, 0, "Process_Event_Core: km_core_state_context_set_if_needed returned [%d]", result);
}
@ -127,13 +127,13 @@ BOOL ProcessHook()
SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "Key pressed: %s Context <unavailable>",
Debug_VirtualKey(_td->state.vkey));
} else {
km_core_cp* debug_context = km_core_state_context_debug(
km_core_cu* debug_context = km_core_state_context_debug(
_td->lpActiveKeyboard->lpCoreKeyboardState,
KM_CORE_DEBUG_CONTEXT_CACHED
);
SendDebugMessageFormat(_td->state.msg.hwnd, sdmKeyboard, 0, "Key pressed: %s Context '%ls'",
Debug_VirtualKey(_td->state.vkey), debug_context);
km_core_cp_dispose(debug_context);
km_core_cu_dispose(debug_context);
}
}

View file

@ -23,11 +23,11 @@ TEST(KEYBOARDOPTIONS, SetupCoreEnvironment) {
// These are taken from SetupCoreEnvironment in CoreEnvironment.cpp
expected_items[0].scope = KM_CORE_OPT_ENVIRONMENT;
expected_items[0].key = KM_CORE_KMX_ENV_BASELAYOUT;
expected_items[0].value = reinterpret_cast<km_core_cp *>(Globals::get_BaseKeyboardName());
expected_items[0].value = reinterpret_cast<km_core_cu *>(Globals::get_BaseKeyboardName());
expected_items[1].scope = KM_CORE_OPT_ENVIRONMENT;
expected_items[1].key = KM_CORE_KMX_ENV_BASELAYOUTALT;
expected_items[1].value = reinterpret_cast<km_core_cp *>(Globals::get_BaseKeyboardNameAlt());
expected_items[1].value = reinterpret_cast<km_core_cu *>(Globals::get_BaseKeyboardNameAlt());
expected_items[2].scope = KM_CORE_OPT_ENVIRONMENT;
expected_items[2].key = KM_CORE_KMX_ENV_SIMULATEALTGR;
@ -38,7 +38,7 @@ TEST(KEYBOARDOPTIONS, SetupCoreEnvironment) {
expected_items[3].value = KeyboardGivesCtrlRAltForRAlt() ? u"1" : u"0";
expected_items[4] = KM_CORE_OPTIONS_END;
km_core_cp const* retValue = nullptr;
km_core_cu const* retValue = nullptr;
std::u16string value = u"";
std::u16string expectedValue = u"";