mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-05 00:15:32 +00:00
Merge branch 'beta' into web-64-touch-alias-api
This commit is contained in:
commit
06713c2b0b
37 changed files with 540 additions and 468 deletions
|
|
@ -1,20 +1,28 @@
|
|||
# Keyman for Android
|
||||
|
||||
## 2019-01-02 11.0.2050 beta
|
||||
* Initial beta release of Keyman for Android 11
|
||||
* [Pull Requests](https://github.com/keymanapp/keyman/pulls?utf8=%E2%9C%93&q=is%3Apr+merged%3A2018-07-01..2019-01-01+label%3Aandroid+-label%3Acherry-pick+-label%3Astable)
|
||||
|
||||
## 11.0 alpha
|
||||
* Move to 11.0
|
||||
* Add round launcher icons (#1077)
|
||||
* Change default keyboard from `european` to `sil_euro_latin` (#1112)
|
||||
* Remove deprecated ad-hoc distribution of keyboards via `keyman://` protocol (#1109)
|
||||
* Add splash screen (#1151)
|
||||
* Update app to use Material Design theme (#681)
|
||||
* Fix globe button when pausing WebBrowser (#1213)
|
||||
* Change system keyboard to "numeric" layer for digit/phone number text fields (#1218)
|
||||
* Add feature to vibrate device when Keyman Web calls `beep` (#1227)
|
||||
* Add support for extra key found on European hardware keyboards (#1291)
|
||||
* Add feature for keyboard picker to switch to next keyboard (#1283)
|
||||
* Update to Cloud API 4.0 for downloading keyboards (#1320)
|
||||
* Fixes issue where file extensions are upper-case, e.g. ".TTF" (#1333)
|
||||
* New Features:
|
||||
* System keyboard changes to "numeric" layer for digit/phone number text fields (#1218)
|
||||
* Device vibrates when Keyman Web calls `beep` -- when invalid combinations are pressed (#1227)
|
||||
* Added support for 102nd key found on European hardware keyboards (#1291)
|
||||
* Keyboard picker can now switch to next system keyboard (#1283)
|
||||
|
||||
* Changes:
|
||||
* Added round launcher icons (#1077)
|
||||
* Added splash screen (#1151)
|
||||
* Updated app to use Material Design theme (#681, #1378, #1303)
|
||||
* Updated to Cloud API 4.0 for downloading keyboards (#1320)
|
||||
* Removed deprecated ad-hoc distribution of keyboards via `keyman://` protocol (#1109)
|
||||
* Changed default keyboard from `european` to `sil_euro_latin` (#1112, #1400)
|
||||
|
||||
* Bug fixes:
|
||||
* Diacritics now display more consistently on key caps (#1407)
|
||||
* Fixed globe button when pausing WebBrowser (#1213)
|
||||
* Fixed issue where file extensions are upper-case, e.g. ".TTF" (#1333)
|
||||
* Fixed various crashes (#1108, #1057)
|
||||
|
||||
## 2018-11-14 10.0.508 stable
|
||||
* Fix crash that can occur when text selection ends before the starting position (#1313)
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ km_kbp_state_option_lookup(km_kbp_state const *state,
|
|||
if (scope == KM_KBP_OPT_UNKNOWN || scope > KM_KBP_OPT_MAX_SCOPES)
|
||||
return KM_KBP_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
auto & opts = state->options();
|
||||
auto & processor = state->processor();
|
||||
|
||||
*value_out = opts.lookup(km_kbp_option_scope(scope), key);
|
||||
*value_out = processor.lookup_option(km_kbp_option_scope(scope), key);
|
||||
if (!*value_out) return KM_KBP_STATUS_KEY_ERROR;
|
||||
|
||||
return KM_KBP_STATUS_OK;
|
||||
|
|
@ -57,7 +57,7 @@ km_kbp_state_options_update(km_kbp_state *state, km_kbp_option_item const *opt)
|
|||
assert(state); assert(opt);
|
||||
if (!state|| !opt) return KM_KBP_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
auto & opts = state->options();
|
||||
auto & processor = state->processor();
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -66,7 +66,10 @@ km_kbp_state_options_update(km_kbp_state *state, km_kbp_option_item const *opt)
|
|||
if (opt->scope == KM_KBP_OPT_UNKNOWN || opt->scope > KM_KBP_OPT_MAX_SCOPES)
|
||||
return KM_KBP_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
if (!opts.assign(state, km_kbp_option_scope(opt->scope), opt->key, opt->value))
|
||||
if (processor.update_option(
|
||||
km_kbp_option_scope(opt->scope),
|
||||
opt->key,
|
||||
opt->value).empty())
|
||||
return KM_KBP_STATUS_KEY_ERROR;
|
||||
}
|
||||
}
|
||||
|
|
@ -92,7 +95,8 @@ km_kbp_state_options_to_json(km_kbp_state const *state, char *buf, size_t *space
|
|||
|
||||
try
|
||||
{
|
||||
jo << state->options();
|
||||
// TODO: Fix
|
||||
// jo << state->options();
|
||||
}
|
||||
catch (std::bad_alloc)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ km_kbp_status km_kbp_state_to_json(km_kbp_state const *state,
|
|||
jo << json::object
|
||||
<< "$schema" << "keyman/keyboardprocessor/doc/introspection.schema"
|
||||
<< "keyboard" << state->processor().keyboard()
|
||||
<< "options" << state->options()
|
||||
// << "options" << state->options() TODO: Fix
|
||||
<< "context" << state->context()
|
||||
<< "actions" << state->actions()
|
||||
<< json::close;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
*/
|
||||
#include <kmx/kmx_processor.h>
|
||||
|
||||
using namespace km::kbp::kmx;
|
||||
using namespace km::kbp;
|
||||
using namespace kmx;
|
||||
|
||||
void KMX_Actions::ResetQueue()
|
||||
{
|
||||
|
|
@ -31,7 +32,7 @@ KMX_BOOL KMX_Actions::QueueAction(int ItemType, KMX_DWORD dwData)
|
|||
QueueSize++;
|
||||
|
||||
int result = TRUE;
|
||||
|
||||
|
||||
switch(ItemType)
|
||||
{
|
||||
case QIT_VKEYDOWN:
|
||||
|
|
|
|||
|
|
@ -21,23 +21,41 @@ namespace {
|
|||
}
|
||||
|
||||
KMX_Environment::KMX_Environment() {
|
||||
Load(KM_KBP_KMX_ENV_PLATFORM, DEFAULT_PLATFORM);
|
||||
Load(KM_KBP_KMX_ENV_BASELAYOUT, DEFAULT_BASELAYOUT);
|
||||
Load(KM_KBP_KMX_ENV_BASELAYOUTALT, DEFAULT_BASELAYOUTALT);
|
||||
Load(KM_KBP_KMX_ENV_SIMULATEALTGR, DEFAULT_SIMULATEALTGR);
|
||||
Load(KM_KBP_KMX_ENV_CAPSLOCK, DEFAULT_CAPSLOCK);
|
||||
Load(KM_KBP_KMX_ENV_BASELAYOUTGIVESCTRLRALTFORRALT, DEFAULT_BASELAYOUTGIVESCTRLRALTFORRALT);
|
||||
}
|
||||
|
||||
void KMX_Environment::InitOption(std::vector<option> &default_env, km_kbp_cp const *key, km_kbp_cp const *default_value) {
|
||||
default_env.emplace_back(KM_KBP_OPT_ENVIRONMENT, key, default_value);
|
||||
Load(key, default_value);
|
||||
}
|
||||
|
||||
void KMX_Environment::Init(std::vector<option> &default_env) {
|
||||
InitOption(default_env, KM_KBP_KMX_ENV_PLATFORM, DEFAULT_PLATFORM);
|
||||
InitOption(default_env, KM_KBP_KMX_ENV_BASELAYOUT, DEFAULT_BASELAYOUT);
|
||||
InitOption(default_env, KM_KBP_KMX_ENV_BASELAYOUTALT, DEFAULT_BASELAYOUTALT);
|
||||
InitOption(default_env, KM_KBP_KMX_ENV_SIMULATEALTGR, DEFAULT_SIMULATEALTGR);
|
||||
InitOption(default_env, KM_KBP_KMX_ENV_CAPSLOCK, DEFAULT_CAPSLOCK);
|
||||
InitOption(default_env, KM_KBP_KMX_ENV_BASELAYOUTGIVESCTRLRALTFORRALT, DEFAULT_BASELAYOUTGIVESCTRLRALTFORRALT);
|
||||
char16_t const * KMX_Environment::LookUp(std::u16string const & key) const {
|
||||
assert(!key.empty());
|
||||
if (!key.empty()) return nullptr;
|
||||
|
||||
// TODO refactor this and the keyboard option terminator into state.cpp and keyboard.cpp respectively
|
||||
default_env.emplace_back();
|
||||
if (!u16icmp(key.c_str(), KM_KBP_KMX_ENV_PLATFORM)) {
|
||||
return _platform.c_str();
|
||||
}
|
||||
else if (!u16icmp(key.c_str(), KM_KBP_KMX_ENV_BASELAYOUT)) {
|
||||
return _baseLayout.c_str();
|
||||
}
|
||||
else if (!u16icmp(key.c_str(), KM_KBP_KMX_ENV_BASELAYOUTALT)) {
|
||||
return _baseLayoutAlt.c_str();
|
||||
}
|
||||
else if (!u16icmp(key.c_str(), KM_KBP_KMX_ENV_SIMULATEALTGR)) {
|
||||
return _simulateAltGr ? u"1" : u"0";
|
||||
}
|
||||
else if (!u16icmp(key.c_str(), KM_KBP_KMX_ENV_CAPSLOCK)) {
|
||||
return _capsLock ? u"1" : u"0";
|
||||
}
|
||||
else if (!u16icmp(key.c_str(), KM_KBP_KMX_ENV_BASELAYOUTGIVESCTRLRALTFORRALT)) {
|
||||
return _baseLayoutGivesCtrlRAltForRAlt ? u"1" : u"0";
|
||||
}
|
||||
else {
|
||||
// Unsupported key
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ private:
|
|||
public:
|
||||
KMX_Environment();
|
||||
void Load(std::u16string const & key, std::u16string const & value);
|
||||
void Init(std::vector<option> &default_env);
|
||||
char16_t const * LookUp(std::u16string const & key) const;
|
||||
|
||||
KMX_BOOL capsLock() const noexcept { return _capsLock; }
|
||||
KMX_BOOL simulateAltGr() const noexcept { return _simulateAltGr; }
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
Copyright: Copyright (C) 2003-2018 SIL International.
|
||||
Authors: mcdurdin
|
||||
*/
|
||||
#include "processor.hpp"
|
||||
#include "kmx_processor.h"
|
||||
#include <option.hpp>
|
||||
#include <state.hpp>
|
||||
|
|
@ -15,7 +16,7 @@ int KMX_Options::_GetIndex(std::u16string const &key) const {
|
|||
for (auto sp = _kp->Keyboard->dpStoreArray;
|
||||
i != _kp->Keyboard->cxStoreArray; ++i, ++sp)
|
||||
{
|
||||
if (sp->dpName && sp->dpName == key) break;
|
||||
if (sp->dpName && sp->dpName == key) return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
|
@ -41,20 +42,19 @@ void KMX_Options::AddOptionsStoresFromXString(PKMX_WCHAR s) {
|
|||
}
|
||||
}
|
||||
|
||||
void KMX_Options::Load(options *options, std::u16string const &key) {
|
||||
void KMX_Options::Load(abstract_processor & ap, std::u16string const &key) {
|
||||
LPSTORE sp;
|
||||
auto i = 0U;
|
||||
|
||||
assert(options != nullptr);
|
||||
assert(!key.empty());
|
||||
|
||||
if (options == nullptr || key.empty()) return;
|
||||
if (key.empty()) return;
|
||||
|
||||
for (i = 0, sp = _kp->Keyboard->dpStoreArray; i < _kp->Keyboard->cxStoreArray; i++, sp++) {
|
||||
if (_kp->KeyboardOptions[i].OriginalStore != NULL
|
||||
&& sp->dpName != NULL
|
||||
&& u16icmp(sp->dpName, key.c_str()) == 0) {
|
||||
Reset(options, i);
|
||||
Reset(ap, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -124,6 +124,16 @@ KMX_Options::~KMX_Options()
|
|||
_kp->KeyboardOptions = NULL;
|
||||
}
|
||||
|
||||
|
||||
char16_t const * KMX_Options::LookUp(std::u16string const &key) const
|
||||
{
|
||||
auto idx = _GetIndex(key);
|
||||
if (idx < 0) return nullptr;
|
||||
|
||||
return _kp->Keyboard->dpStoreArray[idx].dpString;
|
||||
}
|
||||
|
||||
|
||||
void KMX_Options::Set(int nStoreToSet, std::u16string const & rValueToSet)
|
||||
{
|
||||
assert(_kp != NULL);
|
||||
|
|
@ -158,8 +168,7 @@ void KMX_Options::Set(int nStoreToSet, int nStoreToRead)
|
|||
Set(nStoreToSet, rStoreToReadValue);
|
||||
}
|
||||
|
||||
|
||||
void KMX_Options::Reset(options *options, int nStoreToReset)
|
||||
void KMX_Options::Reset(abstract_processor & ap, int nStoreToReset)
|
||||
{
|
||||
assert(_kp != NULL);
|
||||
assert(_kp->Keyboard != NULL);
|
||||
|
|
@ -179,17 +188,17 @@ void KMX_Options::Reset(options *options, int nStoreToReset)
|
|||
if(rStoreToReset.dpName == nullptr) return;
|
||||
|
||||
// Now we need to go back and get any saved value from KPAPI. internal_value is owned by options api
|
||||
km_kbp_cp const *internal_value = options->lookup(km_kbp_option_scope(KM_KBP_OPT_KEYBOARD), _kp->Keyboard->dpStoreArray[nStoreToReset].dpName);
|
||||
if(internal_value) {
|
||||
auto i = ap.persisted_store().find(rStoreToReset.dpName);
|
||||
if(i != ap.persisted_store().end()) {
|
||||
// Copy the value from KPAPI
|
||||
_kp->KeyboardOptions[nStoreToReset].Value = new KMX_WCHAR[u16len(internal_value) + 1];
|
||||
u16cpy(_kp->KeyboardOptions[nStoreToReset].Value, /*u16len(val) + 1,*/ internal_value);
|
||||
_kp->Keyboard->dpStoreArray[nStoreToReset].dpString = _kp->KeyboardOptions[nStoreToReset].Value;
|
||||
rOptionToReset.Value = new KMX_WCHAR[i->second.size() + 1];
|
||||
u16cpy(rOptionToReset.Value, /*u16len(val) + 1,*/ i->second.c_str());
|
||||
rStoreToReset.dpString = rOptionToReset.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void KMX_Options::Save(km_kbp_state *state, int nStoreToSave)
|
||||
void KMX_Options::Save(state & state, int nStoreToSave)
|
||||
{
|
||||
assert(_kp != NULL);
|
||||
assert(_kp->Keyboard != NULL);
|
||||
|
|
@ -200,6 +209,7 @@ void KMX_Options::Save(km_kbp_state *state, int nStoreToSave)
|
|||
auto const & rStoreToSave = _kp->Keyboard->dpStoreArray[nStoreToSave];
|
||||
if (rStoreToSave.dpName == nullptr) return;
|
||||
|
||||
auto opt_ = state->options().assign(state, KM_KBP_OPT_KEYBOARD, rStoreToSave.dpName, rStoreToSave.dpString);
|
||||
state->actions().push_persist(*static_cast<option const *>(opt_));
|
||||
state.processor().persisted_store()[rStoreToSave.dpName] = rStoreToSave.dpString;
|
||||
state.actions().push_persist(
|
||||
option{KM_KBP_OPT_KEYBOARD, rStoreToSave.dpName, rStoreToSave.dpString});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@
|
|||
|
||||
namespace km {
|
||||
namespace kbp {
|
||||
|
||||
class abstract_processor;
|
||||
class state;
|
||||
|
||||
namespace kmx {
|
||||
|
||||
class KMX_Options
|
||||
|
|
@ -27,12 +31,13 @@ public:
|
|||
~KMX_Options();
|
||||
|
||||
void Init(std::vector<option> &opts);
|
||||
void Load(options *options, std::u16string const &key);
|
||||
void Load(abstract_processor &, std::u16string const &key);
|
||||
char16_t const * LookUp(std::u16string const &key) const;
|
||||
void Set(int nStoreToSet, int nStoreToRead);
|
||||
void Set(int nStoreToSet, std::u16string const &value);
|
||||
void Set(std::u16string const &key, std::u16string const &value);
|
||||
void Reset(options *options, int nStoreToReset);
|
||||
void Save(km_kbp_state *state, int nStoreToSave);
|
||||
void Reset(abstract_processor &, int nStoreToReset);
|
||||
void Save(state & state, int nStoreToSave);
|
||||
|
||||
STORE const * begin() const;
|
||||
STORE const * end() const;
|
||||
|
|
@ -41,7 +46,7 @@ public:
|
|||
inline
|
||||
void KMX_Options::Set(std::u16string const &key, std::u16string const &value) {
|
||||
auto i = _GetIndex(key);
|
||||
if (i != signed(_kp->Keyboard->cxStoreArray)) Set(i, value);
|
||||
if (i >= 0) Set(i, value);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ namespace km {
|
|||
if (_valid)
|
||||
_kmx.GetOptions()->Init(defaults);
|
||||
|
||||
for (auto const & opt: defaults)
|
||||
{
|
||||
if (!opt.empty() && opt.scope == KM_KBP_OPT_KEYBOARD )
|
||||
persisted_store()[opt.key] = opt.value;
|
||||
}
|
||||
// Fill out attributes
|
||||
auto v = _kmx.GetKeyboard()->Keyboard->version;
|
||||
auto vs = std::to_string(v >> 16) + "." + std::to_string(v & 0xffff);
|
||||
|
|
@ -27,21 +32,41 @@ namespace km {
|
|||
std::u16string(vs.begin(), vs.end()), p.parent(), defaults);
|
||||
}
|
||||
|
||||
void kmx_processor::init_state(std::vector<option> &default_env) {
|
||||
_kmx.GetEnvironment()->Init(default_env);
|
||||
|
||||
char16_t const * kmx_processor::lookup_option(km_kbp_option_scope scope, std::u16string const & key) const
|
||||
{
|
||||
char16_t const * pValue = nullptr;
|
||||
switch(scope)
|
||||
{
|
||||
case KM_KBP_OPT_KEYBOARD:
|
||||
pValue = _kmx.GetOptions()->LookUp(key);
|
||||
break;
|
||||
case KM_KBP_OPT_ENVIRONMENT:
|
||||
pValue = _kmx.GetEnvironment()->LookUp(key);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return pValue ? pValue : nullptr;
|
||||
}
|
||||
|
||||
void kmx_processor::update_option(km_kbp_state *state, km_kbp_option_scope scope, std::u16string const & key, std::u16string const & value) {
|
||||
option kmx_processor::update_option(km_kbp_option_scope scope, std::u16string const & key, std::u16string const & value)
|
||||
{
|
||||
switch(scope) {
|
||||
case KM_KBP_OPT_KEYBOARD:
|
||||
_kmx.GetOptions()->Load(&state->options(), key);
|
||||
_kmx.GetOptions()->Set(key, value);
|
||||
persisted_store()[key] = value;
|
||||
break;
|
||||
case KM_KBP_OPT_ENVIRONMENT:
|
||||
_kmx.GetEnvironment()->Load(key, value);
|
||||
break;
|
||||
default:
|
||||
return option();
|
||||
break;
|
||||
}
|
||||
|
||||
return option(scope, key, value);
|
||||
}
|
||||
|
||||
km_kbp_status kmx_processor::process_event(km_kbp_state *state, km_kbp_virtual_key vk, uint16_t modifier_state) {
|
||||
|
|
|
|||
|
|
@ -30,12 +30,11 @@ namespace kbp
|
|||
km_kbp_attr const & attributes() const override;
|
||||
km_kbp_status validate() const override;
|
||||
|
||||
void update_option(km_kbp_state *state,
|
||||
km_kbp_option_scope scope,
|
||||
char16_t const * lookup_option(km_kbp_option_scope,
|
||||
std::u16string const & key) const override;
|
||||
option update_option(km_kbp_option_scope scope,
|
||||
std::u16string const & key,
|
||||
std::u16string const & value) override;
|
||||
|
||||
void init_state(std::vector<option> &) override;
|
||||
};
|
||||
|
||||
} // namespace kbp
|
||||
|
|
|
|||
|
|
@ -403,12 +403,12 @@ int KMX_Processor::PostString(PKMX_WCHAR str, LPKEYBOARD lpkb, PKMX_WCHAR endstr
|
|||
case CODE_RESETOPT:
|
||||
p++;
|
||||
n1 = *p - 1;
|
||||
GetOptions()->Reset(&m_kbp_state->options(), n1);
|
||||
GetOptions()->Reset(m_kbp_state->processor(), n1);
|
||||
break;
|
||||
case CODE_SAVEOPT:
|
||||
p++;
|
||||
n1 = *p - 1;
|
||||
GetOptions()->Save(m_kbp_state, n1);
|
||||
GetOptions()->Save(*m_kbp_state, n1);
|
||||
break;
|
||||
case CODE_IFSYSTEMSTORE:
|
||||
p+=3;
|
||||
|
|
|
|||
|
|
@ -76,11 +76,33 @@ namespace km {
|
|||
: abstract_processor(
|
||||
keyboard_attributes(path.stem(), u"3.145", path.parent(), {
|
||||
option{KM_KBP_OPT_KEYBOARD, u"__test_point", u"not tiggered"},
|
||||
option{KM_KBP_OPT_KEYBOARD, u"hello", u"-"}
|
||||
}))
|
||||
})),
|
||||
_options({
|
||||
{u"\x01__test_point", u"not tiggered"},
|
||||
{u"\x02hello", u"-"}
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
char16_t const * mock_processor::lookup_option(km_kbp_option_scope scope,
|
||||
std::u16string const & key) const
|
||||
{
|
||||
auto i = _options.find(char16_t(scope) + key);
|
||||
return i != _options.end() ? i->second.c_str() : nullptr;
|
||||
}
|
||||
|
||||
option mock_processor::update_option(km_kbp_option_scope scope,
|
||||
std::u16string const & key,
|
||||
std::u16string const & value)
|
||||
{
|
||||
auto i = _options.find(char16_t(scope) + key);
|
||||
if (i == _options.end()) return option();
|
||||
|
||||
i->second = value;
|
||||
persisted_store()[key] = value;
|
||||
return option(scope, key, i->second);
|
||||
}
|
||||
|
||||
|
||||
km_kbp_status mock_processor::process_event(km_kbp_state *state, km_kbp_virtual_key vk, uint16_t modifier_state)
|
||||
{
|
||||
|
|
@ -102,12 +124,10 @@ namespace km {
|
|||
|
||||
case KM_KBP_VKEY_F2:
|
||||
{
|
||||
auto & opts = state->options();
|
||||
auto opt = opts.assign(state,
|
||||
KM_KBP_OPT_KEYBOARD,
|
||||
u"__test_point",
|
||||
u"F2 pressed test save.");
|
||||
state->actions().push_persist(static_cast<option const &>(*opt));
|
||||
state->actions().push_persist(
|
||||
update_option(KM_KBP_OPT_KEYBOARD,
|
||||
u"__test_point",
|
||||
u"F2 pressed test save."));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -153,17 +173,6 @@ namespace km {
|
|||
|
||||
}
|
||||
|
||||
void mock_processor::update_option(km_kbp_state *,
|
||||
km_kbp_option_scope,
|
||||
std::u16string const &,
|
||||
std::u16string const &)
|
||||
{};
|
||||
|
||||
void mock_processor::init_state(std::vector<option> &default_env) {
|
||||
default_env.emplace_back(KM_KBP_OPT_ENVIRONMENT, u"hello", u"-");
|
||||
default_env.emplace_back();
|
||||
};
|
||||
|
||||
km_kbp_attr const & mock_processor::attributes() const {
|
||||
return engine_attrs;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <keyman/keyboardprocessor.h>
|
||||
|
||||
#include "processor.hpp"
|
||||
|
|
@ -20,9 +20,8 @@ namespace kbp
|
|||
{
|
||||
class mock_processor : public abstract_processor
|
||||
{
|
||||
std::vector<option> _options;
|
||||
option const * _find_option(km_kbp_option_scope scope,
|
||||
std::u16string const & key) const;
|
||||
std::unordered_map<std::u16string, std::u16string> _options;
|
||||
|
||||
public:
|
||||
mock_processor(km::kbp::path const &);
|
||||
// ~mock_processor() override;
|
||||
|
|
@ -35,12 +34,12 @@ namespace kbp
|
|||
km_kbp_status validate() const override;
|
||||
|
||||
|
||||
void update_option(km_kbp_state *state,
|
||||
km_kbp_option_scope scope,
|
||||
std::u16string const & key,
|
||||
std::u16string const & value) override;
|
||||
|
||||
void init_state(std::vector<option> &) override;
|
||||
char16_t const * lookup_option(km_kbp_option_scope,
|
||||
std::u16string const & key) const override;
|
||||
option update_option(km_kbp_option_scope,
|
||||
std::u16string const & key,
|
||||
std::u16string const & value) override;
|
||||
};
|
||||
|
||||
class null_processor : public mock_processor {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include "option.hpp"
|
||||
#include "processor.hpp"
|
||||
#include "state.hpp"
|
||||
|
||||
|
||||
using namespace km::kbp;
|
||||
|
||||
|
|
@ -43,88 +43,30 @@ option::option(km_kbp_option_scope s, char16_t const *k, char16_t const *v)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
char16_t const * options::lookup(km_kbp_option_scope scope,
|
||||
std::u16string const & key) const noexcept
|
||||
{
|
||||
// Search first in the updated values
|
||||
for (auto & opt: _saved)
|
||||
{
|
||||
if (opt.key == key && opt.scope == scope)
|
||||
return opt.value;
|
||||
}
|
||||
|
||||
// Then in the pristine copies.
|
||||
km_kbp_option_item const * opt = _scopes[scope-1];
|
||||
while (opt->key && key != opt->key) ++opt;
|
||||
return opt->key ? opt->value : nullptr;
|
||||
}
|
||||
|
||||
|
||||
km_kbp_option_item const * options::assign(km_kbp_state *state, km_kbp_option_scope scope, std::u16string const & key,
|
||||
std::u16string const & value)
|
||||
{
|
||||
km_kbp_option_item const * opt = _scopes[scope-1];
|
||||
while (opt->key && key != opt->key) ++opt;
|
||||
if (!opt->key) return nullptr;
|
||||
|
||||
for (auto & save: _saved)
|
||||
{
|
||||
if (save.key == key && save.scope == scope)
|
||||
{
|
||||
save = option(scope, key, value);
|
||||
state->processor().update_option(state, scope, key, value);
|
||||
|
||||
return &save;
|
||||
}
|
||||
}
|
||||
|
||||
_saved.emplace_back(scope, key, value);
|
||||
|
||||
state->processor().update_option(state, scope, key, value);
|
||||
|
||||
return &_saved.back();
|
||||
}
|
||||
|
||||
void options::reset(km_kbp_option_scope scope, std::u16string const & key)
|
||||
{
|
||||
for (auto i = _saved.begin(); i == _saved.end(); ++i)
|
||||
{
|
||||
if (i->key == key && i->scope == scope)
|
||||
{
|
||||
_saved.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
json & km::kbp::operator << (json &j, options const &opts)
|
||||
// TODO: Relocate this and fix it
|
||||
json & km::kbp::operator << (json &j, abstract_processor const &)
|
||||
{
|
||||
j << json::object;
|
||||
auto n = 0;
|
||||
for (auto scope: opts._scopes)
|
||||
{
|
||||
j << scope_names_lut[n++] << json::object;
|
||||
for (auto opt = scope; opt->key; ++opt)
|
||||
{
|
||||
j << opt->key << opt->value;
|
||||
}
|
||||
j << json::close;
|
||||
}
|
||||
// auto n = 0;
|
||||
// for (auto scope: opts._scopes)
|
||||
// {
|
||||
// j << scope_names_lut[n++] << json::object;
|
||||
// for (auto opt = scope; opt->key; ++opt)
|
||||
// {
|
||||
// j << opt->key << opt->value;
|
||||
// }
|
||||
// j << json::close;
|
||||
// }
|
||||
|
||||
j << "saved" << json::object;
|
||||
for (auto scope: {KM_KBP_OPT_KEYBOARD, KM_KBP_OPT_ENVIRONMENT})
|
||||
{
|
||||
j << scope_names_lut[scope-1] << json::object;
|
||||
for (auto & opt: opts._saved)
|
||||
{
|
||||
if (opt.scope != scope) continue;
|
||||
j << opt.key << opt.value;
|
||||
}
|
||||
// for (auto & opt: opts._saved)
|
||||
// {
|
||||
// if (opt.scope != scope) continue;
|
||||
// j << opt.key << opt.value;
|
||||
// }
|
||||
j << json::close;
|
||||
}
|
||||
j << json::close;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <keyman/keyboardprocessor.h>
|
||||
|
|
@ -90,38 +89,5 @@ namespace kbp
|
|||
|
||||
|
||||
|
||||
class options
|
||||
{
|
||||
//km_kbp_keyboard_attrs const &_kb;
|
||||
km_kbp_option_item const * _scopes[KM_KBP_OPT_MAX_SCOPES-1];
|
||||
std::vector<option> _saved;
|
||||
|
||||
public:
|
||||
options(km_kbp_option_item const * kb_default_options);
|
||||
|
||||
void set_default_env(km_kbp_option_item const *env);
|
||||
|
||||
char16_t const * lookup(km_kbp_option_scope scope,
|
||||
std::u16string const & key) const noexcept;
|
||||
km_kbp_option_item const * assign(km_kbp_state *state, km_kbp_option_scope scope, std::u16string const & key,
|
||||
std::u16string const & value);
|
||||
void reset(km_kbp_option_scope scope,
|
||||
std::u16string const & key);
|
||||
|
||||
friend json & operator << (json &j, km::kbp::options const &opts);
|
||||
};
|
||||
|
||||
json & operator << (json &j, km::kbp::options const &opts);
|
||||
|
||||
inline
|
||||
options::options(km_kbp_option_item const * kb_default_options)
|
||||
: _scopes {kb_default_options, nullptr}
|
||||
{}
|
||||
|
||||
inline void options::set_default_env(km_kbp_option_item const *env) {
|
||||
_scopes[KM_KBP_OPT_ENVIRONMENT - 1] = env;
|
||||
}
|
||||
|
||||
|
||||
} // namespace kbp
|
||||
} // namespace km
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <keyman/keyboardprocessor.h>
|
||||
|
||||
|
|
@ -19,8 +20,9 @@ namespace kbp
|
|||
{
|
||||
class abstract_processor
|
||||
{
|
||||
std::unordered_map<std::u16string, std::u16string> _persisted;
|
||||
protected:
|
||||
keyboard_attributes _attributes;
|
||||
keyboard_attributes _attributes;
|
||||
|
||||
public:
|
||||
abstract_processor() {}
|
||||
|
|
@ -31,6 +33,9 @@ namespace kbp
|
|||
return _attributes;
|
||||
}
|
||||
|
||||
auto & persisted_store() const noexcept { return _persisted; }
|
||||
auto & persisted_store() noexcept { return _persisted; }
|
||||
|
||||
virtual km_kbp_status process_event(km_kbp_state *,
|
||||
km_kbp_virtual_key,
|
||||
uint16_t modifier_state) = 0;
|
||||
|
|
@ -38,14 +43,17 @@ namespace kbp
|
|||
virtual km_kbp_attr const & attributes() const = 0;
|
||||
virtual km_kbp_status validate() const = 0;
|
||||
|
||||
virtual void update_option(km_kbp_state *state,
|
||||
km_kbp_option_scope,
|
||||
virtual char16_t const * lookup_option(km_kbp_option_scope,
|
||||
std::u16string const & key) const = 0;
|
||||
virtual option update_option(km_kbp_option_scope,
|
||||
std::u16string const & key,
|
||||
std::u16string const & value) = 0;
|
||||
|
||||
virtual void init_state(std::vector<option> &default_env) = 0;
|
||||
friend json & operator << (json &j, abstract_processor const &opts);
|
||||
};
|
||||
|
||||
json & operator << (json &j, abstract_processor const &opts);
|
||||
|
||||
} // namespace kbp
|
||||
} // namespace km
|
||||
|
||||
|
|
|
|||
|
|
@ -28,14 +28,14 @@ void actions::push_persist(option const &&opt) {
|
|||
|
||||
|
||||
state::state(km::kbp::abstract_processor & ap, km_kbp_option_item const *env)
|
||||
: _options(ap.keyboard().default_options),
|
||||
_processor(ap)
|
||||
: _processor(ap)
|
||||
{
|
||||
ap.init_state(_env);
|
||||
_options.set_default_env(_env.data());
|
||||
|
||||
for (; env && env->key != nullptr; env++) {
|
||||
//assert(env->scope == KM_KBP_OPT_ENVIRONMENT); // todo do we need scope? or can we find a way to eliminate it?
|
||||
assert(_options.assign(static_cast<km_kbp_state *>(this), (km_kbp_option_scope) KM_KBP_OPT_ENVIRONMENT, env->key, env->value) != nullptr);
|
||||
ap.update_option(env->scope
|
||||
? km_kbp_option_scope(env->scope)
|
||||
: KM_KBP_OPT_ENVIRONMENT,
|
||||
env->key,
|
||||
env->value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,8 +122,6 @@ protected:
|
|||
kbp::context _ctxt;
|
||||
kbp::abstract_processor & _processor;
|
||||
kbp::actions _actions;
|
||||
kbp::options _options;
|
||||
std::vector<option> _env;
|
||||
|
||||
public:
|
||||
state(kbp::abstract_processor & kb, km_kbp_option_item const *env);
|
||||
|
|
@ -134,9 +132,6 @@ public:
|
|||
kbp::context & context() noexcept { return _ctxt; }
|
||||
kbp::context const & context() const noexcept { return _ctxt; }
|
||||
|
||||
kbp::options & options() noexcept { return _options; }
|
||||
kbp::options const & options() const noexcept { return _options; }
|
||||
|
||||
kbp::abstract_processor const & processor() const noexcept { return _processor; }
|
||||
kbp::abstract_processor & processor() noexcept { return _processor; }
|
||||
|
||||
|
|
|
|||
|
|
@ -44,23 +44,6 @@ constexpr char const *doc1_expected = u8"\
|
|||
\"version\" : \"3.145\",\n\
|
||||
\"rules\" : []\n\
|
||||
},\n\
|
||||
\"options\" : {\n\
|
||||
\"keyboard\" : {\n\
|
||||
\"__test_point\" : \"not tiggered\",\n\
|
||||
\"hello\" : \"-\"\n\
|
||||
},\n\
|
||||
\"environment\" : {\n\
|
||||
\"hello\" : \"-\"\n\
|
||||
},\n\
|
||||
\"saved\" : {\n\
|
||||
\"keyboard\" : {\n\
|
||||
\"__test_point\" : \"F2 pressed test save.\"\n\
|
||||
},\n\
|
||||
\"environment\" : {\n\
|
||||
\"hello\" : \"world\"\n\
|
||||
}\n\
|
||||
}\n\
|
||||
},\n\
|
||||
\"context\" : [\n\
|
||||
\"H\",\n\
|
||||
\"e\",\n\
|
||||
|
|
@ -87,21 +70,6 @@ constexpr char const *doc2_expected = u8"\
|
|||
\"version\" : \"3.145\",\n\
|
||||
\"rules\" : []\n\
|
||||
},\n\
|
||||
\"options\" : {\n\
|
||||
\"keyboard\" : {\n\
|
||||
\"__test_point\" : \"not tiggered\",\n\
|
||||
\"hello\" : \"-\"\n\
|
||||
},\n\
|
||||
\"environment\" : {\n\
|
||||
\"hello\" : \"-\"\n\
|
||||
},\n\
|
||||
\"saved\" : {\n\
|
||||
\"keyboard\" : {},\n\
|
||||
\"environment\" : {\n\
|
||||
\"hello\" : \"globe\"\n\
|
||||
}\n\
|
||||
}\n\
|
||||
},\n\
|
||||
\"context\" : [],\n\
|
||||
\"actions\" : []\n\
|
||||
}\n";
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
c Description: Tests basic option rules with save reset+set+reset
|
||||
c keys: [K_A][K_B][K_C][K_B][K_A]
|
||||
c expected: foo.foo.
|
||||
c context:
|
||||
c context:
|
||||
c option: foo=1
|
||||
c expected option: foo=1
|
||||
c expected option: foo=2
|
||||
|
||||
store(&version) '10.0'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
c Description: Tests basic option rules with save reset+reset
|
||||
c keys: [K_A][K_B][K_B][K_A]
|
||||
c expected: foo.foo.
|
||||
c context:
|
||||
c context:
|
||||
c option: foo=1
|
||||
c expected option: foo=1
|
||||
c expected option: foo=2
|
||||
|
||||
store(&version) '10.0'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,26 @@
|
|||
# Keyman for iPhone and iPad Version History
|
||||
|
||||
## 11.0 alpha
|
||||
* Replaced deprecated calls to UIAlertView and cleaned up extraneous blank buttons (#1002)
|
||||
* Bookmark add button is enabled only when title/url fields have text (#1073)
|
||||
* Removed deprecated code to to support keyman:// scheme for ad-hoc distribution (#1160)
|
||||
* Updated the default keyboard to SIL EuroLatin (#1288)
|
||||
* Fixed bug behind some crashes of system keyboard (#1166)
|
||||
* Added support for keypress error feedback (#257)
|
||||
* Fixed ongoing issues with keyboard rotation and sizing, including the iPhone X notch. (#444) (#1045)
|
||||
* Fixed keyboard display/overlap of "Getting Started" info panel, added keyboard hide/display API functions. (#1084)
|
||||
* Fixes issues with keyboard keycap scaling and diacritic display. (#1070)
|
||||
## 2019-01-02 11.0.300 beta
|
||||
* Initial beta release of Keyman for iPhone and iPad 11
|
||||
* [Pull Requests](https://github.com/keymanapp/keyman/pulls?utf8=%E2%9C%93&q=is%3Apr+merged%3A2018-07-01..2019-01-01+label%3Aios+-label%3Acherry-pick+-label%3Astable)
|
||||
|
||||
* New Features:
|
||||
* Added support for keypress error feedback with vibration (#1314)
|
||||
|
||||
* Changes:
|
||||
* Replaced deprecated calls to UIAlertView and cleaned up extraneous blank buttons (#1002)
|
||||
* Removed deprecated code to to support keyman:// scheme for ad-hoc distribution (#1160)
|
||||
* Updated the default keyboard to `sil_euro_latin` (#1417, #1288)
|
||||
* Added SIL logo to info page (#1164)
|
||||
|
||||
* Bug Fixes:
|
||||
* Bookmark add button is enabled only when title/url fields have text (#1073)
|
||||
* Fixed bug behind some crashes of system keyboard (#1166)
|
||||
* Fixed ongoing issues with keyboard rotation and sizing, including the iPhone X notch. (#1347, #1318, #1089, #1045)
|
||||
* Fixed keyboard display/overlap of "Getting Started" info panel, added keyboard hide/display API functions (#1084)
|
||||
* Fixed issues with keyboard keycap scaling and diacritic display (#1445, #1407, #1070)
|
||||
* Fixed issue with incorrect font on key caps in some situations (#1450)
|
||||
* Various crashes (#1057, #1301)
|
||||
|
||||
## 2018-08-02 10.0.208 stable
|
||||
* Fixed OSK layout problems (and possible crash) on iOS 11 on certain hardware (#1089, #1159)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
10.99
|
||||
11.0
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
# Keyman for Linux Version History
|
||||
|
||||
## 11.0 alpha
|
||||
## 2019-01-02 11.0.100 beta
|
||||
* Initial beta release of Keyman for Linux
|
||||
* [Pull Requests](https://github.com/keymanapp/keyman/pulls?utf8=%E2%9C%93&q=is%3Apr+merged%3A2018-07-01..2019-01-01+label%3Alinux+-label%3Acherry-pick+-label%3Astable)
|
||||
|
||||
* Keyman for Linux supports .kmp and .kmx file types from Keyman keyboard distribution repository
|
||||
|
||||
* Import KMFL into Keyman
|
||||
* kmflcomp 0.9.10
|
||||
* libkmfl 0.9.12
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#define MAXCONTEXT_ITEMS 128
|
||||
#define KEYMAN_BACKSPACE 14
|
||||
#define KEYMAN_BACKSPACE_KEYSYM 0xff08
|
||||
#define KEYMAN_LCTRL 29
|
||||
#define KEYMAN_LALT 56
|
||||
#define KEYMAN_RCTRL 97
|
||||
|
|
@ -388,8 +389,8 @@ ibus_keyman_engine_constructor (GType type,
|
|||
g_warning("problem creating km_kbp_state");
|
||||
}
|
||||
for (int i =0; i < 3; i++) {
|
||||
km_kbp_cp_dispose(keyboard_opts[i].key);
|
||||
km_kbp_cp_dispose(keyboard_opts[i].value);
|
||||
g_free((km_kbp_cp *)keyboard_opts[i].key);
|
||||
g_free((km_kbp_cp *)keyboard_opts[i].value);
|
||||
}
|
||||
g_free(keyboard_opts);
|
||||
|
||||
|
|
@ -454,10 +455,10 @@ ibus_keyman_engine_commit_string (IBusKeymanEngine *kmfl,
|
|||
g_object_unref (text);
|
||||
}
|
||||
|
||||
static void forward_keycode(IBusKeymanEngine *engine, unsigned char keycode, unsigned int state)
|
||||
static void forward_backspace(IBusKeymanEngine *engine, unsigned int state)
|
||||
{
|
||||
g_debug("DAR: forward_keycode no keysym");
|
||||
ibus_engine_forward_key_event((IBusEngine *)engine, 0, keycode, state);
|
||||
g_message("DAR: forward_backspace %d no keysym state %d", KEYMAN_BACKSPACE, state);
|
||||
ibus_engine_forward_key_event((IBusEngine *)engine, KEYMAN_BACKSPACE_KEYSYM, KEYMAN_BACKSPACE, state);
|
||||
}
|
||||
|
||||
// from android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMHardwareKeyboardInterpreter.java
|
||||
|
|
@ -783,7 +784,7 @@ ibus_keyman_engine_process_key_event (IBusEngine *engine,
|
|||
km_kbp_context_get(km_kbp_state_context(keyman->state),
|
||||
&context_items);
|
||||
reset_context(engine);
|
||||
forward_keycode(keyman, KEYMAN_BACKSPACE, 0);
|
||||
forward_backspace(keyman, 0);
|
||||
km_kbp_context_set(km_kbp_state_context(keyman->state),
|
||||
context_items);
|
||||
km_kbp_context_items_dispose(context_items);
|
||||
|
|
|
|||
|
|
@ -1,24 +1,52 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
def try_ibus():
|
||||
try:
|
||||
bus = IBus.Bus()
|
||||
if not bus.is_connected():
|
||||
print("x", end='')
|
||||
#print("Can not connect to ibus-daemon")
|
||||
else:
|
||||
print(".", end='')
|
||||
if bus.is_global_engine_enabled():
|
||||
print("+", end='')
|
||||
#print("Is global engine enabled:", bus.is_global_engine_enabled())
|
||||
#print("Is global engine used:", bus.get_use_global_engine())
|
||||
#for e in bus.list_active_engines():
|
||||
# print("Active engine:", e.get_name())
|
||||
#print("Global engine name:", bus.get_global_engine().get_name())
|
||||
#for e in bus.list_engines():
|
||||
# print(e.get_name())
|
||||
bus.destroy()
|
||||
print("-", end='')
|
||||
except Exception as e:
|
||||
print("Failed to connect to iBus")
|
||||
print(e)
|
||||
|
||||
|
||||
try:
|
||||
import gi
|
||||
gi.require_version('IBus', '1.0')
|
||||
gi.require_version('DBus', '1.0')
|
||||
from gi.repository import IBus
|
||||
from gi.repository import DBus
|
||||
|
||||
for i in range(10000):
|
||||
try_ibus()
|
||||
#import dbus #,vim
|
||||
bus = IBus.Bus()
|
||||
if not bus.is_connected():
|
||||
print("Can not connect to ibus-daemon")
|
||||
else:
|
||||
print("Is global engine enabled:", bus.is_global_engine_enabled())
|
||||
print("Is global engine used:", bus.get_use_global_engine())
|
||||
for e in bus.list_active_engines():
|
||||
print("Active engine:", e.get_name())
|
||||
print("Global engine name:", bus.get_global_engine().get_name())
|
||||
#for e in bus.list_engines():
|
||||
# print(e.get_name())
|
||||
# bus = IBus.Bus()
|
||||
# if not bus.is_connected():
|
||||
# print("Can not connect to ibus-daemon")
|
||||
# else:
|
||||
# print("Is global engine enabled:", bus.is_global_engine_enabled())
|
||||
# print("Is global engine used:", bus.get_use_global_engine())
|
||||
# for e in bus.list_active_engines():
|
||||
# print("Active engine:", e.get_name())
|
||||
# print("Global engine name:", bus.get_global_engine().get_name())
|
||||
# #for e in bus.list_engines():
|
||||
# # print(e.get_name())
|
||||
except Exception as e:
|
||||
print("Failed to connect to iBus")
|
||||
print("Failed to run test")
|
||||
print(e)
|
||||
|
||||
# dbusconn = bus.get_connection()
|
||||
|
|
|
|||
|
|
@ -10,16 +10,17 @@ import tempfile
|
|||
import zipfile
|
||||
from os import listdir, makedirs
|
||||
from shutil import copy2, rmtree
|
||||
from ast import literal_eval
|
||||
# from ast import literal_eval
|
||||
from enum import Enum
|
||||
|
||||
import requests
|
||||
|
||||
from keyman_config.get_kmp import get_keyboard_data, get_kmp, user_keyboard_dir, user_keyman_dir, user_keyman_font_dir
|
||||
from keyman_config.kmpmetadata import parseinfdata, parsemetadata, infmetadata_to_json, KMFileTypes
|
||||
from keyman_config.kmpmetadata import parseinfdata, parsemetadata, get_metadata, infmetadata_to_json, KMFileTypes
|
||||
from keyman_config.uninstall_kmp import uninstall_kmp
|
||||
from keyman_config.convertico import checkandsaveico
|
||||
from keyman_config.kvk2ldml import convert_kvk_to_ldml, output_ldml
|
||||
from keyman_config.ibus_util import install_to_ibus, restart_ibus, get_ibus_bus
|
||||
|
||||
#TODO userdir install
|
||||
# special processing for kmn if needed
|
||||
|
|
@ -51,49 +52,6 @@ def extract_kmp(kmpfile, directory):
|
|||
with zipfile.ZipFile(kmpfile,"r") as zip_ref:
|
||||
zip_ref.extractall(directory)
|
||||
|
||||
def get_metadata(tmpdirname):
|
||||
"""
|
||||
Get metadata from kmp.json if it exists.
|
||||
If it does not exist then will return get_and_convert_infdata
|
||||
|
||||
Args:
|
||||
inputfile (str): path to kmp file
|
||||
tmpdirname(str): temp directory to extract kmp
|
||||
|
||||
Returns:
|
||||
list[5]: info, system, options, keyboards, files
|
||||
see kmpmetadata.parsemetadata for details
|
||||
"""
|
||||
kmpjson = os.path.join(tmpdirname, "kmp.json")
|
||||
if os.path.isfile(kmpjson):
|
||||
return parsemetadata(kmpjson, False)
|
||||
else:
|
||||
return get_and_convert_infdata(tmpdirname)
|
||||
|
||||
def get_and_convert_infdata(tmpdirname):
|
||||
"""
|
||||
Get metadata from kmp.inf if it exists.
|
||||
Convert it to kmp.json if possible
|
||||
|
||||
Args:
|
||||
inputfile (str): path to kmp file
|
||||
tmpdirname(str): temp directory to extract kmp
|
||||
|
||||
Returns:
|
||||
list[5]: info, system, options, keyboards, files
|
||||
see kmpmetadata.parseinfdata for details
|
||||
"""
|
||||
kmpinf = os.path.join(tmpdirname, "kmp.inf")
|
||||
if os.path.isfile(kmpinf):
|
||||
info, system, options, keyboards, files = parseinfdata(kmpinf, False)
|
||||
j = infmetadata_to_json(info, system, options, keyboards, files)
|
||||
kmpjson = os.path.join(tmpdirname, "kmp.json")
|
||||
with open(kmpjson, "w") as write_file:
|
||||
print(j, file=write_file)
|
||||
return info, system, options, keyboards, files
|
||||
else:
|
||||
return None, None, None, None, None
|
||||
|
||||
def download_source(keyboardID, packageDir, sourcePath):
|
||||
# just get latest version of kmn unless there turns out to be a way to get the version of a file at a date
|
||||
base_url = "https://raw.github.com/keymanapp/keyboards/master/" + sourcePath
|
||||
|
|
@ -165,7 +123,6 @@ def install_kmp_shared(inputfile, online=False):
|
|||
inputfile (str): path to kmp file
|
||||
online(bool, default=False): whether to attempt to get a source kmn and ico for the keyboard
|
||||
"""
|
||||
do_install_to_ibus = False
|
||||
check_keyman_dir('/usr/local/share', "You do not have permissions to install the keyboard files to the shared area /usr/local/share/keyman")
|
||||
check_keyman_dir('/usr/local/share/doc', "You do not have permissions to install the documentation to the shared documentation area /usr/local/share/doc/keyman")
|
||||
check_keyman_dir('/usr/local/share/fonts', "You do not have permissions to install the font files to the shared font area /usr/local/share/fonts")
|
||||
|
|
@ -177,6 +134,9 @@ def install_kmp_shared(inputfile, online=False):
|
|||
if not os.path.isdir(packageDir):
|
||||
os.makedirs(packageDir)
|
||||
extract_kmp(inputfile, packageDir)
|
||||
#restart IBus so it knows about the keyboards being installed
|
||||
logging.debug("restarting IBus")
|
||||
restart_ibus()
|
||||
info, system, options, keyboards, files = get_metadata(packageDir)
|
||||
|
||||
if keyboards:
|
||||
|
|
@ -187,7 +147,6 @@ def install_kmp_shared(inputfile, online=False):
|
|||
for kb in keyboards:
|
||||
if kb['id'] != packageID:
|
||||
process_keyboard_data(kb['id'], packageDir)
|
||||
# do_install_to_ibus = True # temporarily disable
|
||||
|
||||
for f in files:
|
||||
fpath = os.path.join(packageDir, f['name'])
|
||||
|
|
@ -218,9 +177,10 @@ def install_kmp_shared(inputfile, online=False):
|
|||
elif ftype == KMFileTypes.KM_ICON:
|
||||
logging.info("Converting %s to PNG and installing both as keyman files", f['name'])
|
||||
checkandsaveico(fpath)
|
||||
if do_install_to_ibus:
|
||||
# install all keyboards not just packageID
|
||||
install_to_ibus(kmn_file)
|
||||
for kb in keyboards:
|
||||
# install all kmx for first lang not just packageID
|
||||
kmx_file = os.path.join(packageDir, kb['id'] + ".kmx")
|
||||
install_to_ibus(lang, kmx_file)
|
||||
else:
|
||||
logging.error("install_kmp.py: error: No kmp.json or kmp.inf found in %s", inputfile)
|
||||
logging.info("Contents of %s:", inputfile)
|
||||
|
|
@ -231,13 +191,14 @@ def install_kmp_shared(inputfile, online=False):
|
|||
raise InstallError(InstallStatus.Abort, message)
|
||||
|
||||
def install_kmp_user(inputfile, online=False):
|
||||
do_install_to_ibus = False
|
||||
packageID, ext = os.path.splitext(os.path.basename(inputfile))
|
||||
packageDir=user_keyboard_dir(packageID)
|
||||
if not os.path.isdir(packageDir):
|
||||
os.makedirs(packageDir)
|
||||
|
||||
extract_kmp(inputfile, packageDir)
|
||||
#restart IBus so it knows about the keyboards being installed
|
||||
restart_ibus()
|
||||
info, system, options, keyboards, files = get_metadata(packageDir)
|
||||
|
||||
if keyboards:
|
||||
|
|
@ -248,7 +209,6 @@ def install_kmp_user(inputfile, online=False):
|
|||
for kb in keyboards:
|
||||
if kb['id'] != packageID:
|
||||
process_keyboard_data(kb['id'], packageDir)
|
||||
# do_install_to_ibus = True # temporarily disable
|
||||
|
||||
for f in files:
|
||||
fpath = os.path.join(packageDir, f['name'])
|
||||
|
|
@ -274,10 +234,7 @@ def install_kmp_user(inputfile, online=False):
|
|||
elif ftype == KMFileTypes.KM_SOURCE:
|
||||
#TODO for the moment just leave it for ibus-kmfl to ignore if it doesn't load
|
||||
pass
|
||||
if do_install_to_ibus:
|
||||
# install all keyboards not just packageID
|
||||
kmn_file = os.path.join(packageDir, packageID + ".kmn")
|
||||
install_to_ibus(kmn_file)
|
||||
install_keyboards_to_ibus(keyboards, packageDir)
|
||||
else:
|
||||
logging.error("install_kmp.py: error: No kmp.json or kmp.inf found in %s", inputfile)
|
||||
logging.info("Contents of %s:", inputfile)
|
||||
|
|
@ -287,40 +244,22 @@ def install_kmp_user(inputfile, online=False):
|
|||
message = "install_kmp.py: error: No kmp.json or kmp.inf found in %s" % (inputfile)
|
||||
raise InstallError(InstallStatus.Abort, message)
|
||||
|
||||
|
||||
|
||||
def install_to_ibus(kmn_file):
|
||||
if sys.version_info.major == 3 and sys.version_info.minor < 6:
|
||||
dconfreadresult = subprocess.run(["dconf", "read", "/desktop/ibus/general/preload-engines"],
|
||||
stdout=subprocess.PIPE, stderr= subprocess.STDOUT)
|
||||
dconfread = dconfreadresult.stdout.decode("utf-8", "strict")
|
||||
else:
|
||||
dconfreadresult = subprocess.run(["dconf", "read", "/desktop/ibus/general/preload-engines"],
|
||||
stdout=subprocess.PIPE, stderr= subprocess.STDOUT, encoding="UTF8")
|
||||
dconfread = dconfreadresult.stdout
|
||||
if (dconfreadresult.returncode == 0) and dconfread:
|
||||
preload_engines = literal_eval(dconfread)
|
||||
preload_engines.append(kmn_file)
|
||||
logging.info("Installing %s into IBus", kmn_file)
|
||||
if sys.version_info.major == 3 and sys.version_info.minor < 6:
|
||||
dconfwriteresult = subprocess.run(["dconf", "write", "/desktop/ibus/general/preload-engines", str(preload_engines)],
|
||||
stdout=subprocess.PIPE, stderr= subprocess.STDOUT)
|
||||
def install_keyboards_to_ibus(keyboards, packageDir):
|
||||
bus = get_ibus_bus()
|
||||
if bus:
|
||||
# install all kmx for first lang not just packageID
|
||||
for kb in keyboards:
|
||||
kmx_file = os.path.join(packageDir, kb['id'] + ".kmx")
|
||||
if "languages" in kb:
|
||||
logging.debug(kb["languages"][0])
|
||||
keyboard_id = "%s:%s" % (kb["languages"][0]['id'], kmx_file)
|
||||
else:
|
||||
keyboard_id = kmx_file
|
||||
install_to_ibus(bus, keyboard_id)
|
||||
restart_ibus(bus)
|
||||
bus.destroy()
|
||||
else:
|
||||
dconfwriteresult = subprocess.run(["dconf", "write", "/desktop/ibus/general/preload-engines", str(preload_engines)],
|
||||
stdout=subprocess.PIPE, stderr= subprocess.STDOUT, encoding="UTF8")
|
||||
if (dconfwriteresult.returncode == 0):
|
||||
# restart IBus to be sure the keyboard is installed
|
||||
ibusrestartresult = subprocess.run(["ibus", "restart"])
|
||||
if (ibusrestartresult.returncode != 0):
|
||||
message = "install_kmp.py: error %d: Could not restart IBus." % (ibusrestartresult.returncode)
|
||||
raise InstallError(InstallStatus.Continue, message)
|
||||
else:
|
||||
message = "install_kmp.py: error %d: Could not install the keyboad to IBus." % (dconfwriteresult.returncode)
|
||||
raise InstallError(InstallStatus.Continue, message)
|
||||
else:
|
||||
message = "install_kmp.py: error %d: Could not read dconf preload-engines entry so cannot install to IBus" % (dconfreadresult.returncode)
|
||||
raise InstallError(InstallStatus.Continue, message)
|
||||
|
||||
logging.debug("could not install keyboards to IBus")
|
||||
|
||||
|
||||
def install_kmp(inputfile, online=False, sharedarea=False):
|
||||
|
|
|
|||
|
|
@ -459,6 +459,51 @@ def parsemetadata(jsonfile, verbose=False):
|
|||
print_files(files, extracted_dir)
|
||||
return info, system, options, keyboards, files
|
||||
|
||||
def get_metadata(tmpdirname):
|
||||
"""
|
||||
Get metadata from kmp.json if it exists.
|
||||
If it does not exist then will return get_and_convert_infdata
|
||||
|
||||
Args:
|
||||
inputfile (str): path to kmp file
|
||||
tmpdirname(str): temp directory to extract kmp
|
||||
|
||||
Returns:
|
||||
list[5]: info, system, options, keyboards, files
|
||||
see kmpmetadata.parsemetadata for details
|
||||
"""
|
||||
kmpjson = os.path.join(tmpdirname, "kmp.json")
|
||||
if os.path.isfile(kmpjson):
|
||||
return parsemetadata(kmpjson, False)
|
||||
else:
|
||||
return get_and_convert_infdata(tmpdirname)
|
||||
|
||||
def get_and_convert_infdata(tmpdirname):
|
||||
"""
|
||||
Get metadata from kmp.inf if it exists.
|
||||
Convert it to kmp.json if possible
|
||||
|
||||
Args:
|
||||
inputfile (str): path to kmp file
|
||||
tmpdirname(str): temp directory to extract kmp
|
||||
|
||||
Returns:
|
||||
list[5]: info, system, options, keyboards, files
|
||||
see kmpmetadata.parseinfdata for details
|
||||
"""
|
||||
kmpinf = os.path.join(tmpdirname, "kmp.inf")
|
||||
if os.path.isfile(kmpinf):
|
||||
info, system, options, keyboards, files = parseinfdata(kmpinf, False)
|
||||
j = infmetadata_to_json(info, system, options, keyboards, files)
|
||||
kmpjson = os.path.join(tmpdirname, "kmp.json")
|
||||
with open(kmpjson, "w") as write_file:
|
||||
print(j, file=write_file)
|
||||
return info, system, options, keyboards, files
|
||||
else:
|
||||
return None, None, None, None, None
|
||||
|
||||
|
||||
|
||||
def infmetadata_to_json(info, system, options, keyboards, files):
|
||||
jsonfiles = []
|
||||
for entry in files:
|
||||
|
|
|
|||
|
|
@ -1,53 +1,31 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import ast
|
||||
import logging
|
||||
import subprocess
|
||||
import sys
|
||||
import os.path
|
||||
from shutil import rmtree
|
||||
|
||||
from keyman_config.get_kmp import user_keyboard_dir, user_keyman_font_dir
|
||||
from keyman_config.kmpmetadata import get_metadata
|
||||
from keyman_config.ibus_util import uninstall_from_ibus, get_ibus_bus, restart_ibus
|
||||
|
||||
def uninstall_from_ibus(kmnfile):
|
||||
if sys.version_info.major == 3 and sys.version_info.minor < 6:
|
||||
result = subprocess.run(["dconf", "read", "/desktop/ibus/general/preload-engines"],
|
||||
stdout=subprocess.PIPE, stderr= subprocess.STDOUT)
|
||||
logging.debug(result.stdout.decode("utf-8", "strict"))
|
||||
dconfread = result.stdout.decode("utf-8", "strict")
|
||||
else:
|
||||
result = subprocess.run(["dconf", "read", "/desktop/ibus/general/preload-engines"],
|
||||
stdout=subprocess.PIPE, stderr= subprocess.STDOUT, encoding="UTF8")
|
||||
dconfread = result.stdout
|
||||
if (result.returncode == 0) and dconfread:
|
||||
preload_engines = ast.literal_eval(dconfread)
|
||||
if kmnfile not in preload_engines:
|
||||
logging.info("%s is not installed in IBus", kmnfile)
|
||||
return
|
||||
preload_engines.remove(kmnfile)
|
||||
logging.info("Uninstalling %s from IBus", kmnfile)
|
||||
if sys.version_info.major == 3 and sys.version_info.minor < 6:
|
||||
result2 = subprocess.run(["dconf", "write", "/desktop/ibus/general/preload-engines", str(preload_engines)],
|
||||
stdout=subprocess.PIPE, stderr= subprocess.STDOUT)
|
||||
else:
|
||||
result2 = subprocess.run(["dconf", "write", "/desktop/ibus/general/preload-engines", str(preload_engines)],
|
||||
stdout=subprocess.PIPE, stderr= subprocess.STDOUT, encoding="UTF8")
|
||||
|
||||
def uninstall_kmp_shared(keyboardid):
|
||||
def uninstall_kmp_shared(packageID):
|
||||
"""
|
||||
Uninstall a kmp from /usr/local/share/keyman
|
||||
|
||||
Args:
|
||||
keyboardid (str): Keyboard ID
|
||||
packageID (str): Keyboard package ID
|
||||
"""
|
||||
kbdir = os.path.join('/usr/local/share/keyman', keyboardid)
|
||||
kbdir = os.path.join('/usr/local/share/keyman', packageID)
|
||||
if not os.path.isdir(kbdir):
|
||||
logging.error("Keyboard directory for %s does not exist. Aborting", keyboardid)
|
||||
logging.error("Keyboard directory for %s does not exist. Aborting", packageID)
|
||||
exit(3)
|
||||
|
||||
kbdocdir = os.path.join('/usr/local/share/doc/keyman', keyboardid)
|
||||
kbfontdir = os.path.join('/usr/local/share/fonts/keyman', keyboardid)
|
||||
kbdocdir = os.path.join('/usr/local/share/doc/keyman', packageID)
|
||||
kbfontdir = os.path.join('/usr/local/share/fonts/keyman', packageID)
|
||||
|
||||
logging.info("Uninstalling shared keyboard: %s", keyboardid)
|
||||
logging.info("Uninstalling shared keyboard: %s", packageID)
|
||||
if not os.access(kbdir, os.X_OK | os.W_OK): # Check for write access of keyman dir
|
||||
logging.error("You do not have permissions to uninstall the keyboard files. You need to run this with `sudo`")
|
||||
exit(3)
|
||||
|
|
@ -67,45 +45,70 @@ def uninstall_kmp_shared(keyboardid):
|
|||
logging.info("Removed font directory: %s", kbfontdir)
|
||||
else:
|
||||
logging.info("No font directory")
|
||||
kmnfile = os.path.join(kbdir, keyboardid+".kmn")
|
||||
uninstall_from_ibus(kmnfile)
|
||||
|
||||
# need to uninstall from ibus for all lang and all kmx in kmp
|
||||
info, system, options, keyboards, files = get_metadata(kbdir)
|
||||
if keyboards:
|
||||
uninstall_keyboards_from_ibus(keyboards, kbdir)
|
||||
else:
|
||||
logging.warning("could not uninstall keyboards from IBus")
|
||||
|
||||
rmtree(kbdir)
|
||||
logging.info("Removed keyman directory: %s", kbdir)
|
||||
logging.info("Finished uninstalling shared keyboard: %s", keyboardid)
|
||||
logging.info("Finished uninstalling shared keyboard: %s", packageID)
|
||||
|
||||
def uninstall_kmp_user(keyboardid):
|
||||
def uninstall_keyboards_from_ibus(keyboards, packageDir):
|
||||
bus = get_ibus_bus()
|
||||
if bus:
|
||||
# install all kmx for first lang not just packageID
|
||||
for kb in keyboards:
|
||||
kmx_file = os.path.join(packageDir, kb['id'] + ".kmx")
|
||||
if "languages" in kb:
|
||||
logging.debug(kb["languages"][0])
|
||||
keyboard_id = "%s:%s" % (kb["languages"][0]['id'], kmx_file)
|
||||
else:
|
||||
keyboard_id = kmx_file
|
||||
uninstall_from_ibus(bus, keyboard_id)
|
||||
restart_ibus(bus)
|
||||
else:
|
||||
logging.warning("could not uninstall keyboards from IBus")
|
||||
|
||||
def uninstall_kmp_user(packageID):
|
||||
"""
|
||||
Uninstall a kmp from ~/.local/share/keyman
|
||||
|
||||
Args:
|
||||
keyboardid (str): Keyboard ID
|
||||
packageID (str): Keyboard package ID
|
||||
"""
|
||||
kbdir=user_keyboard_dir(keyboardid)
|
||||
kbdir=user_keyboard_dir(packageID)
|
||||
if not os.path.isdir(kbdir):
|
||||
logging.error("Keyboard directory for %s does not exist. Aborting", keyboardid)
|
||||
logging.error("Keyboard directory for %s does not exist. Aborting", packageID)
|
||||
exit(3)
|
||||
logging.info("Uninstalling local keyboard: %s", keyboardid)
|
||||
kmnfile = os.path.join(kbdir, keyboardid+".kmn")
|
||||
uninstall_from_ibus(kmnfile)
|
||||
logging.info("Uninstalling local keyboard: %s", packageID)
|
||||
info, system, options, keyboards, files = get_metadata(kbdir)
|
||||
if keyboards:
|
||||
uninstall_keyboards_from_ibus(keyboards, kbdir)
|
||||
else:
|
||||
logging.warning("could not uninstall keyboards from IBus")
|
||||
rmtree(kbdir)
|
||||
logging.info("Removed user keyman directory: %s", kbdir)
|
||||
fontdir=os.path.join(user_keyman_font_dir(), keyboardid)
|
||||
fontdir=os.path.join(user_keyman_font_dir(), packageID)
|
||||
if os.path.isdir(fontdir):
|
||||
rmtree(fontdir)
|
||||
logging.info("Removed user keyman font directory: %s", fontdir)
|
||||
logging.info("Finished uninstalling local keyboard: %s", keyboardid)
|
||||
logging.info("Finished uninstalling local keyboard: %s", packageID)
|
||||
|
||||
|
||||
|
||||
def uninstall_kmp(keyboardid, sharedarea=False):
|
||||
def uninstall_kmp(packageID, sharedarea=False):
|
||||
"""
|
||||
Uninstall a kmp
|
||||
|
||||
Args:
|
||||
keyboardid (str): Keyboard ID
|
||||
packageID (str): Keyboard package ID
|
||||
sharedarea (str): whether to uninstall from shared /usr/local or ~/.local
|
||||
"""
|
||||
if sharedarea:
|
||||
uninstall_kmp_shared(keyboardid)
|
||||
uninstall_kmp_shared(packageID)
|
||||
else:
|
||||
uninstall_kmp_user(keyboardid)
|
||||
uninstall_kmp_user(packageID)
|
||||
|
|
|
|||
|
|
@ -1,17 +1,25 @@
|
|||
# Keyman for macOS Version History
|
||||
|
||||
## 11.0 alpha
|
||||
* Refactored target-action call from keyView
|
||||
* Added SIL logo and copyright information to About box and DMG image (#1163)
|
||||
## 2019-01-02 11.0.200 beta
|
||||
* Initial beta release of Keyman for macOS 11
|
||||
* [Pull Requests](https://github.com/keymanapp/keyman/pulls?utf8=%E2%9C%93&q=is%3Apr+merged%3A2018-07-01..2019-01-01+label%3Amac+-label%3Acherry-pick+-label%3Astable)
|
||||
|
||||
* Changes:
|
||||
* Code refactoring and cleanup (#1050, #1053)
|
||||
* Added SIL logo and copyright information to About box and DMG image (#1163)
|
||||
|
||||
* Bug Fixes:
|
||||
* In some situations, Keyman for Mac would use the wrong rule in a keyboard (#1091, #1099)
|
||||
* Various crashes (#1424, #1066, #1080)
|
||||
|
||||
## 2018-08-14 10.0.111 stable
|
||||
* CORRECLTY fixed bug in engine that caused incorrect rules to be used (#1095, #1099)
|
||||
|
||||
## 2018-08-10 10.0.110 stable
|
||||
* No change
|
||||
## 2018-08-10 10.0.110 stable
|
||||
* No change (DO NOT USE; use 10.0.111 or later)
|
||||
|
||||
## 2018-08-10 10.0.109 stable
|
||||
* DO NOT USE - Faulty attempt at bug fix in engine (#1091)
|
||||
## 2018-08-10 10.0.109 stable
|
||||
* DO NOT USE (use 10.0.111 or later) - Faulty attempt at bug fix in engine (#1091)
|
||||
|
||||
## 2018-07-12 10.0.104 stable
|
||||
* Removed help button from OSK for versions of macOS < 10.10 to prevent crash (#1080, #1081)
|
||||
|
|
@ -96,14 +104,12 @@
|
|||
## 2018-03-22 10.0.31 beta
|
||||
* Initial beta release of Keyman 10 for macOS
|
||||
|
||||
## 10.0.29 alpha
|
||||
* Detection of context changes due to mouse clicks and command keys in "legacy" apps (#394)
|
||||
|
||||
## 10.0 alpha
|
||||
* New feature: install keyboard packages by double-clicking the kmp file (#511)
|
||||
* Added support for L/R Alt and Ctrl modifiers for keyboards (#178)
|
||||
* Display the version number in the download dialog
|
||||
* Added support for Keyman version 10.0 keyboards
|
||||
* Detection of context changes due to mouse clicks and command keys in "legacy" apps (#394)
|
||||
|
||||
## 2017-11-21 1.2.0 beta
|
||||
* Works around bug in macOS High Sierra so that Configuration dialog can be opened (#368)
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ validate_history_line() {
|
|||
fi
|
||||
elif [ $line_type = "pending-version" ]; then
|
||||
if [[ ${BASH_REMATCH[2]} = "stable" || ${BASH_REMATCH[2]} = "beta" ]]; then
|
||||
warn "Error in entry for version ${BASH_REMATCH[1]} ${BASH_REMATCH[2]} - build number missing for ${BASH_REMATCH[3]} tier."
|
||||
warn "Error in entry for version ${BASH_REMATCH[1]} ${BASH_REMATCH[2]} - build number missing for ${BASH_REMATCH[2]} tier."
|
||||
validation_error=true
|
||||
fi
|
||||
elif [ $line_type = "legacy-version" ]; then
|
||||
|
|
@ -130,11 +130,18 @@ validate_history_line() {
|
|||
elif [ $line_type = "erroneous-version" ]; then
|
||||
if [ ${BASH_REMATCH[3]} = "alpha" ]; then
|
||||
warn "Error in entry for version ${BASH_REMATCH[2]} ${BASH_REMATCH[3]} - alphas should not be dated."
|
||||
validation_error=true
|
||||
else
|
||||
warn "Error in entry for version ${BASH_REMATCH[2]} ${BASH_REMATCH[3]} - build number missing for ${BASH_REMATCH[3]} tier."
|
||||
version="${BASH_REMATCH[2]}"
|
||||
tier="${BASH_REMATCH[3]}"
|
||||
|
||||
# This branch's conditional lack of error 'grandfathers' Android versions 1.0-2.4 stable, which are dated but lack build numbers.
|
||||
[[ "${BASH_REMATCH[2]}" =~ $re_v_major ]]
|
||||
if [ "${BASH_REMATCH[1]}" -ge "10" ]; then
|
||||
warn "Error in entry for version ${version} ${tier} - build number missing for ${tier} tier."
|
||||
validation_error=true
|
||||
fi
|
||||
fi
|
||||
|
||||
validation_error=true
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ verify_on_mac() {
|
|||
}
|
||||
|
||||
# The list of valid projects that our build scripts ought expect.
|
||||
projects=("android" "ios" "mac" "web" "windows")
|
||||
projects=("android" "ios" "linux" "mac" "web" "windows")
|
||||
|
||||
# Used to validate a specified 'project' parameter.
|
||||
verify_project() {
|
||||
|
|
@ -29,7 +29,7 @@ verify_project() {
|
|||
}
|
||||
|
||||
# The list of valid platforms that our build scripts ought expect.
|
||||
platforms=("android" "ios" "mac" "web" "desktop" "developer")
|
||||
platforms=("android" "ios" "linux" "mac" "web" "desktop" "developer")
|
||||
|
||||
# Used to validate a specified 'platform' parameter.
|
||||
verify_platform() {
|
||||
|
|
|
|||
11
resources/validateAllHistory.sh
Normal file
11
resources/validateAllHistory.sh
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
FAIL=0
|
||||
./validateHistory.sh android || FAIL=$(($FAIL + 1))
|
||||
./validateHistory.sh desktop || FAIL=$(($FAIL + 2))
|
||||
./validateHistory.sh developer || FAIL=$(($FAIL + 4))
|
||||
./validateHistory.sh ios || FAIL=$(($FAIL + 8))
|
||||
./validateHistory.sh linux || FAIL=$(($FAIL + 16))
|
||||
./validateHistory.sh mac || FAIL=$(($FAIL + 32))
|
||||
./validateHistory.sh web || FAIL=$(($FAIL + 64))
|
||||
echo Final status = $FAIL
|
||||
exit $FAIL
|
||||
|
|
@ -1,13 +1,30 @@
|
|||
# KeymanWeb Version History
|
||||
|
||||
## 11.0 alpha
|
||||
* Add `setNumericLayer()` for embedded platforms to change OSK to numeric layer.
|
||||
* Fixes issue where file extensions are upper-case, e.g. ".TTF"
|
||||
* Fixes keyboard layout issues after mobile device rotations. (#248) (#970)
|
||||
* Fixes issue with oversized key text on some keyboards. (#382)
|
||||
* Fixes issue with diacritics not displaying on some keyboards. (#1070)
|
||||
* Adds support for Promises to init() and setActiveKeyboard(). (#100)
|
||||
* Adds the alignInputs() API function to facilitate touch-alias element work-arounds in case of future issues. (#69)
|
||||
## 2019-01-03 11.0.201 beta
|
||||
* New Feature:
|
||||
* Adds the alignInputs() API function to facilitate touch-alias element work-arounds in case of future issues. (#69)
|
||||
|
||||
## 2019-01-02 11.0.200 beta
|
||||
* Initial beta release of KeymanWeb 11
|
||||
* [Pull Requests](https://github.com/keymanapp/keyman/pulls?utf8=%E2%9C%93&q=is%3Apr+merged%3A2018-07-01..2019-01-01+label%3Aweb+-label%3Acherry-pick+-label%3Astable)
|
||||
|
||||
* New Features:
|
||||
* Added `setNumericLayer()` for embedded platforms to change OSK to numeric layer. (#1218)
|
||||
* Added support for Promises to `init()` and `setActiveKeyboard()`. (#1432)
|
||||
|
||||
* Changes:
|
||||
* Added OSK bulk rendering script for testing (#1432)
|
||||
* Code refactors (#1403)
|
||||
|
||||
* Bug Fixes:
|
||||
* Fixed issue where file extensions are upper-case, e.g. ".TTF" (#1333)
|
||||
* Fixed keyboard layout issues after mobile device rotations. (#1393)
|
||||
* Fixed issue with oversized key text on some keyboards. (#1421)
|
||||
* Fixed issue with diacritics not displaying on some keyboards. (#1407)
|
||||
* Fixed issue with virtual key case sensitivity (#1394)
|
||||
* Fixed multiple issues on iOS (#1393)
|
||||
* Fixed issues with language duplication in toolbar UI (#1284)
|
||||
* Fixed crashes (#1057)
|
||||
|
||||
## 2018-07-06 10.0.103 stable
|
||||
* Fixes issue for embedded Android, iOS apps where a keyboard with varying row counts in different layers could crash (#1055)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace com.keyman {
|
|||
* @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
|
||||
* This version has been substantially modified to work for this particular application.
|
||||
*/
|
||||
static getTextWidth(text: string, style: CSSStyleDeclaration) {
|
||||
static getTextWidth(text: string, style: {fontFamily?: string, fontSize: string}) {
|
||||
// A final fallback - having the right font selected makes a world of difference.
|
||||
if(!style.fontFamily) {
|
||||
style.fontFamily = getComputedStyle(document.body).fontFamily;
|
||||
|
|
@ -147,7 +147,6 @@ namespace com.keyman {
|
|||
|
||||
// Grab our default for the key's font and font size.
|
||||
let osk = (<KeymanBase> window['keyman']).osk;
|
||||
ts.fontFamily = osk.fontFamily; // Helps with style sheet calculations.
|
||||
ts.fontSize=osk.fontSize; //Build 344, KMEW-90
|
||||
|
||||
//Override font spec if set for this key in the layout
|
||||
|
|
@ -161,8 +160,18 @@ namespace com.keyman {
|
|||
|
||||
let keyboardManager = (<KeymanBase>window['keyman']).keyboardManager;
|
||||
|
||||
// For some reason, fonts will sometimes 'bug out' for the embedded iOS page if we
|
||||
// instead assign fontFamily to the existing style 'ts'. (Occurs in iOS 12.)
|
||||
let styleSpec: {fontFamily?: string, fontSize: string} = {fontSize: ts.fontSize};
|
||||
|
||||
if(ts.fontFamily) {
|
||||
styleSpec.fontFamily = ts.fontFamily;
|
||||
} else {
|
||||
styleSpec.fontFamily = osk.fontFamily; // Helps with style sheet calculations.
|
||||
}
|
||||
|
||||
// Check the key's display width - does the key visualize well?
|
||||
var width: number = OSKKey.getTextWidth(keyText, ts);
|
||||
var width: number = OSKKey.getTextWidth(keyText, styleSpec);
|
||||
if(width == 0 && keyText != '' && keyText != '\xa0') {
|
||||
// Add the Unicode 'empty circle' as a base support for needy diacritics.
|
||||
keyText = '\u25cc' + keyText;
|
||||
|
|
@ -173,7 +182,7 @@ namespace com.keyman {
|
|||
}
|
||||
|
||||
// Recompute the new width for use in autoscaling calculations below, just in case.
|
||||
width = OSKKey.getTextWidth(keyText, ts);
|
||||
width = OSKKey.getTextWidth(keyText, styleSpec);
|
||||
}
|
||||
|
||||
let fontSpec = util.getFontSizeStyle(ts.fontSize);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,27 @@
|
|||
# Keyman Desktop Version History
|
||||
|
||||
## 11.0 alpha
|
||||
* Rework keyboard input to serialize input queue to resolve modifier key stickiness (#1226, #1229, #1236)
|
||||
* Debug logging now uses Event Tracing for Windows (#1261)
|
||||
* Introduce support for Metro-style (UWP) applications such as Edge, Skype (#1265)
|
||||
* Fixed conflicts with Game Bar (#1272)
|
||||
* Added Kannada localization (#1273)
|
||||
* Added SIL logo to startup (#1194)
|
||||
* Removed hard coded version numbers, versioned paths and registry settings for simpler future upgrades (#1171, 1175)
|
||||
## 2019-01-02 11.0.1300.0 beta
|
||||
* Initial beta release of Keyman Desktop 11
|
||||
* [Pull Requests](https://github.com/keymanapp/keyman/pulls?utf8=%E2%9C%93&q=is%3Apr+merged%3A2018-07-01..2019-01-01+label%3Awindows+-label%3Acherry-pick+-label%3Astable)
|
||||
|
||||
* New Features:
|
||||
* Introduce support for Metro-style (UWP) applications such as Edge, Skype (#1265, #1377)
|
||||
* Added Kannada localization (#1273)
|
||||
|
||||
* Changes:
|
||||
* Debug logging now uses Event Tracing for Windows (#1261, #1286)
|
||||
* Added SIL logo to startup (#1194)
|
||||
* Removed hard coded version numbers, versioned paths and registry settings for simpler future upgrades (#1171, #1175)
|
||||
* Upgraded to WiX 3.11 to build installers (#1098, #1178)
|
||||
* Support for Delphi Community Edition (#1104)
|
||||
|
||||
* Bug Fixes:
|
||||
* Rework keyboard input to serialize input queue to resolve modifier key stickiness (#1226, #1229, #1236, #1439, #1300)
|
||||
* Improved On Screen Keyboard key cap font size for scripts such as Tai Dam (#1434)
|
||||
* Fixed conflicts with Game Bar (#1272)
|
||||
* Package names and metadata display always uses Unicode JSON metadata now when available (#1413)
|
||||
* Various crashes (#1410, #1409)
|
||||
* Fixed documentation links (#1068)
|
||||
|
||||
## 2018-06-28 10.0.1200 stable
|
||||
* 10.0 stable release
|
||||
|
|
|
|||
|
|
@ -1,16 +1,35 @@
|
|||
# Keyman Developer Version History
|
||||
|
||||
## 11.0 alpha
|
||||
* Refactor how keyboard_info metadata is generated (#1158)
|
||||
* New Feature: New Project from template and Import Keyboard (#1210)
|
||||
* New Feature: kmconvert command line utility (#1207)
|
||||
* New code editor using open source Monaco component (#1153, #1154, #1252)
|
||||
* Tidy up of installer to make future upgrades easier (#1175)
|
||||
* Support Linux targets (#1239)
|
||||
* Opening or creating a project now closes current editor files (#1242)
|
||||
* Projects can now include other related files such as history.md (#1243)
|
||||
* Keyman Developer now treats files as UTF-8 by default (#1244)
|
||||
* Update kmcomp to add language subtag names to keyboard_info files (#1426)
|
||||
## 2019-01-02 11.0.1300.0 beta
|
||||
* Initial beta release of Keyman Developer 11
|
||||
* [Pull Requests](https://github.com/keymanapp/keyman/pulls?utf8=%E2%9C%93&q=is%3Apr+merged%3A2018-07-01..2019-01-01+label%3Adeveloper+-label%3Acherry-pick+-label%3Astable)
|
||||
|
||||
* New Features:
|
||||
* New Project from template and Import Keyboard (#1210, #1216, #1240)
|
||||
* kmconvert command line utility (#1207)
|
||||
* New code editor using open source Monaco component (#1153, #1154, #1155, #1156, #1252, #1274)
|
||||
* Web views now use Chromium, not MSHTML (IE) (#1078, #1086, #1435, #1374, #1354, #1248)
|
||||
* Support Linux targets (#1239)
|
||||
* Added oskbulkrenderer tool for generating sample on screen keyboards (#1428)
|
||||
|
||||
* Changes:
|
||||
* Tidy up of installer to make future upgrades easier (#1175)
|
||||
* Opening or creating a project now closes current editor files (#1242)
|
||||
* Projects can now include other related files such as history.md (#1243)
|
||||
* Keyman Developer now treats files as UTF-8 by default (#1244, #1355)
|
||||
* kmcomp now adds language subtag names to keyboard_info files (#1426)
|
||||
* kmcomp now supports `-add-help-link` parameter when bulding .keyboard_info files (#1346)
|
||||
* Refactored how keyboard_info metadata is generated (#1158)
|
||||
* Improved performance of web server (#1433)
|
||||
* Current project is now shown in title bar (#1369)
|
||||
* Tweaked setup user interface and structure (#1098, #1175, #1178, #1245, #1238)
|
||||
|
||||
* Bug Fixes:
|
||||
* Support for display (avoiding crash) when loading large icons (#1416)
|
||||
* Importing .kvks into .keyman-touch-layout no longer uses incorrect layer names for some rare modifiers (#1415)
|
||||
* Various bug fixes for touch layout editor (#1414, #1405)
|
||||
* Various bug fixes and regressions for project view (#1368, #1247, #1241, #1228, #1157)
|
||||
* Fixed surrogate pair support in some debugger status views (#1246)
|
||||
|
||||
## 2018-11-28 10.0.1206 stable
|
||||
* Add parameter `-add-help-link` to kmcomp (#1346)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue